Compare commits

..

70 Commits

Author SHA1 Message Date
drh c62f1026c3 Version 3.9.2
FossilOrigin-Name: bda77dda9697c463c3d0704014d51627fceee328
2015-11-02 18:31:45 +00:00
drh 9d46f26ce5 When creating an automatic-index on a sub-query, add a unique integer to the end of each index key to ensure the entire key is unique. Fix for [8a2adec1].
FossilOrigin-Name: c0c4b6b39648be9aa9b1e218e6d281ab17812536
2015-11-02 11:19:06 +00:00
drh 511eb67522 Version 3.9.2
FossilOrigin-Name: c33a275bf1a0ea1021e723006a11bf0c3c36d59a
2015-11-02 11:10:13 +00:00
drh 332ed080d7 Increase the version number to 3.9.2.
FossilOrigin-Name: 14bd4fbf317130800db823610d440af80ae9b90b
2015-11-01 21:42:29 +00:00
drh 047800eadd If a table-constraint PRIMARY KEY lists a single column in single-quotes and
that column has type INTEGER, then make that column an integer primary key,
for historical compatibility.  Fix for ticket [ac661962a2aeab3c331].

FossilOrigin-Name: dab0e60768aa93edf44ff380198c64475fb2a67f
2015-11-01 21:35:04 +00:00
drh a649776664 Version 3.9.1
FossilOrigin-Name: 767c1727fec4ce11b83f25b3f1bfcfe68a2c8b02
2015-10-16 17:31:12 +00:00
drh 0b086403b4 Cherrypick the json form-feed fix, and other #ifdef and build script changes
to address minor issues that came to light after the 3.9.0 release.  Update
the version number to 3.9.0.  No logic changes except for the form-feed
bug-fix in json1 (ticket [57eec374ae1d0a1d4a]).

FossilOrigin-Name: 746fcd2fd412ddc27071827fb20eb6df0741dfb1
2015-10-16 15:56:27 +00:00
drh b43b711587 Version 3.9.0
FossilOrigin-Name: a721fc0d89495518fe5612e2e3bbc60befd2e90d
2015-10-14 12:29:53 +00:00
dan f4f968443b Add the missing 'extern "C" {...}' blocks to fts5.h and sqlite3rbu.h.
FossilOrigin-Name: 47a2ce97d585e1760ffcf760c0de1753677d5713
2015-10-14 10:56:34 +00:00
drh cec7dec006 Remove the unused fts5ExprColsetTest() routine.
FossilOrigin-Name: 9ecafc0c94102dca6da192f400278399464086fb
2015-10-12 22:31:02 +00:00
mistachkin f2c26ed17b Fix a couple harmless compiler warnings.
FossilOrigin-Name: 7f896a971c5953d5370215ecd834d1fb711b4263
2015-10-12 22:20:29 +00:00
dan df705d8185 Further tweaks to improve fts5 prefix query performance.
FossilOrigin-Name: 1c20c1c28b56411f106cf2f6961b3ad4b4d6f6c8
2015-10-12 19:12:29 +00:00
drh 58a8a9236e Change all references to 3.8.12 into 3.9.0. Comment changes only - no
changes to code.

FossilOrigin-Name: 6f2858f6817ca70c132f0437ac2f0f74deb273d2
2015-10-12 04:56:12 +00:00
drh bfad7be78a Detect and report circularly defined views even if the views have the
columns defined in the CREATE VIEW statement.

FossilOrigin-Name: 9ab9c8c6d747647f8ade58c2c4812fc69a813368
2015-10-11 20:39:46 +00:00
drh 2906490b71 Remove an unreachable branch in the query flattener substitution logic.
FossilOrigin-Name: 46ee3453a31b5e793d5aaad471cec1b1a11ab2cf
2015-10-11 20:08:31 +00:00
drh d12b636330 Improved substitution logic in the query flattener. Saves code space, and
(more importantly) works correctly with table-valued functions.

FossilOrigin-Name: 3d0bd95e977db50c314d33ec292f99e0539d7b4a
2015-10-11 19:46:59 +00:00
drh 48310f8c51 Work around a "security feature" bug in memcpy() on OpenBSD.
FossilOrigin-Name: fab6f09044d033dd09ed8a22e06bc6a7851bbabf
2015-10-10 16:41:28 +00:00
drh 72724da95a Remove another instance of strcpy() from FTS5, to mollify OpenBSD.
FossilOrigin-Name: 35e6248abb4435a8b26d270092b856beff867406
2015-10-10 15:57:20 +00:00
drh c5971cc859 Omit the use of strcpy() in FTS5 since OpenBSD hates strcpy().
FossilOrigin-Name: bc24a5bbfd95df3518611b221de69b73776111bc
2015-10-10 15:11:49 +00:00
drh 728e0f91bb Compiler warning fixes: Rename some local variables from "j1" to avoid a
name collision with the j1() bessel function in the math library.  Omit a
dummy initializer that gcc 4.6.3 does not like.

FossilOrigin-Name: 9ddef84d432813f3ece8012047d08441caa3315d
2015-10-10 14:41:28 +00:00
drh 9a4718ff73 Add some #ifdef-ery to json1.c to avoid a duplicate typedef when used in the
amalgamation, since some compilers become upset over duplicate typedefs.

FossilOrigin-Name: de28acd42f29693341feb884b7223cd3d2b96730
2015-10-10 14:00:37 +00:00
drh a0882fad7c The previous fix to JSON1 was not complete. A few more tweaks are needed
for correct handling of all oversized integers.

FossilOrigin-Name: 4a47f0177851721cdf6c981df962b6e8862372e7
2015-10-09 20:40:44 +00:00
drh 8deb4b8b17 Fix the JSON1 extension so that it renders integers outside the range
of -9223372036854775808 to +9223372036854775807 as floating-point numbers.

FossilOrigin-Name: ae736e35fb59c9aed33a8c805cf2ecdee528051f
2015-10-09 18:21:43 +00:00
dan 6cac258245 Remove fts5 sources from TESTSRC2 in main.mk as there is no SQLITE_TEST code in said files.
FossilOrigin-Name: c1840639b8ce8314602cd2396a324de8fac98dbe
2015-10-09 17:54:10 +00:00
dan 2572751be8 Add --enable-fts5 and --enable-json1 options to the amalgamation autoconf package.
FossilOrigin-Name: 8a4e19888f512c3ee95aa3040924fc932fbdab1a
2015-10-09 14:37:15 +00:00
mistachkin 8381be4ace In the MSVC makefile, adjust the names of two nmake variables for consistency.
FossilOrigin-Name: 92aa4b6b6fbb83f965e4c4be0aa21a8b7e330ed8
2015-10-09 14:23:56 +00:00
drh c4e6d1775e Change the version number of the next release to 3.9.0.
FossilOrigin-Name: aa8fdadf2defed00a28366a3b35a3e2eefecf0ed
2015-10-09 13:42:52 +00:00
drh b5c8d27c7d Add the JSON1 and FTS5 extensions to the amalgamation. Add new options
to ./configure: --enable-json1 and --enable-fts5.

FossilOrigin-Name: 1eb769933108cf401b25c8d784ea23f27324a0bd
2015-10-09 13:39:51 +00:00
drh 64db184efa Fix a typo in the MSVC Makefile
FossilOrigin-Name: c8a12082380991781b5ecd2f479ec65600f4f695
2015-10-09 13:29:27 +00:00
drh ce1d9f546b Add configure script options --enable-fts5 and --enable-json1. Automatically
search for -lm when using --enable-fts5.

FossilOrigin-Name: a0c44f1d46f1f31043d66f20c8dc0df53db15c30
2015-10-09 12:48:33 +00:00
dan 0008ce7cc5 Makefile and fts5 changes so that fts5 works with main.mk. Still does not work with Makefile.in.
FossilOrigin-Name: 6ebac32d8378e46f44a6eb55aaa30baf4d7dde7d
2015-10-09 11:09:47 +00:00
drh 45fac88951 Trying to get FTS5 tests to build and run using main.mk. Not yet working.
FossilOrigin-Name: 206174f9b154c590a3e2e94236db38e111d64bdb
2015-10-09 01:42:49 +00:00
drh c306e08ad5 Json1 tests are working. Builds without FTS5 enabled. Still some problems
building with FTS5.

FossilOrigin-Name: 2928f8e87d2e5d121e6e7e5993cbb773bb2b0603
2015-10-08 23:37:00 +00:00
dan d3b90a2e41 Remove calls to "load_static_extension" from fts5 test scripts.
FossilOrigin-Name: 53dd7c4c65842c5c9ed3e84edd62e24f2c9be15b
2015-10-08 21:02:29 +00:00
dan 23fda8242c Further tweaks to main.mk so that fts5 builds as part of testfixture.
FossilOrigin-Name: 97e11b79a52fb1c57f0afd2dbd6ee66cf00a922d
2015-10-08 21:00:46 +00:00
dan 56eac26897 Fix further fts5 compilation issues.
FossilOrigin-Name: 0d7f301fb03c8546a5dbce5d061a1d74e3c86bcf
2015-10-08 20:40:18 +00:00
dan 351ccb3825 Fix two more warnings in fts5 code.
FossilOrigin-Name: 5343e601fb6f0f24f4e4d5d442f7b5b074734143
2015-10-08 20:28:33 +00:00
dan 056d7acf25 Fix a couple of errors in fts5 compilation. This branch still does not build with -Wall -Werror.
FossilOrigin-Name: e9e76e12812b9b42b1142246b71cea98e26903aa
2015-10-08 20:11:42 +00:00
drh 50065656f7 First attempt to add json1 and fts5 to the amalgamation. This check-in does
not compile.

FossilOrigin-Name: d820a1bd1b8dd702d1b3a099af393530cc5a5d51
2015-10-08 19:29:18 +00:00
mistachkin b2682eb14b In the RBU extension, use MoveFile() instead of rename() on Windows CE.
FossilOrigin-Name: df9ef61f1ba2e3a3420fae84e3eaa2e0e235bc28
2015-10-08 17:35:51 +00:00
drh d7fd6aa4ba Remove two unused lines of code - discovered by scan-build.
FossilOrigin-Name: 77b707b77496a08703fe9405e8e4521a4e5b419e
2015-10-08 02:44:42 +00:00
dan 98e713bb8d Further optimizations for fts5 prefix queries without a prefix index.
FossilOrigin-Name: 83dc1ff7fa010715ca7f406a572f4ee444a967d7
2015-10-07 19:06:21 +00:00
mistachkin 08114efde4 Fix harmless compiler warning in FTS5.
FossilOrigin-Name: 13adcd038fc20dd1b6f344f79b449b4034f8f8f2
2015-10-07 17:06:17 +00:00
dan 22c7cca21f Allow the subsitute character (codepoint 26 - 0x1A) to appear in fts5 barewords.
FossilOrigin-Name: baec1b96cb64a6a6317143a8df841e502afe3914
2015-10-07 17:01:22 +00:00
drh 1dcc97cd3a Adjustments to spellfix2.test so that it works reliably on mac.
FossilOrigin-Name: d591e860d3d7c61637b4b07989bf176cb337db2c
2015-10-07 16:14:18 +00:00
dan d46cc33131 Add tests for fts5 phrase queries with column filters.
FossilOrigin-Name: f20f9f813f00cefcd427e506a09b0b973c782e3f
2015-10-07 13:24:27 +00:00
dan 92099b0753 Add further tests for fts5 prefix queries.
FossilOrigin-Name: accdc98b1291f07b802fd23f3ebc7dbc02ba09d3
2015-10-07 09:02:50 +00:00
mistachkin 6418ffab82 Fix a typo in the previous check-in.
FossilOrigin-Name: 80027709c3ba2a8c9bda4d37779f65104be1045c
2015-10-07 04:20:34 +00:00
mistachkin 6bd7456edd When running tests on Tcl 8.6 under Windows, skip tests 'uri-1.12.*' due to a change in Tcl behavior related to NTFS ADS (alternate data streams).
FossilOrigin-Name: 8a0a2aa5a6df3d7b5995457b57f051e39d6cf9e9
2015-10-07 03:07:41 +00:00
drh ee38148785 Remove three obsolete and unused files from tool/
FossilOrigin-Name: 0abd65294e6e8db68e7ce6724f02f17ba1cb3422
2015-10-07 00:35:18 +00:00
mistachkin 91a3ecb0ad Fix typo in comments. No changes to code.
FossilOrigin-Name: a05f903c64edeba8a9748aad68f5981943e68b3c
2015-10-06 21:49:55 +00:00
drh 8b0cf38a12 Simplifications to the VDBE bytecode that handles LIMIT and OFFSET.
FossilOrigin-Name: 041df7c2f14b95868a08090354ebb3308050790e
2015-10-06 21:07:06 +00:00
dan a2507137f3 Optimizations for fts5 expressions that filter on column. More still to come.
FossilOrigin-Name: bf1607ac155018573ca40fb58aca62c5fea7e60b
2015-10-06 20:53:26 +00:00
drh 9f1ef45f6a Fix the LIMIT and OFFSET handling for UNION ALL queries that contain a
subquery with ORDER BY on the right-hand side.  Fix for ticket
[b65cb2c8d91f668584].

FossilOrigin-Name: 4b631364354068af95a01630469cb6fbfe8b52fd
2015-10-06 17:27:18 +00:00
mistachkin 8d9837acd5 Adjustments to sqlite3MemoryBarrier() when compiling with MSVC and/or WinCE.
FossilOrigin-Name: 3168326ebfa1c961d8fc6435453b02be23d910cc
2015-10-06 01:44:53 +00:00
dan 6f832d3dff Improve performance of prefix queries without a prefix index on fts5 tables.
FossilOrigin-Name: f2f0184e9e1c9f121ee2ac864cd28c8cd8efecb5
2015-10-05 19:41:16 +00:00
dan f24bebe37a Update fts3 so that expressions to the left and right of a NOT operator are balanced. This prevents relatively small expressions (a dozen terms or so) that are children of NOT operators from triggering the "expression tree is too large" error.
FossilOrigin-Name: d6b66cd7b89fbd964f798d160a34caac0ba7347a
2015-10-05 15:39:45 +00:00
dan 2c1023df09 Add fts5txt2db.tcl, a tool for creating sample fts4/5 databases from text files.
FossilOrigin-Name: 44f1ce30d1e446c9ee5f8bd8a62119e00356aa0e
2015-10-05 11:57:09 +00:00
dan a0f197b842 Update fts5 to support the table function syntax. "... FROM fts5_tbl WHERE fts5_tbl MATCH ?1 AND rank MATCH ?1" can now be written "FROM fts5_tbl(?1, ?2)".
FossilOrigin-Name: 41d17d9e24303aed6d549ea23c62b93bf2f71691
2015-10-03 15:38:57 +00:00
dan 06f8c635ef Add tests for the rtree module to verify that attempts to insert non-integer primary key values or non-numeric dimensions into an rtree table are handled correctly.
FossilOrigin-Name: f653fce90846b700441e8fa5f1930c1ec5e38e31
2015-10-03 12:23:18 +00:00
dan bca189d5d8 Update fts5 to avoid using a statement journal for UPDATE and DELETE operations that affect at most a single row.
FossilOrigin-Name: 5c83b9db46d61cfa76a1abed50467e2f02db0eb0
2015-10-02 20:04:30 +00:00
dan 5171e911f2 Fix an fts3 bug causing NEAR queries on uncommitted data to malfunction.
FossilOrigin-Name: 6f90839e91024e2006042f5eb7f21ca5b47a9b4a
2015-10-01 18:31:29 +00:00
drh 105865acf9 Add a corrupt database to test/fuzzdata3.db to validate the previous
check-in.

FossilOrigin-Name: e796c0efb6cf17444b53af75046daf7d8fa82f78
2015-09-30 14:30:19 +00:00
drh 9b5351d439 Fix an assert() in btree.c that is only true for non-corrupt databases.
FossilOrigin-Name: 29f7227ff127202c53fe7c3b6558b3c101b0a7bc
2015-09-30 14:19:08 +00:00
dan e755e10a78 Clear the BTCF_ValidNKey flag when putting a cursor into REQUIRESEEK state. Fix for [1b266395].
FossilOrigin-Name: a6d5e4e8693bea3739c35fe9769ac9abfb9ed056
2015-09-30 12:59:12 +00:00
dan d95bb39c52 Improve error handling in shell command ".tables".
FossilOrigin-Name: 31a91ee7d32af8580a170903eb857ed9222fdb0a
2015-09-30 11:19:05 +00:00
drh 4b92f98ccc Use symbolic names XN_ROWID and XN_EXPR in place of the (-1) and (-2)
magic numbers in Index.aiColumn[].  Add asserts to help verify that
Index.aiColumn[] is always used correctly.  Fix one place in FK processing
where Index.aiColumn[] was not being used correctly.

FossilOrigin-Name: 7d272aa62cd4cbbf4b5d04e3b918de27671e8301
2015-09-29 17:20:14 +00:00
dan e60856980a Add the sqlite3_index_info.idxFlags field, allowing xBestIndex() implementations to specify to SQLite that a strategy may visit at most one row. Add support for this to fts3/4. Omit the statement journal from virtual table UPDATE and DELETE operations that are guaranteed not to affect more than one row.
FossilOrigin-Name: a1d08fd3d0419da8c22355d48c6d83eed6fd7e07
2015-09-29 16:47:53 +00:00
dan 65c4f591be Ensure that the xSavepoint() virtual table method is correctly invoked if there are already open savepoints (or statement transactions) the first time a virtual table is written within a transaction.
FossilOrigin-Name: 77948b5eceab92a77c39d0864ac15ad453a76fd7
2015-09-29 16:41:23 +00:00
dan 4ad0971919 Fix an off-by-one error in test function fts5_decode().
FossilOrigin-Name: 3a9f076250d9559d8ea94ba44095ba3ddbc5542d
2015-09-29 12:19:51 +00:00
83 changed files with 2837 additions and 1122 deletions
+25 -19
View File
@@ -65,7 +65,7 @@ TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@
# Any target libraries which libsqlite must be linked against
#
TLIBS = @LIBS@
TLIBS = @LIBS@ $(LIBS)
# Flags controlling use of the in memory btree implementation
#
@@ -175,7 +175,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
fts5.lo \
func.lo global.lo hash.lo \
icu.lo insert.lo journal.lo legacy.lo loadext.lo \
icu.lo insert.lo journal.lo json1.lo legacy.lo loadext.lo \
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
memjournal.lo \
mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
@@ -272,8 +272,8 @@ SRC = \
$(TOP)/src/sqliteInt.h \
$(TOP)/src/sqliteLimit.h \
$(TOP)/src/table.c \
$(TOP)/src/threads.c \
$(TOP)/src/tclsqlite.c \
$(TOP)/src/threads.c \
$(TOP)/src/tokenize.c \
$(TOP)/src/treeview.c \
$(TOP)/src/trigger.c \
@@ -347,6 +347,9 @@ SRC += \
SRC += \
$(TOP)/ext/rbu/sqlite3rbu.h \
$(TOP)/ext/rbu/sqlite3rbu.c
SRC += \
$(TOP)/ext/misc/json1.c
# Generated source code files
@@ -417,7 +420,6 @@ TESTSRC += \
$(TOP)/ext/fts5/fts5_tcl.c \
$(TOP)/ext/fts5/fts5_test_mi.c \
$(TOP)/ext/misc/ieee754.c \
$(TOP)/ext/misc/json1.c \
$(TOP)/ext/misc/nextchar.c \
$(TOP)/ext/misc/percentile.c \
$(TOP)/ext/misc/regexp.c \
@@ -541,16 +543,16 @@ FUZZDATA = \
$(TOP)/test/fuzzdata3.db \
$(TOP)/test/fuzzdata4.db
# Extra arguments for including json1 in the build of tools
#
JSON1_DEP = $(TOP)/ext/misc/json1.c sqlite3ext.h
JSON1_OPT = -DSQLITE_SHELL_JSON1 -DSQLITE_CORE
JSON1_SRC = $(TOP)/ext/misc/json1.c
# Standard options to testfixture
#
TESTOPTS = --verbose=file --output=test-out.txt
# Extra compiler options for various shell tools
#
SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
#
@@ -573,20 +575,20 @@ libtclsqlite3.la: tclsqlite.lo libsqlite3.la
-version-info "8:6:8" \
-avoid-version
sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h $(JSON1_DEP)
$(LTLINK) $(READLINE_FLAGS) $(JSON1_OPT) -o $@ \
$(TOP)/src/shell.c $(JSON1_SRC) libsqlite3.la \
sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h
$(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \
$(TOP)/src/shell.c libsqlite3.la \
$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"
sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h
$(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS)
fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h $(JSON1_DEP)
$(LTLINK) -o $@ $(JSON1_OPT) \
$(TOP)/tool/fuzzershell.c $(JSON1_SRC) sqlite3.c $(TLIBS)
fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h
$(LTLINK) -o $@ $(FUZZERSHELL_OPT) \
$(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS)
fuzzcheck$(TEXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h $(JSON1_DEP)
$(LTLINK) -o $@ $(JSON1_OPT) $(TOP)/test/fuzzcheck.c $(JSON1_SRC) sqlite3.c $(TLIBS)
fuzzcheck$(TEXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h
$(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/fuzzcheck.c sqlite3.c $(TLIBS)
mptester$(TEXE): sqlite3.c $(TOP)/mptest/mptest.c
$(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \
@@ -612,13 +614,14 @@ mptest: mptester$(TEXE)
# files are automatically generated. This target takes care of
# all that automatic generation.
#
.target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl
.target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl fts5.c
rm -rf tsrc
mkdir tsrc
cp -f $(SRC) tsrc
rm tsrc/sqlite.h.in tsrc/parse.y
$(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new
mv vdbe.new tsrc/vdbe.c
cp fts5.c fts5.h tsrc
touch .target_source
sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl
@@ -990,6 +993,9 @@ 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
json1.lo: $(TOP)/ext/misc/json1.c
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c
# FTS5 things
#
FTS5_SRC = \
+16 -13
View File
@@ -1008,7 +1008,8 @@ SRC4 = \
$(TOP)\ext\rtree\rtree.h \
$(TOP)\ext\rtree\rtree.c \
$(TOP)\ext\rbu\sqlite3rbu.h \
$(TOP)\ext\rbu\sqlite3rbu.c
$(TOP)\ext\rbu\sqlite3rbu.c \
$(TOP)\ext\misc\json1.c
# Generated source code files
@@ -1210,11 +1211,11 @@ FUZZDATA = \
$(TOP)\test\fuzzdata3.db \
$(TOP)\test\fuzzdata4.db
# Extra arguments for including json1 in the build of tools
# Extra compiler options for various shell tools
#
JSON1_DEP = sqlite3ext.h $(TOP)\ext\misc\json1.c
JSON1_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_CORE
JSON1_SRC = $(TOP)\ext\misc\json1.c
SHELL_COMPILE_OPTS = -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1
FUZZCHECK_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1
# Standard options to testfixture
#
@@ -1231,19 +1232,19 @@ libsqlite3.lib: $(LIBOBJ)
libtclsqlite3.lib: tclsqlite.lo libsqlite3.lib
$(LTLIB) $(LTLIBOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCL:tcl=tclstub) $(TLIBS)
sqlite3.exe: $(TOP)\src\shell.c $(JSON1_DEP) $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3.h
$(LTLINK) $(SHELL_COMPILE_OPTS) $(JSON1_OPT) $(READLINE_FLAGS) $(TOP)\src\shell.c $(JSON1_SRC) \
sqlite3.exe: $(TOP)\src\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3.h
$(LTLINK) $(SHELL_COMPILE_OPTS) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\shell.c \
/link /pdb:sqlite3sh.pdb $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
sqldiff.exe: $(TOP)\tool\sqldiff.c sqlite3.c sqlite3.h
$(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c sqlite3.c
fuzzershell.exe: $(TOP)\tool\fuzzershell.c sqlite3.c sqlite3.h $(JSON1_DEP)
$(LTLINK) $(NO_WARN) $(JSON1_OPT) \
$(TOP)\tool\fuzzershell.c $(JSON1_SRC) sqlite3.c
fuzzershell.exe: $(TOP)\tool\fuzzershell.c sqlite3.c sqlite3.h
$(LTLINK) $(NO_WARN) $(FUZZERSHELL_COMPILE_OPTS) \
$(TOP)\tool\fuzzershell.c sqlite3.c
fuzzcheck.exe: $(TOP)\test\fuzzcheck.c sqlite3.c sqlite3.h $(JSON1_DEP)
$(LTLINK) $(NO_WARN) $(JSON1_OPT) $(TOP)\test\fuzzcheck.c $(JSON1_SRC) sqlite3.c
fuzzcheck.exe: $(TOP)\test\fuzzcheck.c sqlite3.c sqlite3.h
$(LTLINK) $(NO_WARN) $(FUZZCHECK_COMPILE_OPTS) $(TOP)\test\fuzzcheck.c sqlite3.c
mptester.exe: $(TOP)\mptest\mptest.c $(SHELL_CORE_DEP) $(LIBRESOBJS) sqlite3.h
$(LTLINK) $(NO_WARN) $(SHELL_COMPILE_OPTS) $(TOP)\mptest\mptest.c \
@@ -1269,7 +1270,7 @@ mptest: mptester.exe
# files are automatically generated. This target takes care of
# all that automatic generation.
#
.target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl
.target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl fts5.c
-rmdir /Q/S tsrc 2>NUL
-mkdir tsrc
for %i in ($(SRC1)) do copy /Y %i tsrc
@@ -1277,6 +1278,8 @@ mptest: mptester.exe
for %i in ($(SRC3)) do copy /Y %i tsrc
for %i in ($(SRC4)) do copy /Y %i tsrc
for %i in ($(SRC5)) do copy /Y %i tsrc
copy /Y fts5.c tsrc
copy /Y fts5.h tsrc
del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL
$(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new
move vdbe.new tsrc\vdbe.c
+1 -1
View File
@@ -1 +1 @@
3.8.12
3.9.2
+1 -1
View File
@@ -1,5 +1,5 @@
AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE
AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ @FTS5_FLAGS@ @JSON1_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE
lib_LTLIBRARIES = libsqlite3.la
libsqlite3_la_SOURCES = sqlite3.c
+25
View File
@@ -78,6 +78,31 @@ AC_MSG_RESULT($enable_dynamic_extensions)
AC_SUBST(DYNAMIC_EXTENSION_FLAGS)
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# --enable-fts5
#
AC_ARG_ENABLE(fts5, [AS_HELP_STRING(
[--enable-fts5], [include fts5 support [default=no]])],
[], [enable_fts5=no])
if test x"$enable_fts5" == "xyes"; then
AC_SEARCH_LIBS(log, m)
FTS5_FLAGS=-DSQLITE_ENABLE_FTS5
fi
AC_SUBST(FTS5_FLAGS)
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# --enable-json1
#
AC_ARG_ENABLE(json1, [AS_HELP_STRING(
[--enable-json1], [include json1 support [default=no]])],
[], [enable_json1=no])
if test x"$enable_json1" == "xyes"; then
JSON1_FLAGS=-DSQLITE_ENABLE_JSON1
fi
AC_SUBST(JSON1_FLAGS)
#-----------------------------------------------------------------------
AC_CHECK_FUNCS(posix_fallocate)
#-----------------------------------------------------------------------
Vendored
+204 -23
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for sqlite 3.8.12.
# Generated by GNU Autoconf 2.69 for sqlite 3.9.2.
#
#
# 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.8.12'
PACKAGE_STRING='sqlite 3.8.12'
PACKAGE_VERSION='3.9.2'
PACKAGE_STRING='sqlite 3.9.2'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -902,6 +902,11 @@ with_readline_inc
enable_debug
enable_amalgamation
enable_load_extension
enable_fts3
enable_fts4
enable_fts5
enable_json1
enable_rtree
enable_gcov
'
ac_precious_vars='build_alias
@@ -1454,7 +1459,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.8.12 to adapt to many kinds of systems.
\`configure' configures sqlite 3.9.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1519,7 +1524,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.8.12:";;
short | recursive ) echo "Configuration of sqlite 3.9.2:";;
esac
cat <<\_ACEOF
@@ -1544,6 +1549,11 @@ Optional Features:
separately
--disable-load-extension
Disable loading of external extensions
--enable-fts3 Enable the FTS3 extension
--enable-fts4 Enable the FTS4 extension
--enable-fts5 Enable the FTS5 extension
--enable-json1 Enable the JSON1 extension
--enable-rtree Enable the RTREE extension
--enable-gcov Enable coverage testing using gcov
Optional Packages:
@@ -1634,7 +1644,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.8.12
sqlite configure 3.9.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2053,7 +2063,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.8.12, which was
It was created by sqlite $as_me 3.9.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3911,13 +3921,13 @@ if ${lt_cv_nm_interface+:} false; then :
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:3914: $ac_compile\"" >&5)
(eval echo "\"\$as_me:3924: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
(eval echo "\"\$as_me:3917: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval echo "\"\$as_me:3927: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
(eval echo "\"\$as_me:3920: output\"" >&5)
(eval echo "\"\$as_me:3930: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -5123,7 +5133,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 5126 "configure"' > conftest.$ac_ext
echo '#line 5136 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -6648,11 +6658,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:6651: $lt_compile\"" >&5)
(eval echo "\"\$as_me:6661: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:6655: \$? = $ac_status" >&5
echo "$as_me:6665: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -6987,11 +6997,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:6990: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7000: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:6994: \$? = $ac_status" >&5
echo "$as_me:7004: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7092,11 +7102,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7095: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7105: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7099: \$? = $ac_status" >&5
echo "$as_me:7109: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -7147,11 +7157,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7150: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7160: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7154: \$? = $ac_status" >&5
echo "$as_me:7164: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -9527,7 +9537,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 9530 "configure"
#line 9540 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -9623,7 +9633,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 9626 "configure"
#line 9636 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11223,6 +11233,177 @@ else
OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
fi
#########
# See whether we should enable Full Text Search extensions
# Check whether --enable-fts3 was given.
if test "${enable_fts3+set}" = set; then :
enableval=$enable_fts3; enable_fts3=yes
else
enable_fts3=no
fi
if test "${enable_fts3}" = "yes" ; then
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3"
fi
# Check whether --enable-fts4 was given.
if test "${enable_fts4+set}" = set; then :
enableval=$enable_fts4; enable_fts4=yes
else
enable_fts4=no
fi
if test "${enable_fts4}" = "yes" ; then
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
$as_echo_n "checking for library containing log... " >&6; }
if ${ac_cv_search_log+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char log ();
int
main ()
{
return log ();
;
return 0;
}
_ACEOF
for ac_lib in '' m; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_log=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_log+:} false; then :
break
fi
done
if ${ac_cv_search_log+:} false; then :
else
ac_cv_search_log=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_log" >&5
$as_echo "$ac_cv_search_log" >&6; }
ac_res=$ac_cv_search_log
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
fi
# Check whether --enable-fts5 was given.
if test "${enable_fts5+set}" = set; then :
enableval=$enable_fts5; enable_fts5=yes
else
enable_fts5=no
fi
if test "${enable_fts5}" = "yes" ; then
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
$as_echo_n "checking for library containing log... " >&6; }
if ${ac_cv_search_log+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char log ();
int
main ()
{
return log ();
;
return 0;
}
_ACEOF
for ac_lib in '' m; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_log=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_log+:} false; then :
break
fi
done
if ${ac_cv_search_log+:} false; then :
else
ac_cv_search_log=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_log" >&5
$as_echo "$ac_cv_search_log" >&6; }
ac_res=$ac_cv_search_log
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
fi
#########
# See whether we should enable JSON1
# Check whether --enable-json1 was given.
if test "${enable_json1+set}" = set; then :
enableval=$enable_json1; enable_json1=yes
else
enable_json1=no
fi
if test "${enable_json1}" = "yes" ; then
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1"
fi
#########
# See whether we should enable RTREE
# Check whether --enable-rtree was given.
if test "${enable_rtree+set}" = set; then :
enableval=$enable_rtree; enable_rtree=yes
else
enable_rtree=no
fi
if test "${enable_rtree}" = "yes" ; then
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE"
fi
#########
# attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter
for option in $CFLAGS $CPPFLAGS
@@ -11808,7 +11989,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.8.12, which was
This file was extended by sqlite $as_me 3.9.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -11874,7 +12055,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.8.12
sqlite config.status 3.9.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
+41
View File
@@ -560,6 +560,47 @@ else
OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
fi
#########
# See whether we should enable Full Text Search extensions
AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3],
[Enable the FTS3 extension]),
[enable_fts3=yes],[enable_fts3=no])
if test "${enable_fts3}" = "yes" ; then
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3"
fi
AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4],
[Enable the FTS4 extension]),
[enable_fts4=yes],[enable_fts4=no])
if test "${enable_fts4}" = "yes" ; then
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4"
AC_SEARCH_LIBS([log],[m])
fi
AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5],
[Enable the FTS5 extension]),
[enable_fts5=yes],[enable_fts5=no])
if test "${enable_fts5}" = "yes" ; then
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5"
AC_SEARCH_LIBS([log],[m])
fi
#########
# See whether we should enable JSON1
AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1],
[Enable the JSON1 extension]),
[enable_json1=yes],[enable_json1=no])
if test "${enable_json1}" = "yes" ; then
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1"
fi
#########
# See whether we should enable RTREE
AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree],
[Enable the RTREE extension]),
[enable_rtree=yes],[enable_rtree=no])
if test "${enable_rtree}" = "yes" ; then
OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE"
fi
#########
# attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter
for option in $CFLAGS $CPPFLAGS
+126 -100
View File
@@ -793,125 +793,151 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
rc = SQLITE_ERROR;
}
if( rc==SQLITE_OK && (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
Fts3Expr **apLeaf;
apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
if( 0==apLeaf ){
rc = SQLITE_NOMEM;
}else{
memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth);
}
if( rc==SQLITE_OK ){
int i;
Fts3Expr *p;
/* Set $p to point to the left-most leaf in the tree of eType nodes. */
for(p=pRoot; p->eType==eType; p=p->pLeft){
assert( p->pParent==0 || p->pParent->pLeft==p );
assert( p->pLeft && p->pRight );
}
/* This loop runs once for each leaf in the tree of eType nodes. */
while( 1 ){
int iLvl;
Fts3Expr *pParent = p->pParent; /* Current parent of p */
assert( pParent==0 || pParent->pLeft==p );
p->pParent = 0;
if( pParent ){
pParent->pLeft = 0;
}else{
pRoot = 0;
}
rc = fts3ExprBalance(&p, nMaxDepth-1);
if( rc!=SQLITE_OK ) break;
for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){
if( apLeaf[iLvl]==0 ){
apLeaf[iLvl] = p;
p = 0;
}else{
assert( pFree );
pFree->pLeft = apLeaf[iLvl];
pFree->pRight = p;
pFree->pLeft->pParent = pFree;
pFree->pRight->pParent = pFree;
p = pFree;
pFree = pFree->pParent;
p->pParent = 0;
apLeaf[iLvl] = 0;
}
}
if( p ){
sqlite3Fts3ExprFree(p);
rc = SQLITE_TOOBIG;
break;
}
/* If that was the last leaf node, break out of the loop */
if( pParent==0 ) break;
/* Set $p to point to the next leaf in the tree of eType nodes */
for(p=pParent->pRight; p->eType==eType; p=p->pLeft);
/* Remove pParent from the original tree. */
assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent );
pParent->pRight->pParent = pParent->pParent;
if( pParent->pParent ){
pParent->pParent->pLeft = pParent->pRight;
}else{
assert( pParent==pRoot );
pRoot = pParent->pRight;
}
/* Link pParent into the free node list. It will be used as an
** internal node of the new tree. */
pParent->pParent = pFree;
pFree = pParent;
if( rc==SQLITE_OK ){
if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
Fts3Expr **apLeaf;
apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
if( 0==apLeaf ){
rc = SQLITE_NOMEM;
}else{
memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth);
}
if( rc==SQLITE_OK ){
p = 0;
for(i=0; i<nMaxDepth; i++){
if( apLeaf[i] ){
if( p==0 ){
p = apLeaf[i];
p->pParent = 0;
int i;
Fts3Expr *p;
/* Set $p to point to the left-most leaf in the tree of eType nodes. */
for(p=pRoot; p->eType==eType; p=p->pLeft){
assert( p->pParent==0 || p->pParent->pLeft==p );
assert( p->pLeft && p->pRight );
}
/* This loop runs once for each leaf in the tree of eType nodes. */
while( 1 ){
int iLvl;
Fts3Expr *pParent = p->pParent; /* Current parent of p */
assert( pParent==0 || pParent->pLeft==p );
p->pParent = 0;
if( pParent ){
pParent->pLeft = 0;
}else{
pRoot = 0;
}
rc = fts3ExprBalance(&p, nMaxDepth-1);
if( rc!=SQLITE_OK ) break;
for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){
if( apLeaf[iLvl]==0 ){
apLeaf[iLvl] = p;
p = 0;
}else{
assert( pFree!=0 );
assert( pFree );
pFree->pLeft = apLeaf[iLvl];
pFree->pRight = p;
pFree->pLeft = apLeaf[i];
pFree->pLeft->pParent = pFree;
pFree->pRight->pParent = pFree;
p = pFree;
pFree = pFree->pParent;
p->pParent = 0;
apLeaf[iLvl] = 0;
}
}
if( p ){
sqlite3Fts3ExprFree(p);
rc = SQLITE_TOOBIG;
break;
}
/* If that was the last leaf node, break out of the loop */
if( pParent==0 ) break;
/* Set $p to point to the next leaf in the tree of eType nodes */
for(p=pParent->pRight; p->eType==eType; p=p->pLeft);
/* Remove pParent from the original tree. */
assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent );
pParent->pRight->pParent = pParent->pParent;
if( pParent->pParent ){
pParent->pParent->pLeft = pParent->pRight;
}else{
assert( pParent==pRoot );
pRoot = pParent->pRight;
}
/* Link pParent into the free node list. It will be used as an
** internal node of the new tree. */
pParent->pParent = pFree;
pFree = pParent;
}
pRoot = p;
}else{
/* An error occurred. Delete the contents of the apLeaf[] array
** and pFree list. Everything else is cleaned up by the call to
** sqlite3Fts3ExprFree(pRoot) below. */
Fts3Expr *pDel;
for(i=0; i<nMaxDepth; i++){
sqlite3Fts3ExprFree(apLeaf[i]);
}
while( (pDel=pFree)!=0 ){
pFree = pDel->pParent;
sqlite3_free(pDel);
if( rc==SQLITE_OK ){
p = 0;
for(i=0; i<nMaxDepth; i++){
if( apLeaf[i] ){
if( p==0 ){
p = apLeaf[i];
p->pParent = 0;
}else{
assert( pFree!=0 );
pFree->pRight = p;
pFree->pLeft = apLeaf[i];
pFree->pLeft->pParent = pFree;
pFree->pRight->pParent = pFree;
p = pFree;
pFree = pFree->pParent;
p->pParent = 0;
}
}
}
pRoot = p;
}else{
/* An error occurred. Delete the contents of the apLeaf[] array
** and pFree list. Everything else is cleaned up by the call to
** sqlite3Fts3ExprFree(pRoot) below. */
Fts3Expr *pDel;
for(i=0; i<nMaxDepth; i++){
sqlite3Fts3ExprFree(apLeaf[i]);
}
while( (pDel=pFree)!=0 ){
pFree = pDel->pParent;
sqlite3_free(pDel);
}
}
assert( pFree==0 );
sqlite3_free( apLeaf );
}
}else if( eType==FTSQUERY_NOT ){
Fts3Expr *pLeft = pRoot->pLeft;
Fts3Expr *pRight = pRoot->pRight;
pRoot->pLeft = 0;
pRoot->pRight = 0;
pLeft->pParent = 0;
pRight->pParent = 0;
rc = fts3ExprBalance(&pLeft, nMaxDepth-1);
if( rc==SQLITE_OK ){
rc = fts3ExprBalance(&pRight, nMaxDepth-1);
}
assert( pFree==0 );
sqlite3_free( apLeaf );
if( rc!=SQLITE_OK ){
sqlite3Fts3ExprFree(pRight);
sqlite3Fts3ExprFree(pLeft);
}else{
assert( pLeft && pRight );
pRoot->pLeft = pLeft;
pLeft->pParent = pRoot;
pRoot->pRight = pRight;
pRight->pParent = pRoot;
}
}
}
if( rc!=SQLITE_OK ){
sqlite3Fts3ExprFree(pRoot);
pRoot = 0;
+15 -8
View File
@@ -1322,14 +1322,19 @@ static int fts3SegReaderNext(
if( fts3SegReaderIsPending(pReader) ){
Fts3HashElem *pElem = *(pReader->ppNextElem);
if( pElem==0 ){
pReader->aNode = 0;
}else{
sqlite3_free(pReader->aNode);
pReader->aNode = 0;
if( pElem ){
char *aCopy;
PendingList *pList = (PendingList *)fts3HashData(pElem);
int nCopy = pList->nData+1;
pReader->zTerm = (char *)fts3HashKey(pElem);
pReader->nTerm = fts3HashKeysize(pElem);
pReader->nNode = pReader->nDoclist = pList->nData + 1;
pReader->aNode = pReader->aDoclist = pList->aData;
aCopy = (char*)sqlite3_malloc(nCopy);
if( !aCopy ) return SQLITE_NOMEM;
memcpy(aCopy, pList->aData, nCopy);
pReader->nNode = pReader->nDoclist = nCopy;
pReader->aNode = pReader->aDoclist = aCopy;
pReader->ppNextElem++;
assert( pReader->aNode );
}
@@ -1569,12 +1574,14 @@ int sqlite3Fts3MsrOvfl(
** second argument.
*/
void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
if( pReader && !fts3SegReaderIsPending(pReader) ){
sqlite3_free(pReader->zTerm);
if( pReader ){
if( !fts3SegReaderIsPending(pReader) ){
sqlite3_free(pReader->zTerm);
}
if( !fts3SegReaderIsRootOnly(pReader) ){
sqlite3_free(pReader->aNode);
sqlite3_blob_close(pReader->pBlob);
}
sqlite3_blob_close(pReader->pBlob);
}
sqlite3_free(pReader);
}
+8
View File
@@ -23,6 +23,10 @@
#include "sqlite3.h"
#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************************
** CUSTOM AUXILIARY FUNCTIONS
**
@@ -508,5 +512,9 @@ struct fts5_api {
** END OF REGISTRATION API
*************************************************************************/
#ifdef __cplusplus
} /* end of the 'extern "C"' block */
#endif
#endif /* _FTS5_H */
+33 -10
View File
@@ -81,6 +81,20 @@ extern int sqlite3_fts5_may_be_corrupt;
#endif
typedef struct Fts5Global Fts5Global;
typedef struct Fts5Colset Fts5Colset;
/* If a NEAR() clump or phrase may only match a specific set of columns,
** then an object of the following type is used to record the set of columns.
** Each entry in the aiCol[] array is a column that may be matched.
**
** This object is used by fts5_expr.c and fts5_index.c.
*/
struct Fts5Colset {
int nCol;
int aiCol[1];
};
/**************************************************************************
** Interface to code in fts5_config.c. fts5_config.c contains contains code
@@ -240,7 +254,6 @@ int sqlite3Fts5Get32(const u8*);
typedef struct Fts5PoslistReader Fts5PoslistReader;
struct Fts5PoslistReader {
/* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */
int iCol; /* If (iCol>=0), this column only */
const u8 *a; /* Position list to iterate through */
int n; /* Size of buffer at a[] in bytes */
int i; /* Current offset in a[] */
@@ -252,7 +265,6 @@ struct Fts5PoslistReader {
i64 iPos; /* (iCol<<32) + iPos */
};
int sqlite3Fts5PoslistReaderInit(
int iCol, /* If (iCol>=0), this column only */
const u8 *a, int n, /* Poslist buffer to iterate through */
Fts5PoslistReader *pIter /* Iterator object to initialize */
);
@@ -305,7 +317,7 @@ int sqlite3Fts5IndexClose(Fts5Index *p);
/*
** for(
** pIter = sqlite3Fts5IndexQuery(p, "token", 5, 0);
** sqlite3Fts5IndexQuery(p, "token", 5, 0, 0, &pIter);
** 0==sqlite3Fts5IterEof(pIter);
** sqlite3Fts5IterNext(pIter)
** ){
@@ -321,7 +333,8 @@ int sqlite3Fts5IndexQuery(
Fts5Index *p, /* FTS index to query */
const char *pToken, int nToken, /* Token (or prefix) to query for */
int flags, /* Mask of FTS5INDEX_QUERY_X flags */
Fts5IndexIter **ppIter
Fts5Colset *pColset, /* Match these columns only */
Fts5IndexIter **ppIter /* OUT: New iterator object */
);
/*
@@ -332,7 +345,7 @@ int sqlite3Fts5IterEof(Fts5IndexIter*);
int sqlite3Fts5IterNext(Fts5IndexIter*);
int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
i64 sqlite3Fts5IterRowid(Fts5IndexIter*);
int sqlite3Fts5IterPoslist(Fts5IndexIter*, const u8 **pp, int *pn, i64 *pi);
int sqlite3Fts5IterPoslist(Fts5IndexIter*,Fts5Colset*, const u8**, int*, i64*);
int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf);
/*
@@ -370,6 +383,7 @@ int sqlite3Fts5IndexWrite(
*/
int sqlite3Fts5IndexBeginWrite(
Fts5Index *p, /* Index to write to */
int bDelete, /* True if current operation is a delete */
i64 iDocid /* Docid to add or remove data from */
);
@@ -434,6 +448,15 @@ int sqlite3Fts5PutVarint(unsigned char *p, u64 v);
#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b)
#define fts5GetVarint sqlite3Fts5GetVarint
#define fts5FastGetVarint32(a, iOff, nVal) { \
nVal = (a)[iOff++]; \
if( nVal & 0x80 ){ \
iOff--; \
iOff += fts5GetVarint32(&(a)[iOff], nVal); \
} \
}
/*
** End of interface to code in fts5_varint.c.
**************************************************************************/
@@ -526,7 +549,8 @@ int sqlite3Fts5DropAll(Fts5Config*);
int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
int sqlite3Fts5StorageDelete(Fts5Storage *p, i64);
int sqlite3Fts5StorageInsert(Fts5Storage *p, sqlite3_value **apVal, int, i64*);
int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
int sqlite3Fts5StorageIntegrity(Fts5Storage *p);
@@ -565,7 +589,6 @@ typedef struct Fts5Parse Fts5Parse;
typedef struct Fts5Token Fts5Token;
typedef struct Fts5ExprPhrase Fts5ExprPhrase;
typedef struct Fts5ExprNearset Fts5ExprNearset;
typedef struct Fts5ExprColset Fts5ExprColset;
struct Fts5Token {
const char *p; /* Token text (not NULL terminated) */
@@ -633,9 +656,9 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
Fts5ExprPhrase*
);
Fts5ExprColset *sqlite3Fts5ParseColset(
Fts5Colset *sqlite3Fts5ParseColset(
Fts5Parse*,
Fts5ExprColset*,
Fts5Colset*,
Fts5Token *
);
@@ -644,7 +667,7 @@ void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*);
void sqlite3Fts5ParseNodeFree(Fts5ExprNode*);
void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*);
void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5ExprColset*);
void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*);
void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p);
void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
+1 -1
View File
@@ -13,7 +13,7 @@
#include "fts5Int.h"
#include <math.h>
#include <math.h> /* amalgamator: keep */
/*
** Object used to iterate through all "coalesced phrase instances" in
+15 -18
View File
@@ -185,11 +185,11 @@ int sqlite3Fts5PoslistNext64(
}else{
i64 iOff = *piOff;
int iVal;
i += fts5GetVarint32(&a[i], iVal);
fts5FastGetVarint32(a, i, iVal);
if( iVal==1 ){
i += fts5GetVarint32(&a[i], iVal);
fts5FastGetVarint32(a, i, iVal);
iOff = ((i64)iVal) << 32;
i += fts5GetVarint32(&a[i], iVal);
fts5FastGetVarint32(a, i, iVal);
}
*piOff = iOff + (iVal-2);
*pi = i;
@@ -203,26 +203,20 @@ int sqlite3Fts5PoslistNext64(
** if the iterator reaches EOF, or false otherwise.
*/
int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader *pIter){
if( sqlite3Fts5PoslistNext64(pIter->a, pIter->n, &pIter->i, &pIter->iPos)
|| (pIter->iCol>=0 && (pIter->iPos >> 32) > pIter->iCol)
){
if( sqlite3Fts5PoslistNext64(pIter->a, pIter->n, &pIter->i, &pIter->iPos) ){
pIter->bEof = 1;
}
return pIter->bEof;
}
int sqlite3Fts5PoslistReaderInit(
int iCol, /* If (iCol>=0), this column only */
const u8 *a, int n, /* Poslist buffer to iterate through */
Fts5PoslistReader *pIter /* Iterator object to initialize */
){
memset(pIter, 0, sizeof(*pIter));
pIter->a = a;
pIter->n = n;
pIter->iCol = iCol;
do {
sqlite3Fts5PoslistReaderNext(pIter);
}while( pIter->bEof==0 && (pIter->iPos >> 32)<iCol );
sqlite3Fts5PoslistReaderNext(pIter);
return pIter->bEof;
}
@@ -233,13 +227,15 @@ int sqlite3Fts5PoslistWriterAppend(
){
static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
int rc = SQLITE_OK;
if( (iPos & colmask) != (pWriter->iPrev & colmask) ){
fts5BufferAppendVarint(&rc, pBuf, 1);
fts5BufferAppendVarint(&rc, pBuf, (iPos >> 32));
pWriter->iPrev = (iPos & colmask);
if( 0==sqlite3Fts5BufferGrow(&rc, pBuf, 5+5+5) ){
if( (iPos & colmask) != (pWriter->iPrev & colmask) ){
pBuf->p[pBuf->n++] = 1;
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
pWriter->iPrev = (iPos & colmask);
}
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-pWriter->iPrev)+2);
pWriter->iPrev = iPos;
}
fts5BufferAppendVarint(&rc, pBuf, (iPos - pWriter->iPrev) + 2);
pWriter->iPrev = iPos;
return rc;
}
@@ -290,11 +286,12 @@ char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
** * The 52 upper and lower case ASCII characters, and
** * The 10 integer ASCII characters.
** * The underscore character "_" (0x5F).
** * The unicode "subsitute" character (0x1A).
*/
int sqlite3Fts5IsBareword(char t){
u8 aBareword[128] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 .. 0x0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 .. 0x1F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* 0x10 .. 0x1F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 .. 0x2F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30 .. 0x3F */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 .. 0x4F */
+37 -124
View File
@@ -32,6 +32,11 @@ typedef struct Fts5ExprTerm Fts5ExprTerm;
void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(u64));
void sqlite3Fts5ParserFree(void*, void (*freeProc)(void*));
void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*);
#ifndef NDEBUG
#include <stdio.h>
void sqlite3Fts5ParserTrace(FILE*, char*);
#endif
struct Fts5Expr {
Fts5Index *pIndex;
@@ -89,23 +94,13 @@ struct Fts5ExprPhrase {
Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */
};
/*
** If a NEAR() clump may only match a specific set of columns, then
** Fts5ExprNearset.pColset points to an object of the following type.
** Each entry in the aiCol[] array
*/
struct Fts5ExprColset {
int nCol;
int aiCol[1];
};
/*
** One or more phrases that must appear within a certain token distance of
** each other within each matching document.
*/
struct Fts5ExprNearset {
int nNear; /* NEAR parameter */
Fts5ExprColset *pColset; /* Columns to search (NULL -> all columns) */
Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */
int nPhrase; /* Number of entries in aPhrase[] array */
Fts5ExprPhrase *apPhrase[1]; /* Array of phrase pointers */
};
@@ -276,14 +271,6 @@ void sqlite3Fts5ExprFree(Fts5Expr *p){
}
}
static int fts5ExprColsetTest(Fts5ExprColset *pColset, int iCol){
int i;
for(i=0; i<pColset->nCol; i++){
if( pColset->aiCol[i]==iCol ) return 1;
}
return 0;
}
/*
** Argument pTerm must be a synonym iterator. Return the current rowid
** that it points to.
@@ -314,6 +301,7 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
*/
static int fts5ExprSynonymPoslist(
Fts5ExprTerm *pTerm,
Fts5Colset *pColset,
i64 iRowid,
int *pbDel, /* OUT: Caller should sqlite3_free(*pa) */
u8 **pa, int *pn
@@ -332,7 +320,7 @@ static int fts5ExprSynonymPoslist(
const u8 *a;
int n;
i64 dummy;
rc = sqlite3Fts5IterPoslist(pIter, &a, &n, &dummy);
rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy);
if( rc!=SQLITE_OK ) goto synonym_poslist_out;
if( nIter==nAlloc ){
int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
@@ -346,7 +334,7 @@ static int fts5ExprSynonymPoslist(
if( aIter!=aStatic ) sqlite3_free(aIter);
aIter = aNew;
}
sqlite3Fts5PoslistReaderInit(-1, a, n, &aIter[nIter]);
sqlite3Fts5PoslistReaderInit(a, n, &aIter[nIter]);
assert( aIter[nIter].bEof==0 );
nIter++;
}
@@ -405,7 +393,7 @@ static int fts5ExprSynonymPoslist(
*/
static int fts5ExprPhraseIsMatch(
Fts5ExprNode *pNode, /* Node pPhrase belongs to */
Fts5ExprColset *pColset, /* Restrict matches to these columns */
Fts5Colset *pColset, /* Restrict matches to these columns */
Fts5ExprPhrase *pPhrase, /* Phrase object to initialize */
int *pbMatch /* OUT: Set to true if really a match */
){
@@ -414,13 +402,7 @@ static int fts5ExprPhraseIsMatch(
Fts5PoslistReader *aIter = aStatic;
int i;
int rc = SQLITE_OK;
int iCol = -1;
if( pColset && pColset->nCol==1 ){
iCol = pColset->aiCol[0];
pColset = 0;
}
fts5BufferZero(&pPhrase->poslist);
/* If the aStatic[] array is not large enough, allocate a large array
@@ -440,12 +422,14 @@ static int fts5ExprPhraseIsMatch(
int bFlag = 0;
const u8 *a = 0;
if( pTerm->pSynonym ){
rc = fts5ExprSynonymPoslist(pTerm, pNode->iRowid, &bFlag, (u8**)&a, &n);
rc = fts5ExprSynonymPoslist(
pTerm, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n
);
}else{
rc = sqlite3Fts5IterPoslist(pTerm->pIter, &a, &n, &dummy);
rc = sqlite3Fts5IterPoslist(pTerm->pIter, pColset, &a, &n, &dummy);
}
if( rc!=SQLITE_OK ) goto ismatch_out;
sqlite3Fts5PoslistReaderInit(iCol, a, n, &aIter[i]);
sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
aIter[i].bFlag = bFlag;
if( aIter[i].bEof ) goto ismatch_out;
}
@@ -468,11 +452,9 @@ static int fts5ExprPhraseIsMatch(
}
}while( bMatch==0 );
if( pColset==0 || fts5ExprColsetTest(pColset, FTS5_POS2COLUMN(iPos)) ){
/* Append position iPos to the output */
rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
if( rc!=SQLITE_OK ) goto ismatch_out;
}
/* Append position iPos to the output */
rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
if( rc!=SQLITE_OK ) goto ismatch_out;
for(i=0; i<pPhrase->nTerm; i++){
if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out;
@@ -767,61 +749,6 @@ static int fts5ExprSynonymAdvanceto(
return bEof;
}
/*
** IN/OUT parameter (*pa) points to a position list n bytes in size. If
** the position list contains entries for column iCol, then (*pa) is set
** to point to the sub-position-list for that column and the number of
** bytes in it returned. Or, if the argument position list does not
** contain any entries for column iCol, return 0.
*/
static int fts5ExprExtractCol(
const u8 **pa, /* IN/OUT: Pointer to poslist */
int n, /* IN: Size of poslist in bytes */
int iCol /* Column to extract from poslist */
){
int iCurrent = 0;
const u8 *p = *pa;
const u8 *pEnd = &p[n]; /* One byte past end of position list */
u8 prev = 0;
while( iCol!=iCurrent ){
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
** not part of a varint */
while( (prev & 0x80) || *p!=0x01 ){
prev = *p++;
if( p==pEnd ) return 0;
}
*pa = p++;
p += fts5GetVarint32(p, iCurrent);
}
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
** not part of a varint */
assert( (prev & 0x80)==0 );
while( p<pEnd && ((prev & 0x80) || *p!=0x01) ){
prev = *p++;
}
return p - (*pa);
}
static int fts5ExprExtractColset (
Fts5ExprColset *pColset, /* Colset to filter on */
const u8 *pPos, int nPos, /* Position list */
Fts5Buffer *pBuf /* Output buffer */
){
int rc = SQLITE_OK;
int i;
fts5BufferZero(pBuf);
for(i=0; i<pColset->nCol; i++){
const u8 *pSub = pPos;
int nSub = fts5ExprExtractCol(&pSub, nPos, pColset->aiCol[i]);
if( nSub ){
fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
}
}
return rc;
}
static int fts5ExprNearTest(
int *pRc,
@@ -868,35 +795,16 @@ static int fts5ExprTokenTest(
Fts5ExprNearset *pNear = pNode->pNear;
Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
Fts5ExprColset *pColset = pNear->pColset;
const u8 *pPos;
int nPos;
Fts5Colset *pColset = pNear->pColset;
int rc;
assert( pNode->eType==FTS5_TERM );
assert( pNear->nPhrase==1 && pPhrase->nTerm==1 );
assert( pPhrase->aTerm[0].pSynonym==0 );
rc = sqlite3Fts5IterPoslist(pIter, &pPos, &nPos, &pNode->iRowid);
/* If the term may match any column, then this must be a match.
** Return immediately in this case. Otherwise, try to find the
** part of the poslist that corresponds to the required column.
** If it can be found, return. If it cannot, the next iteration
** of the loop will test the next rowid in the database for this
** term. */
if( pColset==0 ){
assert( pPhrase->poslist.nSpace==0 );
pPhrase->poslist.p = (u8*)pPos;
pPhrase->poslist.n = nPos;
}else if( pColset->nCol==1 ){
assert( pPhrase->poslist.nSpace==0 );
pPhrase->poslist.n = fts5ExprExtractCol(&pPos, nPos, pColset->aiCol[0]);
pPhrase->poslist.p = (u8*)pPos;
}else if( rc==SQLITE_OK ){
rc = fts5ExprExtractColset(pColset, pPos, nPos, &pPhrase->poslist);
}
rc = sqlite3Fts5IterPoslist(pIter, pColset,
(const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid
);
pNode->bNomatch = (pPhrase->poslist.n==0);
return rc;
}
@@ -1002,6 +910,7 @@ static int fts5ExprNearInitAll(
pExpr->pIndex, p->zTerm, strlen(p->zTerm),
(pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
(pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
pNear->pColset,
&p->pIter
);
assert( rc==SQLITE_OK || p->pIter==0 );
@@ -1754,25 +1663,25 @@ void sqlite3Fts5ParseSetDistance(
/*
** The second argument passed to this function may be NULL, or it may be
** an existing Fts5ExprColset object. This function returns a pointer to
** an existing Fts5Colset object. This function returns a pointer to
** a new colset object containing the contents of (p) with new value column
** number iCol appended.
**
** If an OOM error occurs, store an error code in pParse and return NULL.
** The old colset object (if any) is not freed in this case.
*/
static Fts5ExprColset *fts5ParseColset(
static Fts5Colset *fts5ParseColset(
Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */
Fts5ExprColset *p, /* Existing colset object */
Fts5Colset *p, /* Existing colset object */
int iCol /* New column to add to colset object */
){
int nCol = p ? p->nCol : 0; /* Num. columns already in colset object */
Fts5ExprColset *pNew; /* New colset object to return */
Fts5Colset *pNew; /* New colset object to return */
assert( pParse->rc==SQLITE_OK );
assert( iCol>=0 && iCol<pParse->pConfig->nCol );
pNew = sqlite3_realloc(p, sizeof(Fts5ExprColset) + sizeof(int)*nCol);
pNew = sqlite3_realloc(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
if( pNew==0 ){
pParse->rc = SQLITE_NOMEM;
}else{
@@ -1797,12 +1706,12 @@ static Fts5ExprColset *fts5ParseColset(
return pNew;
}
Fts5ExprColset *sqlite3Fts5ParseColset(
Fts5Colset *sqlite3Fts5ParseColset(
Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */
Fts5ExprColset *pColset, /* Existing colset object */
Fts5Colset *pColset, /* Existing colset object */
Fts5Token *p
){
Fts5ExprColset *pRet = 0;
Fts5Colset *pRet = 0;
int iCol;
char *z; /* Dequoted copy of token p */
@@ -1832,7 +1741,7 @@ Fts5ExprColset *sqlite3Fts5ParseColset(
void sqlite3Fts5ParseSetColset(
Fts5Parse *pParse,
Fts5ExprNearset *pNear,
Fts5ExprColset *pColset
Fts5Colset *pColset
){
if( pNear ){
pNear->pColset = pColset;
@@ -2285,6 +2194,11 @@ int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0);
}
/* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */
#ifndef NDEBUG
(void)sqlite3Fts5ParserTrace;
#endif
return rc;
}
@@ -2320,4 +2234,3 @@ int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){
}
return nRet;
}
+357 -107
View File
@@ -291,7 +291,7 @@ struct Fts5Index {
int nMaxPendingData; /* Max pending data before flush to disk */
int nPendingData; /* Current bytes of pending data */
i64 iWriteRowid; /* Rowid for current doc being written */
Fts5Buffer scratch;
int bDelete; /* Current write is a delete */
/* Error state. */
int rc; /* Current error code */
@@ -307,14 +307,13 @@ struct Fts5Index {
};
struct Fts5DoclistIter {
u8 *a;
int n;
int i;
u8 *aEof; /* Pointer to 1 byte past end of doclist */
/* Output variables. aPoslist==0 at EOF */
i64 iRowid;
u8 *aPoslist;
int nPoslist;
int nSize;
};
/*
@@ -512,8 +511,9 @@ struct Fts5IndexIter {
int nSeg; /* Size of aSeg[] array */
int bRev; /* True to iterate in reverse order */
int bSkipEmpty; /* True to skip deleted entries */
int bEof; /* True at EOF */
u8 bSkipEmpty; /* True to skip deleted entries */
u8 bEof; /* True at EOF */
u8 bFiltered; /* True if column-filter already applied */
i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */
Fts5CResult *aFirst; /* Current merge state (see above) */
@@ -1458,7 +1458,8 @@ static void fts5SegIterNextPage(
*/
static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){
int nSz;
int n = fts5GetVarint32(p, nSz);
int n = 0;
fts5FastGetVarint32(p, n, nSz);
assert_nc( nSz>=0 );
*pnSz = nSz/2;
*pbDel = nSz & 0x0001;
@@ -1479,13 +1480,12 @@ static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){
static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
if( p->rc==SQLITE_OK ){
int iOff = pIter->iLeafOffset; /* Offset to read at */
int nSz;
ASSERT_SZLEAF_OK(pIter->pLeaf);
if( iOff>=pIter->pLeaf->szLeaf ){
p->rc = FTS5_CORRUPT;
}else{
const u8 *a = &pIter->pLeaf->p[iOff];
pIter->iLeafOffset += fts5GetPoslistSize(a, &pIter->nPos, &pIter->bDel);
}
fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
pIter->bDel = (nSz & 0x0001);
pIter->nPos = nSz>>1;
pIter->iLeafOffset = iOff;
}
}
@@ -1780,6 +1780,7 @@ static void fts5SegIterNext(
pIter->iEndofDoclist = nList+1;
sqlite3Fts5BufferSet(&p->rc, &pIter->term, strlen(zTerm), (u8*)zTerm);
pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
if( pbNewTerm ) *pbNewTerm = 1;
}
}else{
iOff = 0;
@@ -1940,14 +1941,6 @@ static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){
pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno);
}
#define fts5IndexGetVarint32(a, iOff, nVal) { \
nVal = (a)[iOff++]; \
if( nVal & 0x80 ){ \
iOff--; \
iOff += fts5GetVarint32(&(a)[iOff], nVal); \
} \
}
#define fts5IndexSkipVarint(a, iOff) { \
int iEnd = iOff+9; \
while( (a[iOff++] & 0x80) && iOff<iEnd ); \
@@ -1994,7 +1987,7 @@ static void fts5LeafSeek(
while( 1 ){
/* Figure out how many new bytes are in this term */
fts5IndexGetVarint32(a, iOff, nNew);
fts5FastGetVarint32(a, iOff, nNew);
if( nKeep<nMatch ){
goto search_failed;
}
@@ -2030,7 +2023,7 @@ static void fts5LeafSeek(
iOff = iTermOff;
/* Read the nKeep field of the next term. */
fts5IndexGetVarint32(a, iOff, nKeep);
fts5FastGetVarint32(a, iOff, nKeep);
}
search_failed:
@@ -2733,6 +2726,7 @@ static void fts5MultiIterNew2(
if( pNew ){
Fts5SegIter *pIter = &pNew->aSeg[1];
pNew->bFiltered = 1;
pIter->flags = FTS5_SEGITER_ONETERM;
if( pData->szLeaf>0 ){
pIter->pLeaf = pData;
@@ -3705,10 +3699,15 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
return ret;
}
#define fts5BufferSafeAppendBlob(pBuf, pBlob, nBlob) { \
assert( pBuf->nSpace>=(pBuf->n+nBlob) ); \
memcpy(&pBuf->p[pBuf->n], pBlob, nBlob); \
pBuf->n += nBlob; \
#define fts5BufferSafeAppendBlob(pBuf, pBlob, nBlob) { \
assert( (pBuf)->nSpace>=((pBuf)->n+nBlob) ); \
memcpy(&(pBuf)->p[(pBuf)->n], pBlob, nBlob); \
(pBuf)->n += nBlob; \
}
#define fts5BufferSafeAppendVarint(pBuf, iVal) { \
(pBuf)->n += sqlite3Fts5PutVarint(&(pBuf)->p[(pBuf)->n], (iVal)); \
assert( (pBuf)->nSpace>=(pBuf)->n ); \
}
/*
@@ -3938,12 +3937,81 @@ int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
static void fts5PoslistCallback(
Fts5Index *p,
void *pCtx,
void *pContext,
const u8 *pChunk, int nChunk
){
assert_nc( nChunk>=0 );
if( nChunk>0 ){
fts5BufferAppendBlob(&p->rc, (Fts5Buffer*)pCtx, nChunk, pChunk);
fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk);
}
}
typedef struct PoslistCallbackCtx PoslistCallbackCtx;
struct PoslistCallbackCtx {
Fts5Buffer *pBuf; /* Append to this buffer */
Fts5Colset *pColset; /* Restrict matches to this column */
int eState; /* See above */
};
/*
** TODO: Make this more efficient!
*/
static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
int i;
for(i=0; i<pColset->nCol; i++){
if( pColset->aiCol[i]==iCol ) return 1;
}
return 0;
}
static void fts5PoslistFilterCallback(
Fts5Index *p,
void *pContext,
const u8 *pChunk, int nChunk
){
PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext;
assert_nc( nChunk>=0 );
if( nChunk>0 ){
/* Search through to find the first varint with value 1. This is the
** start of the next columns hits. */
int i = 0;
int iStart = 0;
if( pCtx->eState==2 ){
int iCol;
fts5FastGetVarint32(pChunk, i, iCol);
if( fts5IndexColsetTest(pCtx->pColset, iCol) ){
pCtx->eState = 1;
fts5BufferSafeAppendVarint(pCtx->pBuf, 1);
}else{
pCtx->eState = 0;
}
}
do {
while( i<nChunk && pChunk[i]!=0x01 ){
while( pChunk[i] & 0x80 ) i++;
i++;
}
if( pCtx->eState ){
fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
}
if( i<nChunk ){
int iCol;
iStart = i;
i++;
if( i>=nChunk ){
pCtx->eState = 2;
}else{
fts5FastGetVarint32(pChunk, i, iCol);
pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol);
if( pCtx->eState ){
fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
iStart = i;
}
}
}
}while( i<nChunk );
}
}
@@ -3956,54 +4024,157 @@ static void fts5PoslistCallback(
static void fts5SegiterPoslist(
Fts5Index *p,
Fts5SegIter *pSeg,
Fts5Colset *pColset,
Fts5Buffer *pBuf
){
fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
if( pColset==0 ){
fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
}else{
PoslistCallbackCtx sCtx;
sCtx.pBuf = pBuf;
sCtx.pColset = pColset;
sCtx.eState = pColset ? fts5IndexColsetTest(pColset, 0) : 1;
assert( sCtx.eState==0 || sCtx.eState==1 );
fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
}
}
}
/*
** Iterator pMulti currently points to a valid entry (not EOF). This
** function appends a copy of the position-list of the entry pMulti
** currently points to to buffer pBuf.
**
** If an error occurs, an error code is left in p->rc. It is assumed
** no error has already occurred when this function is called.
** IN/OUT parameter (*pa) points to a position list n bytes in size. If
** the position list contains entries for column iCol, then (*pa) is set
** to point to the sub-position-list for that column and the number of
** bytes in it returned. Or, if the argument position list does not
** contain any entries for column iCol, return 0.
*/
static void fts5MultiIterPoslist(
static int fts5IndexExtractCol(
const u8 **pa, /* IN/OUT: Pointer to poslist */
int n, /* IN: Size of poslist in bytes */
int iCol /* Column to extract from poslist */
){
int iCurrent = 0; /* Anything before the first 0x01 is col 0 */
const u8 *p = *pa;
const u8 *pEnd = &p[n]; /* One byte past end of position list */
u8 prev = 0;
while( iCol!=iCurrent ){
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
** not part of a varint */
while( (prev & 0x80) || *p!=0x01 ){
prev = *p++;
if( p==pEnd ) return 0;
}
*pa = p++;
p += fts5GetVarint32(p, iCurrent);
}
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
** not part of a varint */
assert( (prev & 0x80)==0 );
while( p<pEnd && ((prev & 0x80) || *p!=0x01) ){
prev = *p++;
}
return p - (*pa);
}
/*
** Iterator pMulti currently points to a valid entry (not EOF). This
** function appends the following to buffer pBuf:
**
** * The varint iDelta, and
** * the position list that currently points to, including the size field.
**
** If argument pColset is NULL, then the position list is filtered according
** to pColset before being appended to the buffer. If this means there are
** no entries in the position list, nothing is appended to the buffer (not
** even iDelta).
**
** If an error occurs, an error code is left in p->rc.
*/
static int fts5AppendPoslist(
Fts5Index *p,
i64 iDelta,
Fts5IndexIter *pMulti,
int bSz, /* Append a size field before the data */
Fts5Colset *pColset,
Fts5Buffer *pBuf
){
if( p->rc==SQLITE_OK ){
Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ];
assert( fts5MultiIterEof(p, pMulti)==0 );
assert( pSeg->nPos>0 );
if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+9+9) ){
int iSv1;
int iSv2;
int iData;
/* Append iDelta */
iSv1 = pBuf->n;
fts5BufferSafeAppendVarint(pBuf, iDelta);
if( bSz ){
/* WRITEPOSLISTSIZE */
fts5BufferAppendVarint(&p->rc, pBuf, pSeg->nPos*2);
iSv2 = pBuf->n;
fts5BufferSafeAppendVarint(pBuf, pSeg->nPos*2);
iData = pBuf->n;
if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf
&& (pColset==0 || pColset->nCol==1)
){
const u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
int nPos;
if( pColset ){
nPos = fts5IndexExtractCol(&pPos, pSeg->nPos, pColset->aiCol[0]);
}else{
nPos = pSeg->nPos;
}
fts5BufferSafeAppendBlob(pBuf, pPos, nPos);
}else{
fts5SegiterPoslist(p, pSeg, pColset, pBuf);
}
if( pColset ){
int nActual = pBuf->n - iData;
if( nActual!=pSeg->nPos ){
if( nActual==0 ){
pBuf->n = iSv1;
return 1;
}else{
int nReq = sqlite3Fts5GetVarintLen((u32)(nActual*2));
while( iSv2<(iData-nReq) ){ pBuf->p[iSv2++] = 0x80; }
sqlite3Fts5PutVarint(&pBuf->p[iSv2], nActual*2);
}
}
}
}
fts5SegiterPoslist(p, pSeg, pBuf);
}
return 0;
}
static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
if( pIter->i<pIter->n ){
int bDummy;
if( pIter->i ){
i64 iDelta;
pIter->i += fts5GetVarint(&pIter->a[pIter->i], (u64*)&iDelta);
pIter->iRowid += iDelta;
}else{
pIter->i += fts5GetVarint(&pIter->a[pIter->i], (u64*)&pIter->iRowid);
}
pIter->i += fts5GetPoslistSize(
&pIter->a[pIter->i], &pIter->nPoslist, &bDummy
);
pIter->aPoslist = &pIter->a[pIter->i];
pIter->i += pIter->nPoslist;
}else{
u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist;
assert( pIter->aPoslist );
if( p>=pIter->aEof ){
pIter->aPoslist = 0;
}else{
i64 iDelta;
p += fts5GetVarint(p, (u64*)&iDelta);
pIter->iRowid += iDelta;
/* Read position list size */
if( p[0] & 0x80 ){
int nPos;
pIter->nSize = fts5GetVarint32(p, nPos);
pIter->nPoslist = (nPos>>1);
}else{
pIter->nPoslist = ((int)(p[0])) >> 1;
pIter->nSize = 1;
}
pIter->aPoslist = p;
}
}
@@ -4012,27 +4183,34 @@ static void fts5DoclistIterInit(
Fts5DoclistIter *pIter
){
memset(pIter, 0, sizeof(*pIter));
pIter->a = pBuf->p;
pIter->n = pBuf->n;
pIter->aPoslist = pBuf->p;
pIter->aEof = &pBuf->p[pBuf->n];
fts5DoclistIterNext(pIter);
}
#if 0
/*
** Append a doclist to buffer pBuf.
**
** This function assumes that space within the buffer has already been
** allocated.
*/
static void fts5MergeAppendDocid(
int *pRc, /* IN/OUT: Error code */
Fts5Buffer *pBuf, /* Buffer to write to */
i64 *piLastRowid, /* IN/OUT: Previous rowid written (if any) */
i64 iRowid /* Rowid to append */
){
if( pBuf->n==0 ){
fts5BufferAppendVarint(pRc, pBuf, iRowid);
}else{
fts5BufferAppendVarint(pRc, pBuf, iRowid - *piLastRowid);
}
assert( pBuf->n!=0 || (*piLastRowid)==0 );
fts5BufferSafeAppendVarint(pBuf, iRowid - *piLastRowid);
*piLastRowid = iRowid;
}
#endif
#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \
(iLastRowid) = (iRowid); \
}
/*
** Buffers p1 and p2 contain doclists. This function merges the content
@@ -4056,53 +4234,58 @@ static void fts5MergePrefixLists(
memset(&out, 0, sizeof(out));
memset(&tmp, 0, sizeof(tmp));
sqlite3Fts5BufferGrow(&p->rc, &out, p1->n + p2->n);
fts5DoclistIterInit(p1, &i1);
fts5DoclistIterInit(p2, &i2);
while( p->rc==SQLITE_OK && (i1.aPoslist!=0 || i2.aPoslist!=0) ){
if( i2.aPoslist==0 || (i1.aPoslist && i1.iRowid<i2.iRowid) ){
/* Copy entry from i1 */
fts5MergeAppendDocid(&p->rc, &out, &iLastRowid, i1.iRowid);
/* WRITEPOSLISTSIZE */
fts5BufferAppendVarint(&p->rc, &out, i1.nPoslist * 2);
fts5BufferAppendBlob(&p->rc, &out, i1.nPoslist, i1.aPoslist);
fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize);
fts5DoclistIterNext(&i1);
}
else if( i1.aPoslist==0 || i2.iRowid!=i1.iRowid ){
/* Copy entry from i2 */
fts5MergeAppendDocid(&p->rc, &out, &iLastRowid, i2.iRowid);
/* WRITEPOSLISTSIZE */
fts5BufferAppendVarint(&p->rc, &out, i2.nPoslist * 2);
fts5BufferAppendBlob(&p->rc, &out, i2.nPoslist, i2.aPoslist);
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize);
fts5DoclistIterNext(&i2);
}
else{
Fts5PoslistReader r1;
Fts5PoslistReader r2;
Fts5PoslistWriter writer;
i64 iPos1 = 0;
i64 iPos2 = 0;
int iOff1 = 0;
int iOff2 = 0;
u8 *a1 = &i1.aPoslist[i1.nSize];
u8 *a2 = &i2.aPoslist[i2.nSize];
Fts5PoslistWriter writer;
memset(&writer, 0, sizeof(writer));
/* Merge the two position lists. */
fts5MergeAppendDocid(&p->rc, &out, &iLastRowid, i2.iRowid);
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
fts5BufferZero(&tmp);
sqlite3Fts5PoslistReaderInit(-1, i1.aPoslist, i1.nPoslist, &r1);
sqlite3Fts5PoslistReaderInit(-1, i2.aPoslist, i2.nPoslist, &r2);
while( p->rc==SQLITE_OK && (r1.bEof==0 || r2.bEof==0) ){
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
while( p->rc==SQLITE_OK && (iPos1>=0 || iPos2>=0) ){
i64 iNew;
if( r2.bEof || (r1.bEof==0 && r1.iPos<r2.iPos) ){
iNew = r1.iPos;
sqlite3Fts5PoslistReaderNext(&r1);
if( iPos2<0 || (iPos1>=0 && iPos1<iPos2) ){
iNew = iPos1;
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
}else{
iNew = r2.iPos;
sqlite3Fts5PoslistReaderNext(&r2);
if( r1.iPos==r2.iPos ) sqlite3Fts5PoslistReaderNext(&r1);
iNew = iPos2;
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
if( iPos1==iPos2 ){
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1,&iPos1);
}
}
p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew);
}
/* WRITEPOSLISTSIZE */
fts5BufferAppendVarint(&p->rc, &out, tmp.n * 2);
fts5BufferAppendBlob(&p->rc, &out, tmp.n, tmp.p);
fts5BufferSafeAppendVarint(&out, tmp.n * 2);
fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
fts5DoclistIterNext(&i1);
fts5DoclistIterNext(&i2);
}
@@ -4125,7 +4308,8 @@ static void fts5SetupPrefixIter(
int bDesc, /* True for "ORDER BY rowid DESC" */
const u8 *pToken, /* Buffer containing prefix to match */
int nToken, /* Size of buffer pToken in bytes */
Fts5IndexIter **ppIter /* OUT: New iterator */
Fts5Colset *pColset, /* Restrict matches to these columns */
Fts5IndexIter **ppIter /* OUT: New iterator */
){
Fts5Structure *pStruct;
Fts5Buffer *aBuf;
@@ -4164,14 +4348,18 @@ static void fts5SetupPrefixIter(
fts5BufferZero(&aBuf[i]);
}
}
iLastRowid = 0;
}
fts5MergeAppendDocid(&p->rc, &doclist, &iLastRowid, iRowid);
fts5MultiIterPoslist(p, p1, 1, &doclist);
if( !fts5AppendPoslist(p, iRowid-iLastRowid, p1, pColset, &doclist) ){
iLastRowid = iRowid;
}
}
for(i=0; i<nBuf; i++){
fts5MergePrefixLists(p, &doclist, &aBuf[i]);
if( p->rc==SQLITE_OK ){
fts5MergePrefixLists(p, &doclist, &aBuf[i]);
}
fts5BufferFree(&aBuf[i]);
}
fts5MultiIterFree(p, p1);
@@ -4195,7 +4383,7 @@ static void fts5SetupPrefixIter(
** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain
** to the document with rowid iRowid.
*/
int sqlite3Fts5IndexBeginWrite(Fts5Index *p, i64 iRowid){
int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
assert( p->rc==SQLITE_OK );
/* Allocate the hash table if it has not already been allocated */
@@ -4204,10 +4392,15 @@ int sqlite3Fts5IndexBeginWrite(Fts5Index *p, i64 iRowid){
}
/* Flush the hash table to disk if required */
if( iRowid<=p->iWriteRowid || (p->nPendingData > p->nMaxPendingData) ){
if( iRowid<p->iWriteRowid
|| (iRowid==p->iWriteRowid && p->bDelete==0)
|| (p->nPendingData > p->nMaxPendingData)
){
fts5IndexFlush(p);
}
p->iWriteRowid = iRowid;
p->bDelete = bDelete;
return fts5IndexReturn(p);
}
@@ -4306,7 +4499,6 @@ int sqlite3Fts5IndexClose(Fts5Index *p){
sqlite3_finalize(p->pIdxDeleter);
sqlite3_finalize(p->pIdxSelect);
sqlite3Fts5HashFree(p->pHash);
sqlite3Fts5BufferFree(&p->scratch);
sqlite3_free(p->zDataTbl);
sqlite3_free(p);
}
@@ -4367,6 +4559,7 @@ int sqlite3Fts5IndexWrite(
Fts5Config *pConfig = p->pConfig;
assert( p->rc==SQLITE_OK );
assert( (iCol<0)==p->bDelete );
/* Add the entry to the main terms index. */
rc = sqlite3Fts5HashWrite(
@@ -4393,6 +4586,7 @@ int sqlite3Fts5IndexQuery(
Fts5Index *p, /* FTS index to query */
const char *pToken, int nToken, /* Token (or prefix) to query for */
int flags, /* Mask of FTS5INDEX_QUERY_X flags */
Fts5Colset *pColset, /* Match these columns only */
Fts5IndexIter **ppIter /* OUT: New iterator object */
){
Fts5Config *pConfig = p->pConfig;
@@ -4436,7 +4630,7 @@ int sqlite3Fts5IndexQuery(
}else{
int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
buf.p[0] = FTS5_MAIN_PREFIX;
fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, &pRet);
fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet);
}
if( p->rc ){
@@ -4516,6 +4710,26 @@ const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIter, int *pn){
}
static int fts5IndexExtractColset (
Fts5Colset *pColset, /* Colset to filter on */
const u8 *pPos, int nPos, /* Position list */
Fts5Buffer *pBuf /* Output buffer */
){
int rc = SQLITE_OK;
int i;
fts5BufferZero(pBuf);
for(i=0; i<pColset->nCol; i++){
const u8 *pSub = pPos;
int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
if( nSub ){
fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
}
}
return rc;
}
/*
** Return a pointer to a buffer containing a copy of the position list for
** the current entry. Output variable *pn is set to the size of the buffer
@@ -4526,6 +4740,7 @@ const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIter, int *pn){
*/
int sqlite3Fts5IterPoslist(
Fts5IndexIter *pIter,
Fts5Colset *pColset, /* Column filter (or NULL) */
const u8 **pp, /* OUT: Pointer to position-list data */
int *pn, /* OUT: Size of position-list in bytes */
i64 *piRowid /* OUT: Current rowid */
@@ -4533,13 +4748,25 @@ int sqlite3Fts5IterPoslist(
Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
assert( pIter->pIndex->rc==SQLITE_OK );
*piRowid = pSeg->iRowid;
*pn = pSeg->nPos;
if( pSeg->iLeafOffset+pSeg->nPos <= pSeg->pLeaf->szLeaf ){
*pp = &pSeg->pLeaf->p[pSeg->iLeafOffset];
if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
if( pColset==0 || pIter->bFiltered ){
*pn = pSeg->nPos;
*pp = pPos;
}else if( pColset->nCol==1 ){
*pp = pPos;
*pn = fts5IndexExtractCol(pp, pSeg->nPos, pColset->aiCol[0]);
}else{
fts5BufferZero(&pIter->poslist);
fts5IndexExtractColset(pColset, pPos, pSeg->nPos, &pIter->poslist);
*pp = pIter->poslist.p;
*pn = pIter->poslist.n;
}
}else{
fts5BufferZero(&pIter->poslist);
fts5SegiterPoslist(pIter->pIndex, pSeg, &pIter->poslist);
fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
*pp = pIter->poslist.p;
*pn = pIter->poslist.n;
}
return fts5IndexReturn(pIter->pIndex);
}
@@ -4551,10 +4778,10 @@ int sqlite3Fts5IterPoslist(
*/
int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf){
Fts5Index *p = pIter->pIndex;
Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
assert( p->rc==SQLITE_OK );
fts5BufferZero(pBuf);
fts5MultiIterPoslist(p, pIter, 0, pBuf);
fts5SegiterPoslist(p, pSeg, 0, pBuf);
return fts5IndexReturn(p);
}
@@ -4729,17 +4956,17 @@ static int fts5QueryCksum(
){
u64 cksum = *pCksum;
Fts5IndexIter *pIdxIter = 0;
int rc = sqlite3Fts5IndexQuery(p, z, n, flags, &pIdxIter);
int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIdxIter);
while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIdxIter) ){
i64 dummy;
const u8 *pPos;
int nPos;
i64 rowid = sqlite3Fts5IterRowid(pIdxIter);
rc = sqlite3Fts5IterPoslist(pIdxIter, &pPos, &nPos, &dummy);
rc = sqlite3Fts5IterPoslist(pIdxIter, 0, &pPos, &nPos, &dummy);
if( rc==SQLITE_OK ){
Fts5PoslistReader sReader;
for(sqlite3Fts5PoslistReaderInit(-1, pPos, nPos, &sReader);
for(sqlite3Fts5PoslistReaderInit(pPos, nPos, &sReader);
sReader.bEof==0;
sqlite3Fts5PoslistReaderNext(&sReader)
){
@@ -5103,7 +5330,7 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
poslist.n = 0;
fts5MultiIterPoslist(p, pIter, 0, &poslist);
fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst] , 0, &poslist);
while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
int iCol = FTS5_POS2COLUMN(iPos);
int iTokOff = FTS5_POS2OFFSET(iPos);
@@ -5243,6 +5470,29 @@ static void fts5DecodeStructure(
fts5StructureRelease(p);
}
/*
** This is part of the fts5_decode() debugging aid.
**
** Arguments pBlob/nBlob contain an "averages" record. This function
** appends a human-readable representation of record to the buffer passed
** as the second argument.
*/
static void fts5DecodeAverages(
int *pRc, /* IN/OUT: error code */
Fts5Buffer *pBuf,
const u8 *pBlob, int nBlob
){
int i = 0;
const char *zSpace = "";
while( i<nBlob ){
u64 iVal;
i += sqlite3Fts5GetVarint(&pBlob[i], &iVal);
sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "%s%d", zSpace, (int)iVal);
zSpace = " ";
}
}
/*
** Buffer (a/n) is assumed to contain a list of serialized varints. Read
** each varint and append its string representation to buffer pBuf. Return
@@ -5344,7 +5594,7 @@ static void fts5DecodeFunction(
}
}else if( iSegid==0 ){
if( iRowid==FTS5_AVERAGES_ROWID ){
/* todo */
fts5DecodeAverages(&rc, &s, a, n);
}else{
fts5DecodeStructure(&rc, &s, a, n);
}
@@ -5361,7 +5611,7 @@ static void fts5DecodeFunction(
memset(&term, 0, sizeof(Fts5Buffer));
if( n<4 ){
sqlite3Fts5BufferSet(&rc, &s, 8, (const u8*)"corrupt");
sqlite3Fts5BufferSet(&rc, &s, 7, (const u8*)"corrupt");
goto decode_out;
}else{
iRowidOff = fts5GetU16(&a[0]);
+169 -63
View File
@@ -440,6 +440,19 @@ static int fts5CreateMethod(
#define FTS5_PLAN_SCAN 5 /* No usable constraint */
#define FTS5_PLAN_ROWID 6 /* (rowid = ?) */
/*
** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this
** extension is currently being used by a version of SQLite too old to
** support index-info flags. In that case this function is a no-op.
*/
static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
#if SQLITE_VERSION_NUMBER>=3008012
if( sqlite3_libversion_number()>=3008012 ){
pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
}
#endif
}
/*
** Implementation of the xBestIndex method for FTS5 tables. Within the
** WHERE constraint, it searches for the following:
@@ -492,8 +505,10 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
int omit; /* True to omit this if found */
int iConsIndex; /* Index in pInfo->aConstraint[] */
} aConstraint[] = {
{SQLITE_INDEX_CONSTRAINT_MATCH, FTS5_BI_MATCH, 1, 1, -1},
{SQLITE_INDEX_CONSTRAINT_MATCH, FTS5_BI_RANK, 2, 1, -1},
{SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ,
FTS5_BI_MATCH, 1, 1, -1},
{SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ,
FTS5_BI_RANK, 2, 1, -1},
{SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_ROWID_EQ, 0, 0, -1},
{SQLITE_INDEX_CONSTRAINT_LT|SQLITE_INDEX_CONSTRAINT_LE,
FTS5_BI_ROWID_LE, 0, 0, -1},
@@ -546,6 +561,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH);
if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){
pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0;
if( bHasMatch==0 ) fts5SetUniqueFlag(pInfo);
}else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0;
}else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
@@ -1284,15 +1300,14 @@ static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){
*/
static int fts5SpecialInsert(
Fts5Table *pTab, /* Fts5 table object */
sqlite3_value *pCmd, /* Value inserted into special column */
const char *zCmd, /* Text inserted into table-name column */
sqlite3_value *pVal /* Value inserted into rank column */
){
Fts5Config *pConfig = pTab->pConfig;
const char *z = (const char*)sqlite3_value_text(pCmd);
int rc = SQLITE_OK;
int bError = 0;
if( 0==sqlite3_stricmp("delete-all", z) ){
if( 0==sqlite3_stricmp("delete-all", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
fts5SetVtabError(pTab,
"'delete-all' may only be used with a "
@@ -1302,7 +1317,7 @@ static int fts5SpecialInsert(
}else{
rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
}
}else if( 0==sqlite3_stricmp("rebuild", z) ){
}else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NONE ){
fts5SetVtabError(pTab,
"'rebuild' may not be used with a contentless fts5 table"
@@ -1311,27 +1326,27 @@ static int fts5SpecialInsert(
}else{
rc = sqlite3Fts5StorageRebuild(pTab->pStorage);
}
}else if( 0==sqlite3_stricmp("optimize", z) ){
}else if( 0==sqlite3_stricmp("optimize", zCmd) ){
rc = sqlite3Fts5StorageOptimize(pTab->pStorage);
}else if( 0==sqlite3_stricmp("merge", z) ){
}else if( 0==sqlite3_stricmp("merge", zCmd) ){
int nMerge = sqlite3_value_int(pVal);
rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge);
}else if( 0==sqlite3_stricmp("integrity-check", z) ){
}else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){
rc = sqlite3Fts5StorageIntegrity(pTab->pStorage);
#ifdef SQLITE_DEBUG
}else if( 0==sqlite3_stricmp("prefix-index", z) ){
}else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
pConfig->bPrefixIndex = sqlite3_value_int(pVal);
#endif
}else{
rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, z, pVal, &bError);
rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError);
}
if( rc==SQLITE_OK ){
if( bError ){
rc = SQLITE_ERROR;
}else{
rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, z, pVal, 0);
rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0);
}
}
}
@@ -1352,10 +1367,35 @@ static int fts5SpecialDelete(
return rc;
}
static void fts5StorageInsert(
int *pRc,
Fts5Table *pTab,
sqlite3_value **apVal,
i64 *piRowid
){
int rc = *pRc;
if( rc==SQLITE_OK ){
rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
}
*pRc = rc;
}
/*
** This function is the implementation of the xUpdate callback used by
** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
** inserted, updated or deleted.
**
** A delete specifies a single argument - the rowid of the row to remove.
**
** Update and insert operations pass:
**
** 1. The "old" rowid, or NULL.
** 2. The "new" rowid.
** 3. Values for each of the nCol matchable columns.
** 4. Values for the two hidden columns (<tablename> and "rank").
*/
static int fts5UpdateMethod(
sqlite3_vtab *pVtab, /* Virtual table handle */
@@ -1366,65 +1406,108 @@ static int fts5UpdateMethod(
Fts5Table *pTab = (Fts5Table*)pVtab;
Fts5Config *pConfig = pTab->pConfig;
int eType0; /* value_type() of apVal[0] */
int eConflict; /* ON CONFLICT for this DML */
int rc = SQLITE_OK; /* Return code */
/* A transaction must be open when this is called. */
assert( pTab->ts.eState==1 );
assert( pVtab->zErrMsg==0 );
assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
assert( nArg==1
|| sqlite3_value_type(apVal[1])==SQLITE_INTEGER
|| sqlite3_value_type(apVal[1])==SQLITE_NULL
);
assert( pTab->pConfig->pzErrmsg==0 );
pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
/* A delete specifies a single argument - the rowid of the row to remove.
** Update and insert operations pass:
**
** 1. The "old" rowid, or NULL.
** 2. The "new" rowid.
** 3. Values for each of the nCol matchable columns.
** 4. Values for the two hidden columns (<tablename> and "rank").
*/
/* Put any active cursors into REQUIRE_SEEK state. */
fts5TripCursors(pTab);
eType0 = sqlite3_value_type(apVal[0]);
eConflict = sqlite3_vtab_on_conflict(pConfig->db);
if( eType0==SQLITE_NULL
&& sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL
){
/* A "special" INSERT op. These are handled separately. */
const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]);
if( pConfig->eContent!=FTS5_CONTENT_NORMAL
&& 0==sqlite3_stricmp("delete", z)
){
rc = fts5SpecialDelete(pTab, apVal, pRowid);
}else{
rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
}
}else{
/* A regular INSERT, UPDATE or DELETE statement. The trick here is that
** any conflict on the rowid value must be detected before any
** modifications are made to the database file. There are 4 cases:
**
** 1) DELETE
** 2) UPDATE (rowid not modified)
** 3) UPDATE (rowid modified)
** 4) INSERT
**
** Cases 3 and 4 may violate the rowid constraint.
*/
int eConflict = sqlite3_vtab_on_conflict(pConfig->db);
assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
assert( pVtab->zErrMsg==0 );
assert( (nArg==1 && eType0==SQLITE_INTEGER) || nArg==(2+pConfig->nCol+2) );
assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
assert( nArg!=1 || eType0==SQLITE_INTEGER );
fts5TripCursors(pTab);
if( eType0==SQLITE_INTEGER ){
if( fts5IsContentless(pTab) ){
/* Filter out attempts to run UPDATE or DELETE on contentless tables.
** This is not suported. */
if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
pTab->base.zErrMsg = sqlite3_mprintf(
"cannot %s contentless fts5 table: %s",
(nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
);
rc = SQLITE_ERROR;
}else{
}
/* Case 1: DELETE */
else if( nArg==1 ){
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel);
}
}else{
sqlite3_value *pCmd = apVal[2 + pConfig->nCol];
assert( nArg>1 );
if( SQLITE_NULL!=sqlite3_value_type(pCmd) ){
const char *z = (const char*)sqlite3_value_text(pCmd);
if( pConfig->eContent!=FTS5_CONTENT_NORMAL
&& 0==sqlite3_stricmp("delete", z)
/* Case 2: INSERT */
else if( eType0!=SQLITE_INTEGER ){
/* If this is a REPLACE, first remove the current entry (if any) */
if( eConflict==SQLITE_REPLACE
&& sqlite3_value_type(apVal[1])==SQLITE_INTEGER
){
rc = fts5SpecialDelete(pTab, apVal, pRowid);
}else{
rc = fts5SpecialInsert(pTab, pCmd, apVal[2 + pConfig->nCol + 1]);
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
/* Case 2: UPDATE */
else{
i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
if( iOld!=iNew ){
if( eConflict==SQLITE_REPLACE ){
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
if( rc==SQLITE_OK ){
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}else{
rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
if( rc==SQLITE_OK ){
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
}
}
}else{
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
goto update_method_out;
}
}
if( rc==SQLITE_OK && nArg>1 ){
rc = sqlite3Fts5StorageInsert(pTab->pStorage, apVal, eConflict, pRowid);
}
update_method_out:
pTab->pConfig->pzErrmsg = 0;
return rc;
}
@@ -1560,7 +1643,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
for(i=0; i<nIter; i++){
const u8 *a;
int n = fts5CsrPoslist(pCsr, i, &a);
sqlite3Fts5PoslistReaderInit(-1, a, n, &aIter[i]);
sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
}
while( 1 ){
@@ -2132,14 +2215,16 @@ static int fts5CreateAux(
int rc = sqlite3_overload_function(pGlobal->db, zName, -1);
if( rc==SQLITE_OK ){
Fts5Auxiliary *pAux;
int nName; /* Size of zName in bytes, including \0 */
int nByte; /* Bytes of space to allocate */
nByte = sizeof(Fts5Auxiliary) + strlen(zName) + 1;
nName = (int)strlen(zName) + 1;
nByte = sizeof(Fts5Auxiliary) + nName;
pAux = (Fts5Auxiliary*)sqlite3_malloc(nByte);
if( pAux ){
memset(pAux, 0, nByte);
pAux->zFunc = (char*)&pAux[1];
strcpy(pAux->zFunc, zName);
memcpy(pAux->zFunc, zName, nName);
pAux->pGlobal = pGlobal;
pAux->pUserData = pUserData;
pAux->xFunc = xFunc;
@@ -2167,15 +2252,17 @@ static int fts5CreateTokenizer(
){
Fts5Global *pGlobal = (Fts5Global*)pApi;
Fts5TokenizerModule *pNew;
int nName; /* Size of zName and its \0 terminator */
int nByte; /* Bytes of space to allocate */
int rc = SQLITE_OK;
nByte = sizeof(Fts5TokenizerModule) + strlen(zName) + 1;
nName = (int)strlen(zName) + 1;
nByte = sizeof(Fts5TokenizerModule) + nName;
pNew = (Fts5TokenizerModule*)sqlite3_malloc(nByte);
if( pNew ){
memset(pNew, 0, nByte);
pNew->zName = (char*)&pNew[1];
strcpy(pNew->zName, zName);
memcpy(pNew->zName, zName, nName);
pNew->pUserData = pUserData;
pNew->x = *pTokenizer;
pNew->xDestroy = xDestroy;
@@ -2310,14 +2397,7 @@ static void fts5SourceIdFunc(
sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_fts5_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
static int fts5Init(sqlite3 *db){
static const sqlite3_module fts5Mod = {
/* iVersion */ 2,
/* xCreate */ fts5CreateMethod,
@@ -2347,8 +2427,6 @@ int sqlite3_fts5_init(
int rc;
Fts5Global *pGlobal = 0;
SQLITE_EXTENSION_INIT2(pApi);
pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
if( pGlobal==0 ){
rc = SQLITE_NOMEM;
@@ -2380,6 +2458,16 @@ int sqlite3_fts5_init(
return rc;
}
/*
** The following functions are used to register the module with SQLite. If
** this module is being built as part of the SQLite core (SQLITE_CORE is
** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
**
** Or, if this module is being built as a loadable extension,
** sqlite3Fts5Init() is omitted and the two standard entry points
** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
*/
#ifndef SQLITE_CORE
#ifdef _WIN32
__declspec(dllexport)
#endif
@@ -2388,7 +2476,25 @@ int sqlite3_fts_init(
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
return sqlite3_fts5_init(db, pzErrMsg, pApi);
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
return fts5Init(db);
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_fts5_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
return fts5Init(db);
}
#else
int sqlite3Fts5Init(sqlite3 *db){
return fts5Init(db);
}
#endif
+56 -45
View File
@@ -392,7 +392,7 @@ static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){
Fts5InsertCtx ctx;
ctx.pStorage = p;
ctx.iCol = -1;
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, iDel);
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
if( pConfig->abUnindexed[iCol-1] ) continue;
ctx.szCol = 0;
@@ -549,7 +549,7 @@ int sqlite3Fts5StorageSpecialDelete(
ctx.pStorage = p;
ctx.iCol = -1;
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, iDel);
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
for(iCol=0; rc==SQLITE_OK && iCol<pConfig->nCol; iCol++){
if( pConfig->abUnindexed[iCol] ) continue;
ctx.szCol = 0;
@@ -639,7 +639,7 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
i64 iRowid = sqlite3_column_int64(pScan, 0);
sqlite3Fts5BufferZero(&buf);
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, iRowid);
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
@@ -705,58 +705,69 @@ static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){
}
/*
** Insert a new row into the FTS table.
** Insert a new row into the FTS content table.
*/
int sqlite3Fts5StorageInsert(
Fts5Storage *p, /* Storage module to write to */
sqlite3_value **apVal, /* Array of values passed to xUpdate() */
int eConflict, /* on conflict clause */
i64 *piRowid /* OUT: rowid of new record */
int sqlite3Fts5StorageContentInsert(
Fts5Storage *p,
sqlite3_value **apVal,
i64 *piRowid
){
Fts5Config *pConfig = p->pConfig;
int rc = SQLITE_OK;
/* Insert the new row into the %_content table. */
if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
*piRowid = sqlite3_value_int64(apVal[1]);
}else{
rc = fts5StorageNewRowid(p, piRowid);
}
}else{
sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
int i; /* Counter variable */
#if 0
if( eConflict==SQLITE_REPLACE ){
eStmt = FTS5_STMT_REPLACE_CONTENT;
rc = fts5StorageDeleteFromIndex(p, sqlite3_value_int64(apVal[1]));
}else{
eStmt = FTS5_STMT_INSERT_CONTENT;
}
#endif
if( rc==SQLITE_OK ){
rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
}
for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
rc = sqlite3_bind_value(pInsert, i, apVal[i]);
}
if( rc==SQLITE_OK ){
sqlite3_step(pInsert);
rc = sqlite3_reset(pInsert);
}
*piRowid = sqlite3_last_insert_rowid(pConfig->db);
}
return rc;
}
/*
** Insert new entries into the FTS index and %_docsize table.
*/
int sqlite3Fts5StorageIndexInsert(
Fts5Storage *p,
sqlite3_value **apVal,
i64 iRowid
){
Fts5Config *pConfig = p->pConfig;
int rc = SQLITE_OK; /* Return code */
sqlite3_stmt *pInsert = 0; /* Statement used to write %_content table */
int eStmt = 0; /* Type of statement used on %_content */
int i; /* Counter variable */
Fts5InsertCtx ctx; /* Tokenization callback context object */
Fts5Buffer buf; /* Buffer used to build up %_docsize blob */
memset(&buf, 0, sizeof(Fts5Buffer));
ctx.pStorage = p;
rc = fts5StorageLoadTotals(p, 1);
/* Insert the new row into the %_content table. */
if( rc==SQLITE_OK ){
if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
*piRowid = sqlite3_value_int64(apVal[1]);
}else{
rc = fts5StorageNewRowid(p, piRowid);
}
}else{
if( eConflict==SQLITE_REPLACE ){
eStmt = FTS5_STMT_REPLACE_CONTENT;
rc = fts5StorageDeleteFromIndex(p, sqlite3_value_int64(apVal[1]));
}else{
eStmt = FTS5_STMT_INSERT_CONTENT;
}
if( rc==SQLITE_OK ){
rc = fts5StorageGetStmt(p, eStmt, &pInsert, 0);
}
for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
rc = sqlite3_bind_value(pInsert, i, apVal[i]);
}
if( rc==SQLITE_OK ){
sqlite3_step(pInsert);
rc = sqlite3_reset(pInsert);
}
*piRowid = sqlite3_last_insert_rowid(pConfig->db);
}
}
/* Add new entries to the FTS index */
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, *piRowid);
ctx.pStorage = p;
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
}
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
ctx.szCol = 0;
@@ -776,7 +787,7 @@ int sqlite3Fts5StorageInsert(
/* Write the %_docsize record */
if( rc==SQLITE_OK ){
rc = fts5StorageInsertDocsize(p, *piRowid, &buf);
rc = fts5StorageInsertDocsize(p, iRowid, &buf);
}
sqlite3_free(buf.p);
-1
View File
@@ -976,7 +976,6 @@ static int f5tTokenHash(
int objc,
Tcl_Obj *CONST objv[]
){
int bOld = sqlite3_fts5_may_be_corrupt;
char *z;
int n;
unsigned int iVal;
+2 -2
View File
@@ -349,7 +349,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
i64 iPos = 0; /* 64-bit position read from poslist */
int iOff = 0; /* Current offset within position list */
rc = sqlite3Fts5IterPoslist(pCsr->pIter, &pPos, &nPos, &dummy);
rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy);
if( rc==SQLITE_OK ){
if( pTab->eType==FTS5_VOCAB_ROW ){
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
@@ -402,7 +402,7 @@ static int fts5VocabFilterMethod(
const int flags = FTS5INDEX_QUERY_SCAN;
fts5VocabResetCursor(pCsr);
rc = sqlite3Fts5IndexQuery(pCsr->pIndex, 0, 0, flags, &pCsr->pIter);
rc = sqlite3Fts5IndexQuery(pCsr->pIndex, 0, 0, flags, 0, &pCsr->pIter);
if( rc==SQLITE_OK ){
rc = fts5VocabNextMethod(pCursor);
}
+3 -2
View File
@@ -67,6 +67,7 @@
%left COLON.
input ::= expr(X). { sqlite3Fts5ParseFinished(pParse, X); }
%destructor input { (void)pParse; }
%type cnearset {Fts5ExprNode*}
%type expr {Fts5ExprNode*}
@@ -101,9 +102,9 @@ cnearset(A) ::= colset(X) COLON nearset(Y). {
A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, Y);
}
%type colset {Fts5ExprColset*}
%type colset {Fts5Colset*}
%destructor colset { sqlite3_free($$); }
%type colsetlist {Fts5ExprColset*}
%type colsetlist {Fts5Colset*}
%destructor colsetlist { sqlite3_free($$); }
colset(A) ::= LCP colsetlist(X) RCP. { A = X; }
-1
View File
@@ -17,7 +17,6 @@ source $testdir/tester.tcl
catch {
sqlite3_fts5_may_be_corrupt 0
append G(perm:dbconfig) "; load_static_extension \$::dbhandle fts5"
reset_db
}
+13 -1
View File
@@ -251,7 +251,6 @@ do_execsql_test 4.3.1 {
INSERT INTO t3 VALUES('a five');
INSERT INTO t3(t3, rank) VALUES('rank', 'bm25()');
}
breakpoint
do_execsql_test 4.3.2 {
SELECT * FROM t3
@@ -260,6 +259,7 @@ do_execsql_test 4.3.2 {
} {
{a four} {a one} {a five} {a two} {a three}
}
do_execsql_test 4.3.3 {
SELECT *, rank FROM t3
WHERE t3 MATCH 'a' AND rank MATCH 'rowidmod(3)'
@@ -268,6 +268,18 @@ do_execsql_test 4.3.3 {
{a three} 0 {a one} 1 {a four} 1 {a two} 2 {a five} 2
}
do_execsql_test 4.3.4 {
SELECT * FROM t3('a', 'rowidmod(4)') ORDER BY rank ASC;
} {
{a four} {a one} {a five} {a two} {a three}
}
do_execsql_test 4.3.5 {
SELECT *, rank FROM t3('a', 'rowidmod(3)') ORDER BY rank ASC
} {
{a three} 0 {a one} 1 {a four} 1 {a two} 2 {a five} 2
}
do_catchsql_test 4.4.3 {
SELECT *, rank FROM t3 WHERE t3 MATCH 'a' AND rank MATCH 'xyz(3)'
} {1 {no such function: xyz}}
-2
View File
@@ -284,8 +284,6 @@ breakpoint
do_faultsim_test 6 -faults oom* -prep {
sqlite_orig db test.db
sqlite3_db_config_lookaside db 0 0 0
} -body {
load_static_extension db fts5
} -test {
faultsim_test_result {0 {}} {1 {initialization of fts5 failed: }}
if {$testrc==0} {
+181
View File
@@ -0,0 +1,181 @@
# 2015 Sep 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.
#
#*************************************************************************
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5onepass
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE ft USING fts5(content);
INSERT INTO ft(rowid, content) VALUES(1, '1 2 3');
INSERT INTO ft(rowid, content) VALUES(2, '4 5 6');
INSERT INTO ft(rowid, content) VALUES(3, '7 8 9');
}
#-------------------------------------------------------------------------
# Check that UPDATE and DELETE statements that feature "WHERE rowid=?" or
# or "WHERE rowid=?" clauses do not use statement journals. But that other
# DELETE and UPDATE statements do.
#
# Note: "MATCH ? AND rowid=?" does use a statement journal.
#
foreach {tn sql uses} {
1.1 { DELETE FROM ft } 1
1.2 { DELETE FROM ft WHERE rowid=? } 0
1.3 { DELETE FROM ft WHERE rowid=? } 0
1.4 { DELETE FROM ft WHERE ft MATCH '1' } 1
1.5 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 1
1.6 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 1
2.1 { UPDATE ft SET content='a b c' } 1
2.2 { UPDATE ft SET content='a b c' WHERE rowid=? } 0
2.3 { UPDATE ft SET content='a b c' WHERE rowid=? } 0
2.4 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' } 1
2.5 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 1
2.6 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 1
} {
do_test 1.$tn { sql_uses_stmt db $sql } $uses
}
#-------------------------------------------------------------------------
# Check that putting a "DELETE/UPDATE ... WHERE rowid=?" statement in a
# trigger program does not prevent the VM from using a statement
# transaction. Even if the calling statement cannot hit a constraint.
#
do_execsql_test 2.0 {
CREATE TABLE t1(x);
CREATE TRIGGER t1_ai AFTER INSERT ON t1 BEGIN
DELETE FROM ft WHERE rowid=new.x;
END;
CREATE TRIGGER t1_ad AFTER DELETE ON t1 BEGIN
UPDATE ft SET content = 'a b c' WHERE rowid=old.x;
END;
CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 BEGIN
DELETE FROM ft WHERE rowid=old.x;
END;
}
foreach {tn sql uses} {
1 { INSERT INTO t1 VALUES(1) } 1
2 { DELETE FROM t1 WHERE x=4 } 1
3 { UPDATE t1 SET x=10 WHERE x=11 } 1
} {
do_test 2.$tn { sql_uses_stmt db $sql } $uses
}
#-------------------------------------------------------------------------
# Test that an "UPDATE ... WHERE rowid=?" works and does not corrupt the
# index when it strikes a constraint. Both inside and outside a
# transaction.
#
foreach {tn tcl1 tcl2} {
1 {} {}
2 {
execsql BEGIN
} {
if {[sqlite3_get_autocommit db]==1} { error "transaction rolled back!" }
execsql COMMIT
}
} {
do_execsql_test 3.$tn.0 {
DROP TABLE IF EXISTS ft2;
CREATE VIRTUAL TABLE ft2 USING fts5(content);
INSERT INTO ft2(rowid, content) VALUES(1, 'a b c');
INSERT INTO ft2(rowid, content) VALUES(2, 'a b d');
INSERT INTO ft2(rowid, content) VALUES(3, 'a b e');
}
eval $tcl1
foreach {tn2 sql content} {
1 { UPDATE ft2 SET rowid=2 WHERE rowid=1 }
{ 1 {a b c} 2 {a b d} 3 {a b e} }
2 {
INSERT INTO ft2(rowid, content) VALUES(4, 'a b f');
UPDATE ft2 SET rowid=5 WHERE rowid=4;
UPDATE ft2 SET rowid=3 WHERE rowid=5;
} { 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} }
3 {
UPDATE ft2 SET rowid=3 WHERE rowid=4; -- matches 0 rows
UPDATE ft2 SET rowid=2 WHERE rowid=3;
} { 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} }
4 {
INSERT INTO ft2(rowid, content) VALUES(4, 'a b g');
UPDATE ft2 SET rowid=-1 WHERE rowid=4;
UPDATE ft2 SET rowid=3 WHERE rowid=-1;
} {-1 {a b g} 1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} }
5 {
DELETE FROM ft2 WHERE rowid=451;
DELETE FROM ft2 WHERE rowid=-1;
UPDATE ft2 SET rowid = 2 WHERE rowid = 1;
} {1 {a b c} 2 {a b d} 3 {a b e} 5 {a b f} }
} {
do_catchsql_test 3.$tn.$tn2.a $sql {1 {constraint failed}}
do_execsql_test 3.$tn.$tn2.b { SELECT rowid, content FROM ft2 } $content
do_execsql_test 3.$tn.$tn2.c {
INSERT INTO ft2(ft2) VALUES('integrity-check');
}
}
eval $tcl2
}
#-------------------------------------------------------------------------
# Check that DELETE and UPDATE operations can be done without flushing
# the in-memory hash table to disk.
#
reset_db
do_execsql_test 4.1.1 {
CREATE VIRTUAL TABLE ttt USING fts5(x);
BEGIN;
INSERT INTO ttt(rowid, x) VALUES(1, 'a b c');
INSERT INTO ttt(rowid, x) VALUES(2, 'a b c');
INSERT INTO ttt(rowid, x) VALUES(3, 'a b c');
COMMIT
}
do_test 4.1.2 { fts5_level_segs ttt } {1}
do_execsql_test 4.2.1 {
BEGIN;
DELETE FROM ttt WHERE rowid=1;
DELETE FROM ttt WHERE rowid=3;
INSERT INTO ttt(rowid, x) VALUES(4, 'd e f');
INSERT INTO ttt(rowid, x) VALUES(5, 'd e f');
COMMIT;
} {}
do_test 4.2.2 { fts5_level_segs ttt } {2}
do_execsql_test 4.3.1 {
BEGIN;
UPDATE ttt SET x = 'd e f' WHERE rowid = 2;
UPDATE ttt SET x = 'A B C' WHERE rowid = 4;
INSERT INTO ttt(rowid, x) VALUES(6, 'd e f');
COMMIT;
} {}
do_test 4.2.2 { fts5_level_segs ttt } {3}
finish_test
+119
View File
@@ -0,0 +1,119 @@
# 2014 Jan 08
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Tests focused on phrase queries.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5phrase
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t3 USING fts5(a, b, c);
INSERT INTO t3 VALUES('d e a', 'd i j j f', 'i j i e b f h'); -- 1
INSERT INTO t3 VALUES('g a e', 'f g i g a', 'h d g i g h c'); -- 2
INSERT INTO t3 VALUES('e a d', 'e i h a f', 'c e h i f b i'); -- 3
INSERT INTO t3 VALUES('a g c', 'd j d j c', 'c d f j i g j'); -- 4
INSERT INTO t3 VALUES('b c b', 'j g c d f', 'j c j d g f b'); -- 5
INSERT INTO t3 VALUES('j a d', 'e b i h h', 'c c f g d i d'); -- 6
INSERT INTO t3 VALUES('a d f', 'h g i i i', 'e a g c i f b'); -- 7
INSERT INTO t3 VALUES('g f d', 'f c g b j', 'b b h h h j j'); -- 8
INSERT INTO t3 VALUES('f h g', 'c j f g j', 'd h d f e b h'); -- 9
INSERT INTO t3 VALUES('f h d', 'c i a d b', 'g b j b a d e'); -- 10
INSERT INTO t3 VALUES('j h h', 'j i h a g', 'd e i e a g j'); -- 11
INSERT INTO t3 VALUES('a b e', 'h g a g c', 'h c a a d e g'); -- 12
INSERT INTO t3 VALUES('a j g', 'i h i f i', 'a g h j g i b'); -- 13
INSERT INTO t3 VALUES('j h e', 'f e d i e', 'i d c f e d c'); -- 14
INSERT INTO t3 VALUES('d j d', 'd b i a c', 'g d h i d b e'); -- 15
INSERT INTO t3 VALUES('h j e', 'e b b c f', 'j a f g h d j'); -- 16
INSERT INTO t3 VALUES('c b j', 'c a b a i', 'h f i d a d c'); -- 17
INSERT INTO t3 VALUES('e e d', 'i d f c c', 'g i d a f e a'); -- 18
INSERT INTO t3 VALUES('e i g', 'e a b i h', 'i f d d a d f'); -- 19
INSERT INTO t3 VALUES('h g f', 'b h h j d', 'i f d e g j a'); -- 20
INSERT INTO t3 VALUES('e h f', 'j c b c f', 'j a j g h a c'); -- 21
INSERT INTO t3 VALUES('d c h', 'b g i c e', 'i i c d e h i'); -- 22
INSERT INTO t3 VALUES('a h i', 'a g d f f', 'e f i i b b h'); -- 23
INSERT INTO t3 VALUES('d d g', 'c c b c g', 'g c h e b c e'); -- 24
INSERT INTO t3 VALUES('a b b', 'b f a d i', 'd a h a b c i'); -- 25
INSERT INTO t3 VALUES('a f d', 'a j e a h', 'j i h j a i f'); -- 26
INSERT INTO t3 VALUES('d j d', 'h a d i a', 'h h f j h g a'); -- 27
INSERT INTO t3 VALUES('g a e', 'd g f a g', 'i d b c g g j'); -- 28
INSERT INTO t3 VALUES('j e h', 'g h j h g', 'd a e j a a h'); -- 29
INSERT INTO t3 VALUES('e j e', 'g e j g c', 'f c e b e e a'); -- 30
INSERT INTO t3 VALUES('h f f', 'i j g e c', 'j j f c a i j'); -- 31
INSERT INTO t3 VALUES('a g c', 'c g d b i', 'g h c b a a f'); -- 32
INSERT INTO t3 VALUES('c h i', 'j d h e e', 'a h i d c c j'); -- 33
INSERT INTO t3 VALUES('d a c', 'e d d b j', 'c e b b h i h'); -- 34
INSERT INTO t3 VALUES('d f h', 'c a f c c', 'j b b c c j f'); -- 35
INSERT INTO t3 VALUES('b g h', 'g c c c f', 'c g c f h e e'); -- 36
INSERT INTO t3 VALUES('f e a', 'b h f j h', 'j g h f d g f'); -- 37
INSERT INTO t3 VALUES('h f a', 'a e i j g', 'f d a f d f c'); -- 38
INSERT INTO t3 VALUES('f i c', 'f i i i i', 'e c f d h j f'); -- 39
INSERT INTO t3 VALUES('h h d', 'd i e d i', 'd f e i a h a'); -- 40
INSERT INTO t3 VALUES('f g c', 'd a f c h', 'b b g j c e g'); -- 41
INSERT INTO t3 VALUES('h i h', 'h d j d e', 'e d b b i e g'); -- 42
INSERT INTO t3 VALUES('b h i', 'j e i d a', 'j j h e e c a'); -- 43
INSERT INTO t3 VALUES('g i g', 'f c c f d', 'a c i c a d a'); -- 44
INSERT INTO t3 VALUES('c c f', 'a b j d b', 'c a e g f e c'); -- 45
INSERT INTO t3 VALUES('d h j', 'g c b j d', 'e a h f h j g'); -- 46
INSERT INTO t3 VALUES('a a d', 'j e j a i', 'i d c f f f b'); -- 47
INSERT INTO t3 VALUES('b g j', 'e c i h f', 'd d h b g a d'); -- 48
INSERT INTO t3 VALUES('c i a', 'a c c c c', 'e h i e h i e'); -- 49
INSERT INTO t3 VALUES('f f c', 'f f b i i', 'f f a j e c i'); -- 50
}
proc pmatch {col expr} {
return [expr {[string first $expr $col]>=0}]
}
db func pmatch pmatch
foreach {tn cols tokens} {
1 a "c c"
2 b "c c"
3 c "c c"
4 {a b c} "c c"
5 {a b c} "b h"
6 {a b} "b h"
7 {a c} "b h"
8 {c a} "b h"
9 {c} "i e"
10 {b} "i e"
11 {a} "i e"
} {
set fts "{$cols}:[join $tokens +]"
set where [list]
foreach c $cols { lappend where "pmatch($c, '$tokens')" }
set where [join $where " OR "]
set res [db eval "SELECT rowid FROM t3 WHERE $where"]
do_execsql_test "1.$tn.$fts->([llength $res] rows)" {
SELECT rowid FROM t3($fts)
} $res
}
do_execsql_test 2.0 {
SELECT rowid,
highlight(t3, 0, '*', '*'),
highlight(t3, 1, '*', '*'),
highlight(t3, 2, '*', '*')
FROM t3('a:f+f')
} {
31 {h *f f*} {i j g e c} {j j f c a i j}
50 {*f f* c} {f f b i i} {f f a j e c i}
}
finish_test
+134
View File
@@ -62,6 +62,140 @@ foreach {tn q res} {
do_execsql_test 2.3.$tn $q $res
}
#-------------------------------------------------------------------------
# Check that prefix queries with:
#
# * a column filter, and
# * no prefix index.
#
# work Ok.
#
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t3 USING fts5(a, b, c);
INSERT INTO t3(t3, rank) VALUES('pgsz', 32);
BEGIN;
INSERT INTO t3 VALUES('acb ccc bba', 'cca bba bca', 'bbc ccc bca'); -- 1
INSERT INTO t3 VALUES('cbb cac cab', 'abb aac bba', 'aab ccc cac'); -- 2
INSERT INTO t3 VALUES('aac bcb aac', 'acb bcb caa', 'aca bab bca'); -- 3
INSERT INTO t3 VALUES('aab ccb ccc', 'aca cba cca', 'aca aac cbb'); -- 4
INSERT INTO t3 VALUES('bac aab bab', 'ccb bac cba', 'acb aba abb'); -- 5
INSERT INTO t3 VALUES('bab abc ccb', 'acb cba abb', 'cbb aaa cab'); -- 6
INSERT INTO t3 VALUES('cbb bbc baa', 'aab aca baa', 'bcc cca aca'); -- 7
INSERT INTO t3 VALUES('abc bba abb', 'cac abc cba', 'acc aac cac'); -- 8
INSERT INTO t3 VALUES('bbc bbc cab', 'bcb ccb cba', 'bcc cac acb'); -- 9
COMMIT;
}
foreach {tn match res} {
1 "a : c*" {1 2 4 6 7 9}
2 "b : c*" {1 3 4 5 6 8 9}
3 "c : c*" {1 2 4 6 7 8 9}
4 "a : b*" {1 3 5 6 7 8 9}
5 "b : b*" {1 2 3 5 7 9}
6 "c : b*" {1 3 7 9}
7 "a : a*" {1 3 4 5 6 8}
8 "b : a*" {2 3 4 6 7 8}
9 "c : a*" {2 3 4 5 6 7 8 9}
} {
do_execsql_test 3.1.$tn {
SELECT rowid FROM t3($match)
} $res
}
do_test 3.2 {
expr srand(0)
execsql { DELETE FROM t3 }
for {set i 0} {$i < 1000} {incr i} {
set a [fts5_rnddoc 3]
set b [fts5_rnddoc 8]
set c [fts5_rnddoc 20]
execsql { INSERT INTO t3 VALUES($a, $b, $c) }
}
execsql { INSERT INTO t3(t3) VALUES('integrity-check') }
} {}
proc gmatch {col pattern} {
expr {[lsearch -glob $col $pattern]>=0}
}
db func gmatch gmatch
proc ghl {col pattern} {
foreach t $col {
if {[string match $pattern $t]} {
lappend res "*$t*"
} else {
lappend res $t
}
}
set res
}
db func ghl ghl
set COLS(a) 0
set COLS(b) 1
set COLS(c) 2
for {set x 0} {$x<2} {incr x} {
foreach {tn pattern} {
1 {xa*}
2 {xb*}
3 {xc*}
4 {xd*}
5 {xe*}
6 {xf*}
7 {xg*}
8 {xh*}
9 {xi*}
10 {xj*}
} {
foreach col {a b c} {
# Check that the list of returned rowids is correct.
#
set res [db eval "SELECT rowid FROM t3 WHERE gmatch($col, '$pattern')"]
set query "$col : $pattern"
do_execsql_test 3.3.$x.$tn.$col.rowid {
SELECT rowid FROM t3($query);
} $res
# Check that the highlight() function works.
#
set res [db eval \
"SELECT ghl($col, '$pattern') FROM t3 WHERE gmatch($col, '$pattern')"
]
set idx $COLS($col)
do_execsql_test 3.3.$x.$tn.$col.highlight {
SELECT highlight(t3, $idx, '*', '*') FROM t3($query);
} $res
}
foreach colset {{a b} {b c} {c a} {a c} {b a}} {
# Check that the list of returned rowids is correct.
#
foreach {col1 col2} $colset {}
set expr "gmatch($col1, '$pattern') OR gmatch($col2, '$pattern')"
set res [db eval "SELECT rowid FROM t3 WHERE $expr"]
set query "{$colset} : $pattern"
do_execsql_test 3.3.$x.$tn.{$colset}.rowid {
SELECT rowid FROM t3($query);
} $res
set resq "SELECT ghl($col1, '$pattern'), ghl($col2, '$pattern')"
append resq " FROM t3 WHERE $expr"
set res [db eval $resq]
set idx1 $COLS($col1)
set idx2 $COLS($col2)
do_execsql_test 3.3.$x.$tn.{$colset}.highlight {
SELECT highlight(t3, $idx1, '*', '*'), highlight(t3, $idx2, '*', '*')
FROM t3($query)
} $res
}
}
execsql { INSERT INTO t3(t3) VALUES('optimize') }
execsql { INSERT INTO t3(t3) VALUES('integrity-check') }
}
finish_test
+118 -3
View File
@@ -19,7 +19,6 @@ ifcapable !fts5 {
return
}
if 1 {
#-------------------------------------------------------------------------
#
set doc "x x [string repeat {y } 50]z z"
@@ -137,8 +136,6 @@ do_execsql_test 5.4 {
SELECT rowid FROM tt WHERE tt MATCH 'a*';
} {1 2}
}
do_execsql_test 5.5 {
DELETE FROM tt;
BEGIN;
@@ -184,6 +181,124 @@ do_catchsql_test 6.3 {
SELECT * FROM xyz WHERE xyz MATCH NULL
} {1 {fts5: syntax error near ""}}
#-------------------------------------------------------------------------
do_execsql_test 7.1 {
CREATE VIRTUAL TABLE ft2 USING fts5(content);
INSERT INTO ft2(rowid, content) VALUES(1, 'a b c');
INSERT INTO ft2(rowid, content) VALUES(2, 'a b d');
}
do_catchsql_test 7.2 {
BEGIN;
UPDATE ft2 SET rowid=2 WHERE rowid=1;
} {1 {constraint failed}}
do_execsql_test 7.3 {
COMMIT;
INSERT INTO ft2(ft2) VALUES('integrity-check');
} {}
do_execsql_test 7.4 {
SELECT * FROM ft2;
} {{a b c} {a b d}}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 8.1 {
CREATE VIRTUAL TABLE ft2 USING fts5(content);
INSERT INTO ft2(rowid, content) VALUES(1, 'a b');
}
do_execsql_test 8.2 {
BEGIN;
INSERT INTO ft2(rowid, content) VALUES(4, 'a x');
}
do_execsql_test 8.3 {
INSERT INTO ft2(ft2) VALUES('integrity-check');
}
#-------------------------------------------------------------------------
# Check that the "table function" syntax works.
#
reset_db
do_execsql_test 9.1 {
CREATE VIRTUAL TABLE ft2 USING fts5(content);
INSERT INTO ft2(rowid, content) VALUES(1, 'a b');
INSERT INTO ft2(rowid, content) VALUES(2, 'a b c d');
INSERT INTO ft2(rowid, content) VALUES(3, 'c d e f');
}
do_execsql_test 9.2 {
SELECT rowid FROM ft2('a');
} {1 2}
do_execsql_test 9.3 {
SELECT rowid FROM ft2('b AND c');
} {2}
#-------------------------------------------------------------------------
#
do_execsql_test 10.0 {
CREATE VIRTUAL TABLE t3 USING fts5(a, b, c);
INSERT INTO t3 VALUES('bac aab bab', 'c bac c', 'acb aba abb'); -- 1
INSERT INTO t3 VALUES('bab abc c', 'acb c abb', 'c aaa c'); -- 2
}
do_execsql_test 10.1 {
SELECT rowid FROM t3('c: c*');
} {2}
do_execsql_test 10.2 {
SELECT rowid FROM t3('b: acb');
} {2}
#-------------------------------------------------------------------------
# Test that character 0x1A is allowed in fts5 barewords.
#
do_test 11.0 {
execsql "CREATE VIRTUAL TABLE t4 USING fts5(x, tokenize=\"ascii tokenchars '\x1A'\")"
execsql "
INSERT INTO t4 VALUES('a b c \x1A');
INSERT INTO t4 VALUES('a b c d\x1A');
INSERT INTO t4 VALUES('a b c \x1Ad');
INSERT INTO t4 VALUES('a b c d');
"
} {}
do_test 11.1 {
execsql "SELECT rowid FROM t4('\x1A')"
} {1}
do_test 11.2 {
execsql "SELECT rowid FROM t4('\x1A*')"
} {1 3}
do_test 11.3 {
execsql "SELECT rowid FROM t4('d\x1A')"
} {2}
do_test 11.4 {
catchsql "SELECT rowid FROM t4('d\x1B')"
} {/fts5: syntax error/}
do_test 11.5 {
catchsql "SELECT rowid FROM t4('d\x19')"
} {/fts5: syntax error/}
#-------------------------------------------------------------------------
#
do_test 12.1 {
execsql {
CREATE VIRTUAL TABLE xx USING fts5(x,y);
BEGIN;
INSERT INTO xx VALUES('1 2 3', 'a b c');
}
} {}
do_execsql_test 12.2 {
SELECT rowid FROM xx('x:a');
COMMIT;
} {}
finish_test
+135
View File
@@ -0,0 +1,135 @@
proc usage {} {
puts stderr "$::argv0 ?OPTIONS? DATABASE FILE1..."
puts stderr ""
puts stderr "Options are"
puts stderr " -fts5"
puts stderr " -fts4"
puts stderr " -colsize <list of column sizes>"
puts stderr {
This script is designed to create fts4/5 tables with more than one column.
The -colsize option should be set to a Tcl list of integer values, one for
each column in the table. Each value is the number of tokens that will be
inserted into the column value for each row. For example, setting the -colsize
option to "5 10" creates an FTS table with 2 columns, with roughly 5 and 10
tokens per row in each, respectively.
Each "FILE" argument should be a text file. The contents of these text files is
split on whitespace characters to form a list of tokens. The first N1 tokens
are used for the first column of the first row, where N1 is the first element
of the -colsize list. The next N2 are used for the second column of the first
row, and so on. Rows are added to the table until the entire list of tokens
is exhausted.
}
exit -1
}
set O(aColsize) [list 10 10 10]
set O(tblname) t1
set O(fts) fts5
set options_with_values {-colsize}
for {set i 0} {$i < [llength $argv]} {incr i} {
set opt [lindex $argv $i]
if {[string range $opt 0 0]!="-"} break
if {[lsearch $options_with_values $opt]>=0} {
incr i
if {$i==[llength $argv]} usage
set val [lindex $argv $i]
}
switch -- $opt {
-colsize {
set O(aColSize) $val
}
-fts4 {
set O(fts) fts4
}
-fts5 {
set O(fts) fts5
}
}
}
if {$i > [llength $argv]-2} usage
set O(db) [lindex $argv $i]
set O(files) [lrange $argv [expr $i+1] end]
foreach {k v} [lrange $argv 0 end-2] {
switch -- $k {
-colsize {
set O(aColSize) $v
}
-colsize {
set O(aColSize) $v
}
}
}
sqlite3 db $O(db)
load_static_extension db fts5
# Create the FTS table in the db. Return a list of the table columns.
#
proc create_table {} {
global O
set cols [list a b c d e f g h i j k l m n o p q r s t u v w x y z]
set nCol [llength $O(aColsize)]
set cols [lrange $cols 0 [expr $nCol-1]]
set sql "CREATE VIRTUAL TABLE IF NOT EXISTS $O(tblname) USING $O(fts) ("
append sql [join $cols ,]
append sql ");"
db eval $sql
return $cols
}
# Return a list of tokens from the named file.
#
proc readfile {file} {
set fd [open $file]
set data [read $fd]
close $fd
split $data
}
# Load all the data into a big list of tokens.
#
set tokens [list]
foreach f $O(files) {
set tokens [concat $tokens [readfile $f]]
}
set N [llength $tokens]
set i 0
set cols [create_table]
set sql "INSERT INTO $O(tblname) VALUES(\$[lindex $cols 0]"
foreach c [lrange $cols 1 end] {
append sql ", \$$c"
}
append sql ")"
db eval BEGIN
while {$i < $N} {
foreach c $cols s $O(aColsize) {
set $c [lrange $tokens $i [expr $i+$s-1]]
incr i $s
}
db eval $sql
}
db eval COMMIT
+6 -8
View File
@@ -7,6 +7,7 @@ set G(src) [string map [list %dir% $srcdir] {
%dir%/fts5.h
%dir%/fts5Int.h
fts5parse.h
fts5parse.c
%dir%/fts5_aux.c
%dir%/fts5_buffer.c
%dir%/fts5_config.c
@@ -19,12 +20,11 @@ set G(src) [string map [list %dir% $srcdir] {
%dir%/fts5_unicode2.c
%dir%/fts5_varint.c
%dir%/fts5_vocab.c
fts5parse.c
}]
set G(hdr) {
#if !defined(SQLITE_TEST) || defined(SQLITE_ENABLE_FTS5)
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
@@ -37,7 +37,7 @@ set G(hdr) {
set G(footer) {
#endif /* !defined(SQLITE_TEST) || defined(SQLITE_ENABLE_FTS5) */
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
}
#-------------------------------------------------------------------------
@@ -87,7 +87,9 @@ proc fts5c_printfile {zIn} {
foreach line [split $data "\n"] {
if {[regexp {^#include.*fts5} $line]} continue
if {[regexp {^(const )?[a-zA-Z][a-zA-Z0-9]* [*]?sqlite3Fts5} $line]} {
if { ![regexp { sqlite3Fts5Init\(} $line]
&& [regexp {^(const )?[a-zA-Z][a-zA-Z0-9]* [*]?sqlite3Fts5} $line]
} {
set line "static $line"
}
set line [string map $sub_map $line]
@@ -107,7 +109,3 @@ proc fts5c_close {} {
fts5c_init fts5.c
foreach f $G(src) { fts5c_printfile $f }
fts5c_close
+59 -15
View File
@@ -21,24 +21,38 @@
** This implementation parses JSON text at 250 MB/s, so it is hard to see
** how JSONB might improve on that.)
*/
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
#if !defined(_SQLITEINT_H_)
#include "sqlite3ext.h"
#endif
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdarg.h>
#define UNUSED_PARAM(X) (void)(X)
#ifndef LARGEST_INT64
# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
#endif
/*
** Versions of isspace(), isalnum() and isdigit() to which it is safe
** to pass signed char values.
*/
#define safe_isdigit(x) isdigit((unsigned char)(x))
#define safe_isalnum(x) isalnum((unsigned char)(x))
#ifdef sqlite3Isdigit
/* Use the SQLite core versions if this routine is part of the
** SQLite amalgamation */
# define safe_isdigit(x) sqlite3Isdigit(x)
# define safe_isalnum(x) sqlite3Isalnum(x)
#else
/* Use the standard library for separate compilation */
#include <ctype.h> /* amalgamator: keep */
# define safe_isdigit(x) isdigit((unsigned char)(x))
# define safe_isalnum(x) isalnum((unsigned char)(x))
#endif
/*
** Growing our own isspace() routine this way is twice as fast as
@@ -46,7 +60,7 @@ SQLITE_EXTENSION_INIT1
** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
*/
static const char jsonIsSpace[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -65,10 +79,13 @@ static const char jsonIsSpace[] = {
};
#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
/* Unsigned integer types */
typedef sqlite3_uint64 u64;
typedef unsigned int u32;
typedef unsigned char u8;
#ifndef SQLITE_AMALGAMATION
/* Unsigned integer types. These are already defined in the sqliteInt.h,
** but the definitions need to be repeated for separate compilation. */
typedef sqlite3_uint64 u64;
typedef unsigned int u32;
typedef unsigned char u8;
#endif
/* Objects */
typedef struct JsonString JsonString;
@@ -477,18 +494,42 @@ static void jsonReturn(
sqlite3_result_int(pCtx, 0);
break;
}
case JSON_REAL: {
double r = strtod(pNode->u.zJContent, 0);
sqlite3_result_double(pCtx, r);
break;
}
case JSON_INT: {
sqlite3_int64 i = 0;
const char *z = pNode->u.zJContent;
if( z[0]=='-' ){ z++; }
while( z[0]>='0' && z[0]<='9' ){ i = i*10 + *(z++) - '0'; }
while( z[0]>='0' && z[0]<='9' ){
unsigned v = *(z++) - '0';
if( i>=LARGEST_INT64/10 ){
if( i>LARGEST_INT64/10 ) goto int_as_real;
if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
if( v==9 ) goto int_as_real;
if( v==8 ){
if( pNode->u.zJContent[0]=='-' ){
sqlite3_result_int64(pCtx, SMALLEST_INT64);
goto int_done;
}else{
goto int_as_real;
}
}
}
i = i*10 + v;
}
if( pNode->u.zJContent[0]=='-' ){ i = -i; }
sqlite3_result_int64(pCtx, i);
int_done:
break;
int_as_real: /* fall through to real */;
}
case JSON_REAL: {
double r;
#ifdef SQLITE_AMALGAMATION
const char *z = pNode->u.zJContent;
sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
#else
r = strtod(pNode->u.zJContent, 0);
#endif
sqlite3_result_double(pCtx, r);
break;
}
case JSON_STRING: {
@@ -858,7 +899,7 @@ static int jsonParseFindParents(JsonParse *pParse){
** Compare the OBJECT label at pNode against zKey,nKey. Return true on
** a match.
*/
static int jsonLabelCompare(JsonNode *pNode, const char *zKey, int nKey){
static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
if( pNode->jnFlags & JNODE_RAW ){
if( pNode->n!=nKey ) return 0;
return strncmp(pNode->u.zJContent, zKey, nKey)==0;
@@ -1995,6 +2036,7 @@ int sqlite3Json1Init(sqlite3 *db){
}
#ifndef SQLITE_CORE
#ifdef _WIN32
__declspec(dllexport)
#endif
@@ -2007,3 +2049,5 @@ int sqlite3_json_init(
(void)pzErrMsg; /* Unused parameter */
return sqlite3Json1Init(db);
}
#endif
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */
+57 -2
View File
@@ -89,6 +89,10 @@
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU)
#include "sqlite3rbu.h"
#if defined(_WIN32_WCE)
#include "windows.h"
#endif
/* Maximum number of prepared UPDATE statements held by this module */
#define SQLITE_RBU_UPDATE_CACHESIZE 16
@@ -2382,6 +2386,30 @@ static void rbuLockDatabase(sqlite3rbu *p){
}
}
#if defined(_WIN32_WCE)
static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
int nChar;
LPWSTR zWideFilename;
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
if( nChar==0 ){
return 0;
}
zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
return 0;
}
memset(zWideFilename, 0, nChar*sizeof(zWideFilename[0]));
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
nChar);
if( nChar==0 ){
sqlite3_free(zWideFilename);
zWideFilename = 0;
}
return zWideFilename;
}
#endif
/*
** The RBU handle is currently in RBU_STAGE_OAL state, with a SHARED lock
** on the database file. This proc moves the *-oal file to the *-wal path,
@@ -2416,10 +2444,37 @@ static void rbuMoveOalFile(sqlite3rbu *p){
rbuObjIterFinalize(&p->objiter);
sqlite3_close(p->dbMain);
sqlite3_close(p->dbRbu);
p->dbMain = 0;
p->dbRbu = 0;
#if defined(_WIN32_WCE)
{
LPWSTR zWideOal;
LPWSTR zWideWal;
zWideOal = rbuWinUtf8ToUnicode(zOal);
if( zWideOal ){
zWideWal = rbuWinUtf8ToUnicode(zWal);
if( zWideWal ){
if( MoveFileW(zWideOal, zWideWal) ){
p->rc = SQLITE_OK;
}else{
p->rc = SQLITE_IOERR;
}
sqlite3_free(zWideWal);
}else{
p->rc = SQLITE_IOERR_NOMEM;
}
sqlite3_free(zWideOal);
}else{
p->rc = SQLITE_IOERR_NOMEM;
}
}
#else
p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
#endif
if( p->rc==SQLITE_OK ){
p->dbMain = 0;
p->dbRbu = 0;
rbuOpenDatabase(p);
rbuSetupCheckpoint(p, 0);
}
+8
View File
@@ -269,6 +269,10 @@
#include "sqlite3.h" /* Required for error code definitions */
#ifdef __cplusplus
extern "C" {
#endif
typedef struct sqlite3rbu sqlite3rbu;
/*
@@ -447,4 +451,8 @@ int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
*/
void sqlite3rbu_destroy_vfs(const char *zName);
#ifdef __cplusplus
} /* end of the 'extern "C"' block */
#endif
#endif /* _SQLITE3RBU_H */
+55
View File
@@ -34,6 +34,11 @@ set testprefix rtree1
#
# rtree-12.*: Test that on-conflict clauses are supported.
# rtree-13.*: Test that bug [d2889096e7bdeac6d] has been fixed.
# rtree-14.*: Test if a non-integer is inserted into the PK column of an
# r-tree table, it is converted to an integer before being
# inserted. Also that if a non-numeric is inserted into one
# of the min/max dimension columns, it is converted to the
# required type before being inserted.
#
ifcapable !rtree {
@@ -535,4 +540,54 @@ do_execsql_test 13.2 {
SELECT * FROM r CROSS JOIN t9 WHERE id=x;
} {1 1 0.0 0.0 2 2 0.0 0.0}
#-------------------------------------------------------------------------
# Test if a non-integer is inserted into the PK column of an r-tree
# table, it is converted to an integer before being inserted. Also
# that if a non-numeric is inserted into one of the min/max dimension
# columns, it is converted to the required type before being inserted.
#
do_execsql_test 14.1 {
CREATE VIRTUAL TABLE t10 USING rtree(ii, x1, x2);
}
do_execsql_test 14.2 {
INSERT INTO t10 VALUES(NULL, 1, 2);
INSERT INTO t10 VALUES(NULL, 2, 3);
INSERT INTO t10 VALUES('4xxx', 3, 4);
INSERT INTO t10 VALUES(5.0, 4, 5);
INSERT INTO t10 VALUES(6.4, 5, 6);
}
do_execsql_test 14.3 {
SELECT * FROM t10;
} {
1 1.0 2.0 2 2.0 3.0 4 3.0 4.0 5 4.0 5.0 6 5.0 6.0
}
do_execsql_test 14.4 {
DELETE FROM t10;
INSERT INTO t10 VALUES(1, 'one', 'two');
INSERT INTO t10 VALUES(2, '52xyz', '81...');
}
do_execsql_test 14.5 {
SELECT * FROM t10;
} {
1 0.0 0.0
2 52.0 81.0
}
do_execsql_test 14.4 {
DROP TABLE t10;
CREATE VIRTUAL TABLE t10 USING rtree_i32(ii, x1, x2);
INSERT INTO t10 VALUES(1, 'one', 'two');
INSERT INTO t10 VALUES(2, '52xyz', '81...');
INSERT INTO t10 VALUES(3, 42.3, 49.9);
}
do_execsql_test 14.5 {
SELECT * FROM t10;
} {
1 0 0
2 52 81
3 42 49
}
finish_test
+37 -26
View File
@@ -12,6 +12,8 @@
# THREADLIB Specify any extra linker options needed to make the library
# thread safe
#
# LIBS Extra libraries options
#
# OPTS Extra compiler command-line options.
#
# EXE The suffix to add to executable files. ".exe" for windows
@@ -48,19 +50,21 @@ TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP)
TCCX += -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3
TCCX += -I$(TOP)/ext/async -I$(TOP)/ext/userauth
TCCX += -I$(TOP)/ext/fts5
THREADLIB += $(LIBS)
# Object files for the SQLite library.
#
LIBOBJ+= vdbe.o parse.o \
alter.o analyze.o attach.o auth.o \
backup.o bitvec.o btmutex.o btree.o build.o \
callback.o complete.o ctime.o date.o dbstat.o delete.o expr.o fault.o fkey.o \
callback.o complete.o ctime.o date.o dbstat.o delete.o expr.o \
fault.o fkey.o \
fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \
fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \
fts3_tokenize_vtab.o \
fts3_unicode.o fts3_unicode2.o \
fts3_write.o func.o global.o hash.o \
icu.o insert.o journal.o legacy.o loadext.o \
fts3_write.o fts5.o func.o global.o hash.o \
icu.o insert.o journal.o json1.o legacy.o loadext.o \
main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \
memjournal.o \
mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \
@@ -225,10 +229,11 @@ SRC += \
SRC += \
$(TOP)/ext/userauth/userauth.c \
$(TOP)/ext/userauth/sqlite3userauth.h
SRC += \
$(TOP)/ext/rbu/sqlite3rbu.c \
$(TOP)/ext/rbu/sqlite3rbu.h
SRC += \
$(TOP)/ext/misc/json1.c
# FTS5 things
@@ -321,7 +326,6 @@ TESTSRC += \
$(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/fuzzer.c \
$(TOP)/ext/misc/ieee754.c \
$(TOP)/ext/misc/json1.c \
$(TOP)/ext/misc/nextchar.c \
$(TOP)/ext/misc/percentile.c \
$(TOP)/ext/misc/regexp.c \
@@ -331,8 +335,7 @@ TESTSRC += \
$(TOP)/ext/misc/wholenumber.c \
$(TOP)/ext/misc/vfslog.c \
$(TOP)/ext/fts5/fts5_tcl.c \
$(TOP)/ext/fts5/fts5_test_mi.c \
fts5.c
$(TOP)/ext/fts5/fts5_test_mi.c
#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
@@ -379,7 +382,7 @@ TESTSRC2 = \
$(TOP)/ext/fts3/fts3_expr.c \
$(TOP)/ext/fts3/fts3_tokenizer.c \
$(TOP)/ext/fts3/fts3_write.c \
$(TOP)/ext/async/sqlite3async.c
$(TOP)/ext/async/sqlite3async.c
# Header files used by all library source files.
#
@@ -451,16 +454,16 @@ FUZZDATA = \
$(TOP)/test/fuzzdata3.db \
$(TOP)/test/fuzzdata4.db
# Extra arguments for including json1 in the build of tools
#
JSON1_DEP = $(TOP)/ext/misc/json1.c sqlite3ext.h
JSON1_OPT = -DSQLITE_SHELL_JSON1 -DSQLITE_CORE
JSON1_SRC = $(TOP)/ext/misc/json1.c
# Standard options to testfixture
#
TESTOPTS = --verbose=file --output=test-out.txt
# Extra compiler options for various shell tools
#
SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
#
@@ -470,24 +473,23 @@ libsqlite3.a: $(LIBOBJ)
$(AR) libsqlite3.a $(LIBOBJ)
$(RANLIB) libsqlite3.a
sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h $(JSON1_DEP)
$(TCCX) $(READLINE_FLAGS) $(JSON1_OPT) -o sqlite3$(EXE) \
$(TOP)/src/shell.c $(JSON1_SRC) \
libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h
$(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \
$(TOP)/src/shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h
$(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \
$(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) $(THREADLIB)
fuzzershell$(EXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h $(JSON1_DEP)
fuzzershell$(EXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h
$(TCCX) -o fuzzershell$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
$(JSON1_OPT) $(TOP)/tool/fuzzershell.c $(JSON1_SRC) sqlite3.c \
$(FUZZERSHELL_OPT) $(TOP)/tool/fuzzershell.c sqlite3.c \
$(TLIBS) $(THREADLIB)
fuzzcheck$(EXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h $(JSON1_DEP)
fuzzcheck$(EXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h
$(TCCX) -o fuzzcheck$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
-DSQLITE_ENABLE_MEMSYS5 $(JSON1_OPT) \
$(TOP)/test/fuzzcheck.c $(JSON1_SRC) sqlite3.c $(TLIBS) $(THREADLIB)
-DSQLITE_ENABLE_MEMSYS5 $(FUZZCHECK_OPT) \
$(TOP)/test/fuzzcheck.c sqlite3.c $(TLIBS) $(THREADLIB)
mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c
$(TCCX) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \
@@ -515,13 +517,14 @@ sqlite3.o: sqlite3.c
# files are automatically generated. This target takes care of
# all that automatic generation.
#
target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl
target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl fts5.c
rm -rf tsrc
mkdir tsrc
cp -f $(SRC) tsrc
rm tsrc/sqlite.h.in tsrc/parse.y
tclsh $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new
mv vdbe.new tsrc/vdbe.c
cp fts5.c fts5.h tsrc
touch target_source
sqlite3.c: target_source $(TOP)/tool/mksqlite3c.tcl
@@ -668,9 +671,17 @@ fts3_unicode2.o: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR)
fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c
fts5.o: fts5.c
$(TCCX) -DSQLITE_CORE -c fts5.c
json1.o: $(TOP)/ext/misc/json1.c
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c
rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c
fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
cp $(TOP)/ext/fts5/fts5parse.y .
rm -f fts5parse.h
@@ -717,9 +728,9 @@ testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
$(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \
-o testfixture$(EXE) $(LIBTCL) libsqlite3.a $(THREADLIB)
amalgamation-testfixture$(EXE): sqlite3.c fts5.c $(TESTSRC) $(TOP)/src/tclsqlite.c
amalgamation-testfixture$(EXE): sqlite3.c $(TESTSRC) $(TOP)/src/tclsqlite.c
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
$(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts5.c \
$(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c \
-o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c
+86 -82
View File
@@ -1,24 +1,24 @@
C Remove\sdead\scode,\sreplacing\swith\sassert()\sstatements\sthat\smake\ssure\sthe\ncode\sreally\swas\sdead.
D 2015-09-29T15:50:04.571
C Version\s3.9.2
D 2015-11-02T18:31:45.544
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2143eeef6d0cc26006ae5fc4bb242a4a8b973412
F Makefile.in f0088ff0d2ac949fce6de7c00f13a99ac5bdb663
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc b9054642ab305be4174d8b0433c9951c2839701d
F Makefile.msc 0ed934b4ae6a5ec0b9d7e770104864f8372414ab
F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
F VERSION ccfc4d1576dbfdeece0a4372a2e6a2e37d3e7975
F VERSION 36a3ce894ac495d8cb9006319eced49e72998587
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
F autoconf/Makefile.am 27de1af382c82e81f1fe36a7f38528fba004eb1a
F autoconf/Makefile.am bd4a90972aa87f079af6624ddea3df3d58f26d2f
F autoconf/README 14458f1046c118efa721aadec5f227e876d3cd38
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
F autoconf/config.guess 94cc57e2a3fdb9c235b362ace86d77e89d188cad x
F autoconf/config.sub 1efb390a8fb4bfafd74783a15a8fb5311c84300e x
F autoconf/configure.ac ba3e99ba1a8171d0682b68443517088fc5d6f13a
F autoconf/configure.ac a1fe4eee429fd9d3170be41941514a2b7120ba4e
F autoconf/depcomp 0b26f101e3bc9fd1ff0be1da9fb4a82371142f92 x
F autoconf/install-sh 06ee6336e63bb845c8439d777c32eb2eccc4fbf1 x
F autoconf/ltmain.sh 7a658a24028f02331c1d2446562758083c5eadd1
@@ -38,8 +38,8 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
F config.h.in 42b71ad3fe21c9e88fa59e8458ca1a6bc72eb0c0
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
F configure 2f61915a1bdfbc589244334401cf97d3401e6a39 x
F configure.ac 713de38000413e469188db2cb85bed759b56f322
F configure f0b449016511057506dae6a525433b004df9cc4c x
F configure.ac 1e87304e51af110950c48a1eea6ffc7a577f600e
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
@@ -82,7 +82,7 @@ F ext/fts3/fts3.c e028eb13432f108d2e22cded019fc980700e4e00
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h c84125c666ee54cef6efce6ff64abb0d0e2f4535
F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
F ext/fts3/fts3_expr.c 71c063da9c2a4167fb54aec089dd5ef33a58c9cb
F ext/fts3/fts3_expr.c dfd571a24412779ac01f25c01d888c6ef7b2d0ef
F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
F ext/fts3/fts3_icu.c deb46f7020d87ea7a14a433fb7a7f4bef42a9652
@@ -96,7 +96,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
F ext/fts3/fts3_unicode.c a93f5edc0aff44ef8b06d7cb55b52026541ca145
F ext/fts3/fts3_unicode2.c c3d01968d497bd7001e7dc774ba75b372738c057
F ext/fts3/fts3_write.c 6f7233a06df17084d5cd968899053731bf953f94
F ext/fts3/fts3_write.c f442223e4a1914dc1fc12b65af7e4f2c255fa47c
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
F ext/fts3/tool/fts3view.c 8e53d0190a7b3443764bbd32ad47be2bd852026d
@@ -105,25 +105,25 @@ F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl 95cf7ec186e48d4985e433ff8a1c89090a774252
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
F ext/fts5/fts5.h 98f802fe41481f9d797fce496f0fefcad72c7782
F ext/fts5/fts5Int.h 666aba8432940a8449a3bd4636e898fe906ed95d
F ext/fts5/fts5_aux.c 7a307760a9c57c750d043188ec0bad59f5b5ec7e
F ext/fts5/fts5_buffer.c 64dcaf36a3ebda9e84b7c3b8788887ec325e12a4
F ext/fts5/fts5.h 8b9a13b309b180e9fb88ea5666c0d8d73c6102d9
F ext/fts5/fts5Int.h 38667e39859ff3f3bc91f47efe672023a145a118
F ext/fts5/fts5_aux.c b09aa27dcdaa3d50a30be433fddaa48a50aa827b
F ext/fts5/fts5_buffer.c e99224a316cc5b2c574ccccdc7f2344bca54784d
F ext/fts5/fts5_config.c 57ee5fe71578cb494574fc0e6e51acb9a22a8695
F ext/fts5/fts5_expr.c 667faaf14a69a5683ac383acdc8d942cf32c3f93
F ext/fts5/fts5_expr.c bc31478fd04de55150031f6e6a652939d3e335ac
F ext/fts5/fts5_hash.c 4bf4b99708848357b8a2b5819e509eb6d3df9246
F ext/fts5/fts5_index.c 4fdbc0a321e3a1d73741a623d7aea4db78d6a86d
F ext/fts5/fts5_main.c 53116cffeb26898832ff7700cc5ebac5fe085d32
F ext/fts5/fts5_storage.c 120f7b143688b5b7710dacbd48cff211609b8059
F ext/fts5/fts5_tcl.c 6da58d6e8f42a93c4486b5ba9b187a7f995dee37
F ext/fts5/fts5_index.c f73968357818455039ecb79dcd4b082c3baaeaeb
F ext/fts5/fts5_main.c bf43550b8e9a68514abd179500f1917a2256cd7a
F ext/fts5/fts5_storage.c df061a5caf9e50fbbd43113009b5b248362f4995
F ext/fts5/fts5_tcl.c 3bf445e66de32137d4693694ff7b1fd6074e32bd
F ext/fts5/fts5_test_mi.c e96be827aa8f571031e65e481251dc1981d608bf
F ext/fts5/fts5_tokenize.c f380f46f341af9c9a9908e1aade685ba1eaa157a
F ext/fts5/fts5_unicode2.c 78273fbd588d1d9bd0a7e4e0ccc9207348bae33c
F ext/fts5/fts5_varint.c 3f86ce09cab152e3d45490d7586b7ed2e40c13f1
F ext/fts5/fts5_vocab.c 4622e0b7d84a488a1585aaa56eb214ee67a988bc
F ext/fts5/fts5parse.y 833db1101b78c0c47686ab1b84918e38c36e9452
F ext/fts5/fts5_vocab.c a05027ab6abb692ad27654c85137a4f1061a159e
F ext/fts5/fts5parse.y e83dca6028e3309178d05b5bd920e372dc295d35
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
F ext/fts5/test/fts5_common.tcl b6e6a40ef5d069c8e86ca4fbad491e1195485dbc
F ext/fts5/test/fts5_common.tcl 51f7ef3af444b89c6f6ce3896a0ac349ff4e996d
F ext/fts5/test/fts5aa.test 4804f237005bb4ba8ea4a76120d8011ebcb5d611
F ext/fts5/test/fts5ab.test 6fe3a56731d15978afbb74ae51b355fc9310f2ad
F ext/fts5/test/fts5ac.test 9737992d08c56bfd4803e933744d2d764e23795c
@@ -135,7 +135,7 @@ F ext/fts5/test/fts5ah.test e592c4978622dbc4de552cd0f9395df60ac5d54c
F ext/fts5/test/fts5ai.test f20e53bbf0c55bc596f1fd47f2740dae028b8f37
F ext/fts5/test/fts5aj.test 05b569f5c16ea3098fb1984eec5cf50dbdaae5d8
F ext/fts5/test/fts5ak.test 7b8c5df96df599293f920b7e5521ebc79f647592
F ext/fts5/test/fts5al.test 5c79525671862861906fa0a848da462a8473eafb
F ext/fts5/test/fts5al.test a1b7b6393376bc2adc216527a28f5ae5594069df
F ext/fts5/test/fts5alter.test 6022c61467a82aa11c70822ccad22b328dcf0d04
F ext/fts5/test/fts5auto.test caa5bcf917db11944655a2a9bd38c67c520376ca
F ext/fts5/test/fts5aux.test 8c687c948cc98e9a94be014df7d518acc1b3b74f
@@ -156,7 +156,7 @@ F ext/fts5/test/fts5fault2.test 28c36c843bb39ae855ba79827417ecc37f114341
F ext/fts5/test/fts5fault3.test d6e9577d4312e331a913c72931bf131704efc8f3
F ext/fts5/test/fts5fault4.test 762991d526ee67c2b374351a17248097ea38bee7
F ext/fts5/test/fts5fault5.test 54da9fd4c3434a1d4f6abdcb6469299d91cf5875
F ext/fts5/test/fts5fault6.test 97bce1a36b7a64e3203fea504ae8e5cfd5ada423
F ext/fts5/test/fts5fault6.test 9682664d679643ac6736e90c225526cc84073cda
F ext/fts5/test/fts5fault7.test f62ed4d98f137eb03f1db94d1fa41b17a771d971
F ext/fts5/test/fts5full.test 6f6143af0c6700501d9fd597189dfab1555bb741
F ext/fts5/test/fts5hash.test 42eb066f667e9a389a63437cb7038c51974d4fc6
@@ -164,16 +164,18 @@ F ext/fts5/test/fts5integrity.test 29f41d2c7126c6122fbb5d54e556506456876145
F ext/fts5/test/fts5matchinfo.test 2163b0013e824bba65499da9e34ea4da41349cc2
F ext/fts5/test/fts5merge.test 8f3cdba2ec9c5e7e568246e81b700ad37f764367
F ext/fts5/test/fts5near.test b214cddb1c1f1bddf45c75af768f20145f7e71cc
F ext/fts5/test/fts5onepass.test 7ed9608e258132cb8d55e7c479b08676ad68810c
F ext/fts5/test/fts5optimize.test 42741e7c085ee0a1276140a752d4407d97c2c9f5
F ext/fts5/test/fts5phrase.test f6d1d464da5beb25dc56277aa4f1d6102f0d9a2f
F ext/fts5/test/fts5plan.test 6a55ecbac9890765b0e16f8c421c7e0888cfe436
F ext/fts5/test/fts5porter.test 7cdc07bef301d70eebbfa75dcaf45c3680e1d0e1
F ext/fts5/test/fts5porter2.test 2e65633d58a1c525d5af0f6c01e5a59155bb3487
F ext/fts5/test/fts5prefix.test 552a462f0e8595676611f41643de217fb4ac2808
F ext/fts5/test/fts5prefix.test ad3069f099ff593a2196422244fa218f8942dfb9
F ext/fts5/test/fts5rank.test 11dcebba31d822f7e99685b4ea2c2ae3ec0b16f1
F ext/fts5/test/fts5rebuild.test 03935f617ace91ed23a6099c7c74d905227ff29b
F ext/fts5/test/fts5restart.test c17728fdea26e7d0f617d22ad5b4b2862b994c17
F ext/fts5/test/fts5rowid.test 400384798349d658eaf06aefa1e364957d5d4821
F ext/fts5/test/fts5simple.test 967b7144644ad4b40b2526160a5adfa896864c55
F ext/fts5/test/fts5simple.test f8463172dc2d4bf9f74c78e9df9c83e942c63a94
F ext/fts5/test/fts5synonym.test cf88c0a56d5ea9591e3939ef1f6e294f7f2d0671
F ext/fts5/test/fts5tokenizer.test ea4df698b35cc427ebf2ba22829d0e28386d8c89
F ext/fts5/test/fts5unicode.test fbef8d8a3b4b88470536cc57604a82ca52e51841
@@ -182,8 +184,9 @@ F ext/fts5/test/fts5unicode3.test 35c3d02aa7acf7d43d8de3bfe32c15ba96e8928e
F ext/fts5/test/fts5unindexed.test e9539d5b78c677315e7ed8ea911d4fd25437c680
F ext/fts5/test/fts5version.test 978f59541d8cef7e8591f8be2115ec5ccb863e2e
F ext/fts5/test/fts5vocab.test cdf97b9678484e9bad5062edf9c9106e5c3b0c5c
F ext/fts5/tool/fts5txt2db.tcl 3d19fb8ffb234031d33d7d2151acfbc55e9cfcc4
F ext/fts5/tool/loadfts5.tcl 58e90407cc5c2b1770460119488fd7c0090d4dd3
F ext/fts5/tool/mkfts5c.tcl 5745072c7de346e18c7f491e4c3281fe8a1cfe51
F ext/fts5/tool/mkfts5c.tcl 09ce6a7997440508360f5ba1651ab7e923a8bf31
F ext/fts5/tool/showfts5.tcl 9eaf6c3df352f98a2ab5ce1921dd94128ab1381d
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
F ext/icu/icu.c b2732aef0b076e4276d9b39b5a33cec7a05e1413
@@ -195,7 +198,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
F ext/misc/fuzzer.c 4c84635c71c26cfa7c2e5848cf49fe2d2cfcd767
F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e
F ext/misc/json1.c 263cac0292302b7cf7ecb2e8bd698a50d1aedecc
F ext/misc/json1.c 4f45afd9dbcd6feca8c528251efbb7fc09299a09
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
@@ -229,13 +232,13 @@ F ext/rbu/rbufault.test cc0be8d5d392d98b0c2d6a51be377ea989250a89
F ext/rbu/rbufault2.test 9a7f19edd6ea35c4c9f807d8a3db0a03a5670c06
F ext/rbu/rbufts.test 828cd689da825f0a7b7c53ffc1f6f7fdb6fa5bda
F ext/rbu/rbusave.test 0f43b6686084f426ddd040b878426452fd2c2f48
F ext/rbu/sqlite3rbu.c 4ba82bd850aa012f73c31dd242d570f18c9cc35a
F ext/rbu/sqlite3rbu.h 5357f070cd8c0bcad459b620651ec1656859e4d0
F ext/rbu/sqlite3rbu.c ea47de615e911b3a69a8e7fb3be3866298403a25
F ext/rbu/sqlite3rbu.h 1d568cb33738d7900975cc5c72e6f68049f15914
F ext/rbu/test_rbu.c 2a3652241fa45d5eaa141775e4ae68c1d3582c03
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c 0f9b595bd0debcbedf1d7a63d0e0678d619e6c9c
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test 541bbcab74613907fea08b2ecdcdd5b7aa724cc9
F ext/rtree/rtree1.test 96a80c08440c932cd72aac50660e7af2612d2cda
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc
F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
@@ -261,7 +264,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
F main.mk 151fcaba704fdeeb0a1941857ef6e1d6216732d8
F main.mk 645d30a780fb304cf7fa79537b78728e32dd46fc
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
F mkopcodeh.awk 0e7f04a8eb90f92259e47d80110e4e98d7ce337a
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
@@ -275,37 +278,37 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 4911e1f18fc11b60edbc6410643e938762969a6a
F src/alter.c 9d649e46c780166e416fb11dbd23f8d49aab8267
F src/analyze.c 4c308880cf53c558070cb8513bdff4ffb1a38a77
F src/attach.c e944d0052b577703b9b83aac1638452ff42a8395
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c c3a9c4209439b806c44cf30daf466955727bf46c
F src/bitvec.c d1f21d7d91690747881f03940584f4cc548c9d3d
F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
F src/btree.c 164583151135a3764672c2c25aa8e4fa06bdb12b
F src/btree.c 0b74bc28b2dc907cba03b5b4b3b81584273be699
F src/btree.h 40189aefdc2b830d25c8b58fd7d56538481bfdd7
F src/btreeInt.h 8177c9ab90d772d6d2c6c517e05bed774b7c92c0
F src/build.c 361f58b73aad7804f5706bf62d210bd9cd608041
F src/build.c ca574d33ffb1763cfd2979383f4d507095bfbe19
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f
F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b
F src/ctime.c 509ef9c64d1321f42448f111da86400b1799218a
F src/date.c fb1c99172017dcc8e237339132c91a21a0788584
F src/dbstat.c e637e7a7ff40ef32132a418c6fdf1cfb63aa27c7
F src/delete.c 46bb5e217f83af68574ccb613421485578c41ba8
F src/expr.c 3a76afcdac925294c39903b7002ddb9e5fd29863
F src/delete.c 35c939eb8bacc9dd8a6715964e5f69feb8c20e44
F src/expr.c b89dfbb8a385a45411c487355597c01f4ea4c882
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 83e1baba999bed3144ea5a2143fc922edf51135f
F src/fkey.c 31900763094a3736a5fc887469202eb579fef2d0
F src/func.c ecdd69ec6a1e406f04cc73324be2ebbf6354197f
F src/global.c 508e4087f7b41d688e4762dcf4d4fe28cfbc87f9
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c 81d6bf397c05b4e8ddc4af2ff6637c113ee7e37a
F src/insert.c 3c522beb5bf50a2efee1fca1e80fd40942e5817c
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
F src/lempar.c d344a95d60c24e2f490ee59db9784b1b17439012
F src/loadext.c f0b66d28e377fd6c6d36cc9d92df1ff251ebee44
F src/main.c c80ea19ec71609ccbec21f334fbcf475bb6af2fc
F src/loadext.c c5916a158f1fb74d955847c84f7ebdb6f5de9d8c
F src/main.c fec97668771438033a7559883401067b139729e1
F src/malloc.c 3a37ce6979a40f499d8cea9e9ab4e8517854d35d
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987
@@ -318,7 +321,7 @@ F src/mutex.c 8e45800ee78e0cd1f1f3fe8e398853307f4a085c
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
F src/mutex_unix.c a94b46f3f7beba307dde1b298b0f99f9c3677a93
F src/mutex_w32.c b483d3e5914b84c82516a6a9919582f12ef3b838
F src/mutex_w32.c 5e6fe1c298fb5a8a15aaed4161d5759311431c17
F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8
F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf
@@ -333,24 +336,24 @@ F src/parse.y f599aa5e871a493330d567ced93de696f61f48f7
F src/pcache.c 24be750c79272e0ca7b6e007bc94999700f3e5ef
F src/pcache.h 9968603796240cdf83da7e7bef76edf90619cea9
F src/pcache1.c e822007159d53a7ea7aa040d6e28964ddb6de083
F src/pragma.c 577f70c3899ee6fc2e5a4c37158c69c1c23f71e7
F src/pragma.c dcfe3a35d2de935feeaba1455528b4a5c4f1208c
F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a
F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1
F src/printf.c 0c4bcdd1c2e2521024f0a69cb5eb334f86b3652a
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c 1954a0f01bf65d78d7d559aea3d5c67f33376d91
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
F src/select.c e49f4af9748c9e0cc1bf864b4190aa94841c8409
F src/shell.c a11b20da4c6630e0e8f83c47ce36f717dd0422f0
F src/sqlite.h.in 4b76d74d69af48c534c58fb723137dc6944bdedc
F src/select.c 0bc9cd2e1cacfdc9cdc9a83884cc100f166e80a4
F src/shell.c d25df04168d6ba5a4fa05bdbf859df667f9eb621
F src/sqlite.h.in dc35357824c6bb84a04acd4e99dee3e07299a8c6
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h 64350bf36833a56ad675e27392a913f417c5c308
F src/sqliteInt.h b6516bb2727876348b4e05aadd12237797626270
F src/sqlite3ext.h 4b66e3e3435da4b4c8c83696d0349f0c503b3924
F src/sqliteInt.h e21cc96bc24161df7373f6b24367cf580496889d
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
F src/tclsqlite.c d9439b6a910985b7fff43ba6756bcef00de22649
F src/test1.c c96508c835979bf15dc0e3146e2c7a51a2333d3c
F src/test1.c 8fff9c5aa63d6490f516d018b70c12a9cb9a4d8a
F src/test2.c 577961fe48961b2f2e5c8b56ee50c3f459d3359d
F src/test3.c 64d2afdd68feac1bb5e2ffb8226c8c639f798622
F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e
@@ -364,7 +367,7 @@ F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
F src/test_backup.c 2e6e6a081870150f20c526a2e9d0d29cda47d803
F src/test_blob.c e5a7a81d61a780da79101aeb1e60d300af169e07
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
F src/test_config.c fb2e5d354d9a077f5fbb261652eff4787deb104f
F src/test_config.c ada6f38b0acb6722fb7f0ed8c54fd66df41085b9
F src/test_demovfs.c 0de72c2c89551629f58486fde5734b7d90758852
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
@@ -399,28 +402,28 @@ F src/threads.c bbfb74450643cb5372a43ad4f6cffd7e9dfcecb0
F src/tokenize.c 83c6ed569423a3af83a83973b444cf7123be33a6
F src/treeview.c 154f0acc622fa3514de8777dcedf4c8a8802b4ce
F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f
F src/update.c d8f0afe1a1c66b97cbd87e5236f4e71d35ab4840
F src/update.c dc37664095ca8604293ff1de2d9a547c6efb5e6e
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
F src/util.c fc612367108b74573c5fd13a85d0a23027f438bd
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
F src/vdbe.c 5048103aa6bc9c01bf1a4620729256d1e873bb6c
F src/vdbe.c 1e0bf8d6a2308ce916d444ef399921407fd5d972
F src/vdbe.h 4bc88bd0e06f8046ee6ab7487c0015e85ad949ad
F src/vdbeInt.h 8b867eac234e28627ffcace3cd4b4b79bbec664b
F src/vdbeapi.c 020681b943e77766b32ae1cddf86d7831b7374ca
F src/vdbeaux.c fd00b489ab3f44f2dca1e4344faf289b7bfcf649
F src/vdbeblob.c 1d7b97115e7bbac4c318db416d2ca83fc779544a
F src/vdbeblob.c 565fabd302f5fca3bdf3d56cac330483616a39b6
F src/vdbemem.c 19b3036aa4d676e7103b0fb5efd6327da455f915
F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b
F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0
F src/vtab.c 2ecfe020c10e0a0c7b078203fdba2fae844744bc
F src/vtab.c 2a8b44aa372c33f6154208e7a7f6c44254549806
F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
F src/wal.c 18b0ed49830cf04fe2d68224b41838a73ac6cd24
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba
F src/where.c b7f928b6b8ce091f385ba5ac2394928608431550
F src/where.c e3724b7b31d1e13869308ed4125305364f7d823a
F src/whereInt.h 7892bb54cf9ca0ae5c7e6094491b94c9286dc647
F src/wherecode.c a87238178f8c300fd27afec54326ea8d0a18baa2
F src/whereexpr.c 2473e4350e30f9b55d1c6a8f66ca23c689f23f1d
F src/wherecode.c cdfff200d065e7fb1af827b3274ed46b10a91d65
F src/whereexpr.c e63244ca06c503e5f3c5b7f3c9aea0db826089ed
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -467,7 +470,7 @@ F test/autoindex1.test 14b63a9f1e405fe6d5bfc8c8d00249c2ebaf13ea
F test/autoindex2.test af7e595c6864cc6ef5fc38d5db579a3e34940cb8
F test/autoindex3.test a3be0d1a53a7d2edff208a5e442312957047e972
F test/autoindex4.test 49d3cd791a9baa16fb461d7ea3de80d019a819cf
F test/autoindex5.test 6f487290ce2a667c24517191651bfb8c7d86b6dc
F test/autoindex5.test 96f084a5e6024ea07cace5888df3223f3ea86990
F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
@@ -621,7 +624,7 @@ F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7
F test/filectrl.test 7c13f96457435238da99aff7343ad6a3a4885787
F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146
F test/fkey1.test de5b287f6a480b36bd51e8debcf48168e26e4ed2
F test/fkey1.test 13e3d48236a2b9f5c5ebd232eef9b3ab682a8a2c
F test/fkey2.test f3d27ecba480a348c328965d154214719bb158a9
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
@@ -690,7 +693,7 @@ F test/fts3aux2.test 7ae2b2c13aefdf4169279a27a5f51780ce57f6ba
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
F test/fts3conf.test 92bc4cc67f948b2f53f73c8ab0ebf4be9eee92aa
F test/fts3conf.test ff90127b2462c788348c0dd7f6f8c573ef9cb5d9
F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
@@ -702,7 +705,7 @@ F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
F test/fts3expr.test 3401d47b229c4504424caf362cc4ff704cad4162
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
F test/fts3expr3.test 9e91b8edbcb197bf2e92161aa7696446d96dce5f
F test/fts3expr3.test c4d4a7d6327418428c96e0a3a1137c251b8dfbf8
F test/fts3expr4.test e1be1248566f43c252d4404d52914f1fc4bfa065
F test/fts3expr5.test f9abfffbf5e53d48a33e12a1e8f8ba2c551c9b49
F test/fts3fault.test da49627b280b210ebc6657f76344c7851f10ce66
@@ -750,10 +753,10 @@ F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
F test/fuzz3.test 53fabcd5f0f430f8b221282f6c12c4d0903c21eb
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
F test/fuzzcheck.c b8eb7ee40f6d28548a0b028e0676293522f3427f
F test/fuzzcheck.c c84086021a514360268190a1bc6ae8ed78d7c94f
F test/fuzzdata1.db 7ee3227bad0e7ccdeb08a9e6822916777073c664
F test/fuzzdata2.db f03a420d3b822cc82e4f894ca957618fbe9c4973
F test/fuzzdata3.db 1d6044c33a114007f02b6e6846f1fa232f607bfd
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
F test/fuzzdata4.db 1882f0055fb63214d8407ddc7aca9b0b1c59af21
F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
@@ -780,7 +783,7 @@ F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a
F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635
F test/index.test fe3c7a1aad82af92623747e9c3f3aa94ccd51238
F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407
F test/index3.test fa3e49bbaa4f38091c9c742e36a1abe67c4ef1fc
F test/index3.test 81bc47890b8abfb181bc35f8d10b56c069803386
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
F test/index6.test 7102ec371414c42dfb1d5ca37eb4519aa9edc23a
@@ -817,8 +820,8 @@ F test/journal3.test ff8af941f9e06161d3db1b46bb9f965ff0e7f307
F test/jrnlmode.test 7864d59cf7f6e552b9b99ba0f38acd167edc10fa
F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
F test/json101.test e8b50fbcdbf283cfafbc42632bf2c7dfa4541c46
F test/json102.test 796b1c59894c6e0f38fc1a3acb0e690573b952a3
F test/json101.test 83e6ebfb3cef6329853ab854403ec82b1787b537
F test/json102.test bf3fe7a706d30936a76a0f7a0375e1e8e73aff5a
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
@@ -898,6 +901,7 @@ F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
F test/notnull.test f8fcf58669ddba79274daa2770d61dfad8274f62
F test/null.test 0dcce4f04284ec66108c503327ad6d224c0752b3
F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1
F test/offset1.test f06b83657bcf26f9ce805e67450e189e282143b2
F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
F test/orderby1.test 870e150450437d3980badbde3d0166b81d9e33f6
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
@@ -943,7 +947,7 @@ F test/rbu.test 168573d353cd0fd10196b87b0caa322c144ef736
F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8
F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.tcl afdac5c3429dceb034295617c0a51df9954d467a
F test/releasetest.tcl 67a82199e6ddee609211488bc04ed3f9ea3aa28a
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea
F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14
@@ -1029,7 +1033,7 @@ F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
F test/speedtest1.c 857439869d1cb4db35e1c720ee9c2756eb9ea2a0
F test/spellfix.test 0597065ff57042df1f138e6a2611ae19c2698135
F test/spellfix2.test 1ff48bb65b6198d21674ae24d19bb136e547585a
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/sqldiff1.test 8f6bc7c6a5b3585d350d779c6078869ba402f8f5
F test/sqllimits1.test 89b3d5aad05b99f707ee3786bdd4416dccf83304
F test/stat.test 8de91498c99f5298b303f70f1d1f3b9557af91bf
@@ -1044,7 +1048,7 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
F test/tabfunc01.test 83e63be7b6e3f67b6a03519c9c61bc68efb25f31
F test/tabfunc01.test 03c4ad422c6ab596cff6dcaf86dd061a9f039525
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
@@ -1240,7 +1244,7 @@ F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2
F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825
F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8
F test/update.test 6c68446b8a0a33d522a7c72b320934596a2d7d32
F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b
F test/uri.test 6630ecbdea2aac10df3c89dbae2243f4c2c353e4
F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
@@ -1249,7 +1253,7 @@ F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
F test/view.test 0d8935e64867ae01492347884f5cbb47f056f4c8
F test/view.test f6c3a39e0c819891265e1d0754e99960d81ef6c9
F test/vtab1.test 6210e076997f176bedc300a87ad6404651b601dd
F test/vtab2.test f8cd1bb9aba7143eba97812d9617880a36d247ad
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
@@ -1336,11 +1340,10 @@ F test/zerodamage.test cf6748bad89553cc1632be51a6f54e487e4039ac
F tool/build-all-msvc.bat 761d8c82a1a529261291812732a853a1b4256d85 x
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
F tool/fuzzershell.c 87cc3d6f00239d786d231954289f106131989cc7
F tool/fuzzershell.c b36096cdbcb4af985a2d6c20093d61e55b49bfe1
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
@@ -1354,13 +1357,12 @@ F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkpragmatab.tcl 84af2b180484323a2ea22a2279e8bd9e3e1e492e
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 87240b09c20042999b41d5fabe091b7111287835
F tool/mksqlite3c.tcl 421ecbd437d8cd7123e67430ee8146218396680d
F tool/mksqlite3h.tcl 44730d586c9031638cdd2eb443b801c0d2dbd9f8
F tool/mksqlite3c.tcl b66b4170f693602cd6985aed15d9509fe2f18c84
F tool/mksqlite3h.tcl 1d41ab59bffb025121f75b76e183125ce41b3ec8
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
F tool/mkvsix.tcl bbe57cd9ae11c6cc70319241101ef8d2b8c3765b
F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091
F tool/omittest.tcl 34d7ac01fe4fd18e3637f64abe12c40eca0f6b97
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
@@ -1370,7 +1372,6 @@ F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68
F tool/showstat4.c 9515faa8ec176599d4a8288293ba8ec61f7b728a
F tool/showwal.c 85cb36d4fe3e93e2fbd63e786e0d1ce42d0c4fad
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b
F tool/spaceanal.tcl 93c1fdc9733c525b17a2024c7df193daa002e037
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
@@ -1389,7 +1390,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 59662cd2b65255a30e1a420331c07c51b644621a
R cec1f3888d085a601a5cfb22d1afd716
P c0c4b6b39648be9aa9b1e218e6d281ab17812536
R 56b278dd241b099a55f2d39b092fbea8
T +bgcolor * #d0c0ff
T +sym-release *
T +sym-version-3.9.2 *
U drh
Z 0ae71f6c4f92a526967039eb67c1881e
Z ea2f853532ec0d2d6055c0d00a95dc82
+1 -1
View File
@@ -1 +1 @@
0e317dda5dfd35b742afd70dacb5bfb39aa3fc4a
bda77dda9697c463c3d0704014d51627fceee328
+3 -3
View File
@@ -602,14 +602,14 @@ void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){
if( ALWAYS(v) ){
int r1 = sqlite3GetTempReg(pParse);
int r2 = sqlite3GetTempReg(pParse);
int j1;
int addr1;
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
sqlite3VdbeUsesBtree(v, iDb);
sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2);
j1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
addr1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2);
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, r2);
}
+9 -3
View File
@@ -661,7 +661,7 @@ static int saveCursorPosition(BtCursor *pCur){
pCur->eState = CURSOR_REQUIRESEEK;
}
invalidateOverflowCache(pCur);
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl|BTCF_AtLast);
return rc;
}
@@ -6499,7 +6499,13 @@ static int pageInsertArray(
if( pData<pBegin ) return 1;
pSlot = pData;
}
memcpy(pSlot, pCArray->apCell[i], sz);
/* pSlot and pCArray->apCell[i] will never overlap on a well-formed
** database. But they might for a corrupt database. Hence use memmove()
** since memcpy() sends SIGABORT with overlapping buffers on OpenBSD */
assert( (pSlot+sz)<=pCArray->apCell[i]
|| pSlot>=(pCArray->apCell[i]+sz)
|| CORRUPT_DB );
memmove(pSlot, pCArray->apCell[i], sz);
put2byte(pCellptr, (pSlot - aData));
pCellptr += 2;
}
@@ -7624,7 +7630,7 @@ static int balance_nonroot(
** by smaller than the child due to the database header, and so all the
** free space needs to be up front.
*/
assert( nNew==1 );
assert( nNew==1 || CORRUPT_DB );
rc = defragmentPage(apNew[0]);
testcase( rc!=SQLITE_OK );
assert( apNew[0]->nFree ==
+32 -31
View File
@@ -985,7 +985,7 @@ void sqlite3StartTable(
** now.
*/
if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
int j1;
int addr1;
int fileFormat;
int reg1, reg2, reg3;
/* nullRow[] is an OP_Record encoding of a row containing 5 NULLs */
@@ -1006,14 +1006,14 @@ void sqlite3StartTable(
reg3 = ++pParse->nMem;
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT);
sqlite3VdbeUsesBtree(v, iDb);
j1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
1 : SQLITE_MAX_FILE_FORMAT;
sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, reg3);
sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, reg3);
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
/* This just creates a place-holder record in the sqlite_master table.
** The record created does not contain anything yet. It will be replaced
@@ -1271,6 +1271,30 @@ void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
sqlite3ExprDelete(db, pSpan->pExpr);
}
/*
** Backwards Compatibility Hack:
**
** Historical versions of SQLite accepted strings as column names in
** indexes and PRIMARY KEY constraints and in UNIQUE constraints. Example:
**
** CREATE TABLE xyz(a,b,c,d,e,PRIMARY KEY('a'),UNIQUE('b','c' COLLATE trim)
** CREATE INDEX abc ON xyz('c','d' DESC,'e' COLLATE nocase DESC);
**
** This is goofy. But to preserve backwards compatibility we continue to
** accept it. This routine does the necessary conversion. It converts
** the expression given in its argument from a TK_STRING into a TK_ID
** if the expression is just a TK_STRING with an optional COLLATE clause.
** If the epxression is anything other than TK_STRING, the expression is
** unchanged.
*/
static void sqlite3StringToId(Expr *p){
if( p->op==TK_STRING ){
p->op = TK_ID;
}else if( p->op==TK_COLLATE && p->pLeft->op==TK_STRING ){
p->pLeft->op = TK_ID;
}
}
/*
** Designate the PRIMARY KEY for the table. pList is a list of names
** of columns that form the primary key. If pList is NULL, then the
@@ -1317,6 +1341,7 @@ void sqlite3AddPrimaryKey(
for(i=0; i<nTerm; i++){
Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[i].pExpr);
assert( pCExpr!=0 );
sqlite3StringToId(pCExpr);
if( pCExpr->op==TK_ID ){
const char *zCName = pCExpr->u.zToken;
for(iCol=0; iCol<pTab->nCol; iCol++){
@@ -2855,30 +2880,6 @@ Index *sqlite3AllocateIndexObject(
return p;
}
/*
** Backwards Compatibility Hack:
**
** Historical versions of SQLite accepted strings as column names in
** indexes and PRIMARY KEY constraints and in UNIQUE constraints. Example:
**
** CREATE TABLE xyz(a,b,c,d,e,PRIMARY KEY('a'),UNIQUE('b','c' COLLATE trim)
** CREATE INDEX abc ON xyz('c','d' DESC,'e' COLLATE nocase DESC);
**
** This is goofy. But to preserve backwards compatibility we continue to
** accept it. This routine does the necessary conversion. It converts
** the expression given in its argument from a TK_STRING into a TK_ID
** if the expression is just a TK_STRING with an optional COLLATE clause.
** If the epxression is anything other than TK_STRING, the expression is
** unchanged.
*/
static void sqlite3StringToId(Expr *p){
if( p->op==TK_STRING ){
p->op = TK_ID;
}else if( p->op==TK_COLLATE && p->pLeft->op==TK_STRING ){
p->pLeft->op = TK_ID;
}
}
/*
** Create a new index for an SQL table. pName1.pName2 is the name of the index
** and pTblList is the name of the table that is to be indexed. Both will
@@ -3136,7 +3137,7 @@ Index *sqlite3CreateIndex(
/* Analyze the list of expressions that form the terms of the index and
** report any errors. In the common case where the expression is exactly
** a table column, store that column in aiColumn[]. For general expressions,
** populate pIndex->aColExpr and store -2 in aiColumn[].
** populate pIndex->aColExpr and store XN_EXPR (-2) in aiColumn[].
**
** TODO: Issue a warning if two or more columns of the index are identical.
** TODO: Issue a warning if the table primary key is used as part of the
@@ -3165,8 +3166,8 @@ Index *sqlite3CreateIndex(
pListItem = &pCopy->a[i];
}
}
j = -2;
pIndex->aiColumn[i] = -2;
j = XN_EXPR;
pIndex->aiColumn[i] = XN_EXPR;
pIndex->uniqNotNull = 0;
}else{
j = pCExpr->iColumn;
@@ -3219,7 +3220,7 @@ Index *sqlite3CreateIndex(
}
assert( i==pIndex->nColumn );
}else{
pIndex->aiColumn[i] = -1;
pIndex->aiColumn[i] = XN_ROWID;
pIndex->azColl[i] = "BINARY";
}
sqlite3DefaultRowEst(pIndex);
+6
View File
@@ -96,12 +96,18 @@ static const char * const azCompileOpt[] = {
#if SQLITE_ENABLE_FTS4
"ENABLE_FTS4",
#endif
#if SQLITE_ENABLE_FTS5
"ENABLE_FTS5",
#endif
#if SQLITE_ENABLE_ICU
"ENABLE_ICU",
#endif
#if SQLITE_ENABLE_IOTRACE
"ENABLE_IOTRACE",
#endif
#if SQLITE_ENABLE_JSON1
"ENABLE_JSON1",
#endif
#if SQLITE_ENABLE_LOAD_EXTENSION
"ENABLE_LOAD_EXTENSION",
#endif
+2 -2
View File
@@ -422,7 +422,7 @@ void sqlite3DeleteFrom(
/* Extract the rowid or primary key for the current row */
if( pPk ){
for(i=0; i<nPk; i++){
assert( pPk->aiColumn[i]>=(-1) );
assert( pPk->aiColumn[i]>=0 );
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
pPk->aiColumn[i], iPk+i);
}
@@ -858,7 +858,7 @@ int sqlite3GenerateIndexKey(
for(j=0; j<nCol; j++){
if( pPrior
&& pPrior->aiColumn[j]==pIdx->aiColumn[j]
&& pPrior->aiColumn[j]>=(-1)
&& pPrior->aiColumn[j]!=XN_EXPR
){
/* This column was already computed by the previous index */
continue;
+12 -12
View File
@@ -1595,13 +1595,13 @@ int sqlite3CodeOnce(Parse *pParse){
** to be set to NULL if iCur contains one or more NULL values.
*/
static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
int j1;
int addr1;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull);
j1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
addr1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull);
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
VdbeComment((v, "first_entry_in(%d)", iCur));
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
}
@@ -2201,7 +2201,7 @@ static void sqlite3ExprCodeIN(
** the presence of a NULL on the RHS makes a difference in the
** outcome.
*/
int j1;
int addr1;
/* First check to see if the LHS is contained in the RHS. If so,
** then the answer is TRUE the presence of NULLs in the RHS does
@@ -2209,12 +2209,12 @@ static void sqlite3ExprCodeIN(
** answer is NULL if the RHS contains NULLs and the answer is
** FALSE if the RHS is NULL-free.
*/
j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
addr1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull);
VdbeCoverage(v);
sqlite3VdbeGoto(v, destIfFalse);
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
}
}
}
@@ -2443,15 +2443,15 @@ void sqlite3ExprCodeLoadIndexColumn(
int regOut /* Store the index column value in this register */
){
i16 iTabCol = pIdx->aiColumn[iIdxCol];
if( iTabCol>=(-1) ){
if( iTabCol==XN_EXPR ){
assert( pIdx->aColExpr );
assert( pIdx->aColExpr->nExpr>iIdxCol );
pParse->iSelfTab = iTabCur;
sqlite3ExprCode(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut);
}else{
sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur,
iTabCol, regOut);
return;
}
assert( pIdx->aColExpr );
assert( pIdx->aColExpr->nExpr>iIdxCol );
pParse->iSelfTab = iTabCur;
sqlite3ExprCode(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut);
}
/*
+10 -1
View File
@@ -252,6 +252,8 @@ int sqlite3FkLocateIndex(
char *zDfltColl; /* Def. collation for column */
char *zIdxCol; /* Name of indexed column */
if( iCol<0 ) break; /* No foreign keys against expression indexes */
/* If the index uses a collation sequence that is different from
** the default collation sequence for the column, this index is
** unusable. Bail out early in this case. */
@@ -404,6 +406,7 @@ static void fkLookupParent(
for(i=0; i<nCol; i++){
int iChild = aiCol[i]+1+regData;
int iParent = pIdx->aiColumn[i]+1+regData;
assert( pIdx->aiColumn[i]>=0 );
assert( aiCol[i]!=pTab->iPKey );
if( pIdx->aiColumn[i]==pTab->iPKey ){
/* The parent key is a composite key that includes the IPK column */
@@ -612,6 +615,7 @@ static void fkScanChildren(
assert( pIdx!=0 );
for(i=0; i<pPk->nKeyCol; i++){
i16 iCol = pIdx->aiColumn[i];
assert( iCol>=0 );
pLeft = exprTableRegister(pParse, pTab, regData, iCol);
pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol);
pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
@@ -931,6 +935,7 @@ void sqlite3FkCheck(
if( aiCol[i]==pTab->iPKey ){
aiCol[i] = -1;
}
assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
#ifndef SQLITE_OMIT_AUTHORIZATION
/* Request permission to read the parent key columns. If the
** authorization callback returns SQLITE_IGNORE, behave as if any
@@ -1062,7 +1067,10 @@ u32 sqlite3FkOldmask(
Index *pIdx = 0;
sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0);
if( pIdx ){
for(i=0; i<pIdx->nKeyCol; i++) mask |= COLUMN_MASK(pIdx->aiColumn[i]);
for(i=0; i<pIdx->nKeyCol; i++){
assert( pIdx->aiColumn[i]>=0 );
mask |= COLUMN_MASK(pIdx->aiColumn[i]);
}
}
}
}
@@ -1185,6 +1193,7 @@ static Trigger *fkActionTrigger(
iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
assert( iFromCol>=0 );
assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) );
assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName;
tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName;
+22 -19
View File
@@ -90,11 +90,11 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
i16 x = pIdx->aiColumn[n];
if( x>=0 ){
pIdx->zColAff[n] = pTab->aCol[x].affinity;
}else if( x==(-1) ){
}else if( x==XN_ROWID ){
pIdx->zColAff[n] = SQLITE_AFF_INTEGER;
}else{
char aff;
assert( x==(-2) );
assert( x==XN_EXPR );
assert( pIdx->aColExpr!=0 );
aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
if( aff==0 ) aff = SQLITE_AFF_BLOB;
@@ -313,16 +313,16 @@ void sqlite3AutoincrementEnd(Parse *pParse){
assert( v );
for(p = pParse->pAinc; p; p = p->pNext){
Db *pDb = &db->aDb[p->iDb];
int j1;
int addr1;
int iRec;
int memId = p->regCtr;
iRec = sqlite3GetTempReg(pParse);
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
@@ -814,7 +814,7 @@ void sqlite3Insert(
if( ipkColumn<0 ){
sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
}else{
int j1;
int addr1;
assert( !withoutRowid );
if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regCols);
@@ -822,9 +822,9 @@ void sqlite3Insert(
assert( pSelect==0 ); /* Otherwise useTempTable is true */
sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regCols);
}
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v);
addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v);
}
@@ -898,14 +898,14 @@ void sqlite3Insert(
** to generate a unique primary key value.
*/
if( !appendFlag ){
int j1;
int addr1;
if( !IsVirtual(pTab) ){
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v);
addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
}else{
j1 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, j1+2); VdbeCoverage(v);
addr1 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, addr1+2); VdbeCoverage(v);
}
sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v);
}
@@ -1159,7 +1159,7 @@ void sqlite3GenerateConstraintChecks(
int ix; /* Index loop counter */
int nCol; /* Number of columns */
int onError; /* Conflict resolution strategy */
int j1; /* Address of jump instruction */
int addr1; /* Address of jump instruction */
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
int ipkTop = 0; /* Top of the rowid change constraint check */
@@ -1230,9 +1230,10 @@ void sqlite3GenerateConstraintChecks(
}
default: {
assert( onError==OE_Replace );
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i); VdbeCoverage(v);
addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i);
VdbeCoverage(v);
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i);
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
break;
}
}
@@ -1408,13 +1409,13 @@ void sqlite3GenerateConstraintChecks(
for(i=0; i<pIdx->nColumn; i++){
int iField = pIdx->aiColumn[i];
int x;
if( iField==(-2) ){
if( iField==XN_EXPR ){
pParse->ckBase = regNewData+1;
sqlite3ExprCode(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
pParse->ckBase = 0;
VdbeComment((v, "%s column %d", pIdx->zName, i));
}else{
if( iField==(-1) || iField==pTab->iPKey ){
if( iField==XN_ROWID || iField==pTab->iPKey ){
if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
x = regNewData;
regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
@@ -1473,6 +1474,7 @@ void sqlite3GenerateConstraintChecks(
** store it in registers regR..regR+nPk-1 */
if( pIdx!=pPk ){
for(i=0; i<pPk->nKeyCol; i++){
assert( pPk->aiColumn[i]>=0 );
x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
VdbeComment((v, "%s.%s", pTab->zName,
@@ -1494,6 +1496,7 @@ void sqlite3GenerateConstraintChecks(
for(i=0; i<pPk->nKeyCol; i++){
char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
x = pPk->aiColumn[i];
assert( x>=0 );
if( i==(pPk->nKeyCol-1) ){
addrJump = addrUniqueOk;
op = OP_Eq;
@@ -1745,7 +1748,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){
return 0; /* Different columns indexed */
}
if( pSrc->aiColumn[i]==(-2) ){
if( pSrc->aiColumn[i]==XN_EXPR ){
assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 );
if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr,
pDest->aColExpr->a[i].pExpr, -1)!=0 ){
+2 -2
View File
@@ -408,7 +408,7 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_value_free,
sqlite3_result_zeroblob64,
sqlite3_bind_zeroblob64,
/* Version 3.8.12 and later */
/* Version 3.9.0 and later */
sqlite3_value_subtype,
sqlite3_result_subtype
};
@@ -615,7 +615,7 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
** dummy pointer.
*/
#ifdef SQLITE_OMIT_LOAD_EXTENSION
static const sqlite3_api_routines sqlite3Apis = { 0 };
static const sqlite3_api_routines sqlite3Apis;
#endif
+13 -2
View File
@@ -25,6 +25,12 @@
#ifdef SQLITE_ENABLE_ICU
# include "sqliteicu.h"
#endif
#ifdef SQLITE_ENABLE_JSON1
int sqlite3Json1Init(sqlite3*);
#endif
#ifdef SQLITE_ENABLE_FTS5
int sqlite3Fts5Init(sqlite3*);
#endif
#ifndef SQLITE_AMALGAMATION
/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
@@ -2872,12 +2878,18 @@ static int openDatabase(
}
#endif
#ifdef SQLITE_ENABLE_FTS3
#ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3Fts3Init(db);
}
#endif
#ifdef SQLITE_ENABLE_FTS5
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3Fts5Init(db);
}
#endif
#ifdef SQLITE_ENABLE_ICU
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3IcuInit(db);
@@ -2898,7 +2910,6 @@ static int openDatabase(
#ifdef SQLITE_ENABLE_JSON1
if( !db->mallocFailed && rc==SQLITE_OK){
extern int sqlite3Json1Init(sqlite3*);
rc = sqlite3Json1Init(db);
}
#endif
+4 -1
View File
@@ -87,7 +87,10 @@ void sqlite3MemoryBarrier(void){
SQLITE_MEMORY_BARRIER;
#elif defined(__GNUC__)
__sync_synchronize();
#else
#elif !defined(SQLITE_DISABLE_INTRINSIC) && \
defined(_MSC_VER) && _MSC_VER>=1300
_ReadWriteBarrier();
#elif defined(MemoryBarrier)
MemoryBarrier();
#endif
}
+7 -6
View File
@@ -1361,8 +1361,9 @@ void sqlite3Pragma(
*/
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList endCode[] = {
{ OP_IfNeg, 1, 0, 0}, /* 0 */
{ OP_String8, 0, 3, 0}, /* 1 */
{ OP_AddImm, 1, 0, 0}, /* 0 */
{ OP_If, 1, 0, 0}, /* 1 */
{ OP_String8, 0, 3, 0}, /* 2 */
{ OP_ResultRow, 3, 1, 0},
};
@@ -1524,7 +1525,7 @@ void sqlite3Pragma(
int kk;
for(kk=0; kk<pIdx->nKeyCol; kk++){
int iCol = pIdx->aiColumn[kk];
assert( iCol!=(-1) && iCol<pTab->nCol );
assert( iCol!=XN_ROWID && iCol<pTab->nCol );
if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
VdbeCoverage(v);
@@ -1563,9 +1564,9 @@ void sqlite3Pragma(
}
}
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
sqlite3VdbeChangeP3(v, addr, -mxErr);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeChangeP4(v, addr+1, "ok", P4_STATIC);
sqlite3VdbeChangeP2(v, addr, -mxErr);
sqlite3VdbeJumpHere(v, addr+1);
sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
}
break;
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
+52 -59
View File
@@ -579,7 +579,7 @@ static void pushOntoSorter(
}else{
iLimit = pSelect->iLimit;
}
addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, -1); VdbeCoverage(v);
addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
sqlite3VdbeJumpHere(v, addr);
@@ -595,11 +595,8 @@ static void codeOffset(
int iContinue /* Jump here to skip the current record */
){
if( iOffset>0 ){
int addr;
addr = sqlite3VdbeAddOp3(v, OP_IfNeg, iOffset, 0, -1); VdbeCoverage(v);
sqlite3VdbeGoto(v, iContinue);
VdbeComment((v, "skip OFFSET records"));
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp3(v, OP_IfPos, iOffset, iContinue, 1); VdbeCoverage(v);
VdbeComment((v, "OFFSET"));
}
}
@@ -1815,7 +1812,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
Vdbe *v = 0;
int iLimit = 0;
int iOffset;
int addr1, n;
int n;
if( p->iLimit ) return;
/*
@@ -1850,14 +1847,10 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
sqlite3ExprCode(pParse, p->pOffset, iOffset);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v);
VdbeComment((v, "OFFSET counter"));
addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iOffset); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, 0, iOffset);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iOffset, iOffset, 0);
sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1);
VdbeComment((v, "LIMIT+OFFSET"));
addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iLimit); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, -1, iOffset+1);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iLimit, iOffset+1, -1);
}
}
}
@@ -2273,6 +2266,11 @@ static int multiSelect(
if( p->iLimit ){
addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
VdbeComment((v, "Jump ahead if LIMIT reached"));
if( p->iOffset ){
sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iOffset, p->iOffset, 0);
sqlite3VdbeAddOp3(v, OP_Add, p->iLimit, p->iOffset, p->iOffset+1);
sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iLimit, p->iOffset+1, -1);
}
}
explainSetInteger(iSub2, pParse->iNextSelectId);
rc = sqlite3Select(pParse, p, &dest);
@@ -2580,12 +2578,12 @@ static int generateOutputSubroutine(
/* Suppress duplicates for UNION, EXCEPT, and INTERSECT
*/
if( regPrev ){
int j1, j2;
j1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); VdbeCoverage(v);
j2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst,
int addr1, addr2;
addr1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); VdbeCoverage(v);
addr2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst,
(char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
sqlite3VdbeAddOp3(v, OP_Jump, j2+2, iContinue, j2+2); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeAddOp3(v, OP_Jump, addr2+2, iContinue, addr2+2); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regPrev+1, pIn->nSdst-1);
sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev);
}
@@ -2802,7 +2800,7 @@ static int multiSelectOrderBy(
int savedOffset; /* Saved value of p->iOffset */
int labelCmpr; /* Label for the start of the merge algorithm */
int labelEnd; /* Label for the end of the overall SELECT stmt */
int j1; /* Jump instructions that get retargetted */
int addr1; /* Jump instructions that get retargetted */
int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
KeyInfo *pKeyMerge; /* Comparison information for merging rows */
@@ -2938,19 +2936,19 @@ static int multiSelectOrderBy(
** left of the compound operator - the "A" select.
*/
addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
VdbeComment((v, "left SELECT"));
pPrior->iLimit = regLimitA;
explainSetInteger(iSub1, pParse->iNextSelectId);
sqlite3Select(pParse, pPrior, &destA);
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
/* Generate a coroutine to evaluate the SELECT statement on
** the right - the "B" select
*/
addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
VdbeComment((v, "right SELECT"));
savedLimit = p->iLimit;
savedOffset = p->iOffset;
@@ -3041,7 +3039,7 @@ static int multiSelectOrderBy(
/* This code runs once to initialize everything.
*/
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v);
@@ -3084,7 +3082,7 @@ static int multiSelectOrderBy(
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/* Forward Declarations */
static void substExprList(sqlite3*, ExprList*, int, ExprList*);
static void substSelect(sqlite3*, Select *, int, ExprList *);
static void substSelect(sqlite3*, Select *, int, ExprList*, int);
/*
** Scan through the expression pExpr. Replace every reference to
@@ -3121,7 +3119,7 @@ static Expr *substExpr(
pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList);
pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
substSelect(db, pExpr->x.pSelect, iTable, pEList);
substSelect(db, pExpr->x.pSelect, iTable, pEList, 1);
}else{
substExprList(db, pExpr->x.pList, iTable, pEList);
}
@@ -3144,25 +3142,28 @@ static void substSelect(
sqlite3 *db, /* Report malloc errors here */
Select *p, /* SELECT statement in which to make substitutions */
int iTable, /* Table to be replaced */
ExprList *pEList /* Substitute values */
ExprList *pEList, /* Substitute values */
int doPrior /* Do substitutes on p->pPrior too */
){
SrcList *pSrc;
struct SrcList_item *pItem;
int i;
if( !p ) return;
substExprList(db, p->pEList, iTable, pEList);
substExprList(db, p->pGroupBy, iTable, pEList);
substExprList(db, p->pOrderBy, iTable, pEList);
p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
substSelect(db, p->pPrior, iTable, pEList);
pSrc = p->pSrc;
assert( pSrc ); /* Even for (SELECT 1) we have: pSrc!=0 but pSrc->nSrc==0 */
if( ALWAYS(pSrc) ){
do{
substExprList(db, p->pEList, iTable, pEList);
substExprList(db, p->pGroupBy, iTable, pEList);
substExprList(db, p->pOrderBy, iTable, pEList);
p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
pSrc = p->pSrc;
assert( pSrc!=0 );
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
substSelect(db, pItem->pSelect, iTable, pEList);
substSelect(db, pItem->pSelect, iTable, pEList, 1);
if( pItem->fg.isTabFunc ){
substExprList(db, pItem->u1.pFuncArg, iTable, pEList);
}
}
}
}while( doPrior && (p = p->pPrior)!=0 );
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
@@ -3314,7 +3315,7 @@ static int flattenSubquery(
int subqueryIsAgg /* True if the subquery uses aggregate functions */
){
const char *zSavedAuthContext = pParse->zAuthContext;
Select *pParent;
Select *pParent; /* Current UNION ALL term of the other query */
Select *pSub; /* The inner query or "subquery" */
Select *pSub1; /* Pointer to the rightmost select in sub-query */
SrcList *pSrc; /* The FROM clause of the outer query */
@@ -3609,9 +3610,9 @@ static int flattenSubquery(
**
** The outer query has 3 slots in its FROM clause. One slot of the
** outer query (the middle slot) is used by the subquery. The next
** block of code will expand the out query to 4 slots. The middle
** slot is expanded to two slots in order to make space for the
** two elements in the FROM clause of the subquery.
** block of code will expand the outer query FROM clause to 4 slots.
** The middle slot is expanded to two slots in order to make space
** for the two elements in the FROM clause of the subquery.
*/
if( nSubSrc>1 ){
pParent->pSrc = pSrc = sqlite3SrcListEnlarge(db, pSrc, nSubSrc-1,iFrom+1);
@@ -3650,11 +3651,6 @@ static int flattenSubquery(
pList->a[i].zName = zName;
}
}
substExprList(db, pParent->pEList, iParent, pSub->pEList);
if( isAgg ){
substExprList(db, pParent->pGroupBy, iParent, pSub->pEList);
pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
}
if( pSub->pOrderBy ){
/* At this point, any non-zero iOrderByCol values indicate that the
** ORDER BY column expression is identical to the iOrderByCol'th
@@ -3674,27 +3670,20 @@ static int flattenSubquery(
assert( pSub->pPrior==0 );
pParent->pOrderBy = pOrderBy;
pSub->pOrderBy = 0;
}else if( pParent->pOrderBy ){
substExprList(db, pParent->pOrderBy, iParent, pSub->pEList);
}
if( pSub->pWhere ){
pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
}else{
pWhere = 0;
}
pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
if( subqueryIsAgg ){
assert( pParent->pHaving==0 );
pParent->pHaving = pParent->pWhere;
pParent->pWhere = pWhere;
pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
sqlite3ExprDup(db, pSub->pHaving, 0));
assert( pParent->pGroupBy==0 );
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
}else{
pParent->pWhere = substExpr(db, pParent->pWhere, iParent, pSub->pEList);
pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
}
substSelect(db, pParent, iParent, pSub->pEList, 0);
/* The flattened query is distinct if either the inner or the
** outer query is distinct.
@@ -4259,6 +4248,7 @@ static int selectExpander(Walker *pWalker, Select *p){
pTab->nRef++;
#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
if( pTab->pSelect || IsVirtual(pTab) ){
i16 nCol;
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
assert( pFrom->pSelect==0 );
if( pFrom->fg.isTabFunc && !IsVirtual(pTab) ){
@@ -4267,7 +4257,10 @@ static int selectExpander(Walker *pWalker, Select *p){
}
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
sqlite3SelectSetName(pFrom->pSelect, pTab->zName);
nCol = pTab->nCol;
pTab->nCol = -1;
sqlite3WalkSelect(pWalker, pFrom->pSelect);
pTab->nCol = nCol;
}
#endif
}
@@ -5215,7 +5208,7 @@ int sqlite3Select(
*/
if( pGroupBy ){
KeyInfo *pKeyInfo; /* Keying information for the group by clause */
int j1; /* A-vs-B comparision jump */
int addr1; /* A-vs-B comparision jump */
int addrOutputRow; /* Start of subroutine that outputs a result row */
int regOutputRow; /* Return address register for output subroutine */
int addrSetAbort; /* Set the abort flag and return */
@@ -5363,8 +5356,8 @@ int sqlite3Select(
}
sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr,
(char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
j1 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, j1+1, 0, j1+1); VdbeCoverage(v);
addr1 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addr1+1, 0, addr1+1); VdbeCoverage(v);
/* Generate code that runs whenever the GROUP BY changes.
** Changes in the GROUP BY are detected by the previous code
@@ -5386,7 +5379,7 @@ int sqlite3Select(
/* Update the aggregate accumulators based on the content of
** the current row
*/
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
updateAccumulator(pParse, &sAggInfo);
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
VdbeComment((v, "indicate data in accumulator"));
+45 -17
View File
@@ -2612,6 +2612,22 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
return 0;
}
/*
** Print the current sqlite3_errmsg() value to stderr and return 1.
*/
static int shellDatabaseError(sqlite3 *db){
const char *zErr = sqlite3_errmsg(db);
fprintf(stderr, "Error: %s\n", zErr);
return 1;
}
/*
** Print an out-of-memory message to stderr and return 1.
*/
static int shellNomemError(void){
fprintf(stderr, "Error: out of memory\n");
return 1;
}
/*
** If an input line begins with "." then invoke this routine to
@@ -3713,13 +3729,17 @@ static int do_meta_command(char *zLine, ShellState *p){
int ii;
open_db(p, 0);
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ) return rc;
if( rc ) return shellDatabaseError(p->db);
/* Create an SQL statement to query for the list of tables in the
** main and all attached databases where the table name matches the
** LIKE pattern bound to variable "?1". */
zSql = sqlite3_mprintf(
"SELECT name FROM sqlite_master"
" WHERE type IN ('table','view')"
" AND name NOT LIKE 'sqlite_%%'"
" AND name LIKE ?1");
while( sqlite3_step(pStmt)==SQLITE_ROW ){
while( zSql && sqlite3_step(pStmt)==SQLITE_ROW ){
const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
if( zDbName==0 || strcmp(zDbName,"main")==0 ) continue;
if( strcmp(zDbName,"temp")==0 ){
@@ -3738,11 +3758,17 @@ static int do_meta_command(char *zLine, ShellState *p){
" AND name LIKE ?1", zSql, zDbName, zDbName);
}
}
sqlite3_finalize(pStmt);
zSql = sqlite3_mprintf("%z ORDER BY 1", zSql);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
rc = sqlite3_finalize(pStmt);
if( zSql && rc==SQLITE_OK ){
zSql = sqlite3_mprintf("%z ORDER BY 1", zSql);
if( zSql ) rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
}
sqlite3_free(zSql);
if( rc ) return rc;
if( !zSql ) return shellNomemError();
if( rc ) return shellDatabaseError(p->db);
/* Run the SQL statement prepared by the above block. Store the results
** as an array of nul-terminated strings in azResult[]. */
nRow = nAlloc = 0;
azResult = 0;
if( nArg>1 ){
@@ -3756,17 +3782,25 @@ static int do_meta_command(char *zLine, ShellState *p){
int n2 = nAlloc*2 + 10;
azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
if( azNew==0 ){
fprintf(stderr, "Error: out of memory\n");
rc = shellNomemError();
break;
}
nAlloc = n2;
azResult = azNew;
}
azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
if( azResult[nRow] ) nRow++;
if( 0==azResult[nRow] ){
rc = shellNomemError();
break;
}
nRow++;
}
sqlite3_finalize(pStmt);
if( nRow>0 ){
if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
rc = shellDatabaseError(p->db);
}
/* Pretty-print the contents of array azResult[] to the output */
if( rc==0 && nRow>0 ){
int len, maxlen = 0;
int i, j;
int nPrintCol, nPrintRow;
@@ -3785,6 +3819,7 @@ static int do_meta_command(char *zLine, ShellState *p){
fprintf(p->out, "\n");
}
}
for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
sqlite3_free(azResult);
}else
@@ -4619,13 +4654,6 @@ int SQLITE_CDECL main(int argc, char **argv){
}
data.out = stdout;
#ifdef SQLITE_SHELL_JSON1
{
extern int sqlite3_json_init(sqlite3*);
sqlite3_auto_extension((void(*)(void))sqlite3_json_init);
}
#endif
/* Go ahead and open the database file if it already exists. If the
** file does not exist, delay opening it. This prevents empty database
** files from being created if a user mistypes the database name argument
+3 -3
View File
@@ -5656,9 +5656,9 @@ struct sqlite3_module {
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
** was added for version 3.8.12. It may therefore only be used if
** was added for version 3.9.0. It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3008012.
** 3009000.
*/
struct sqlite3_index_info {
/* Inputs */
@@ -5686,7 +5686,7 @@ struct sqlite3_index_info {
double estimatedCost; /* Estimated cost of using this index */
/* Fields below are only available in SQLite 3.8.2 and later */
sqlite3_int64 estimatedRows; /* Estimated number of rows returned */
/* Fields below are only available in SQLite 3.8.12 and later */
/* Fields below are only available in SQLite 3.9.0 and later */
int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */
};
+2 -2
View File
@@ -272,7 +272,7 @@ struct sqlite3_api_routines {
void (*value_free)(sqlite3_value*);
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
/* Version 3.8.12 and later */
/* Version 3.9.0 and later */
unsigned int (*value_subtype)(sqlite3_value*);
void (*result_subtype)(sqlite3_context*,unsigned int);
};
@@ -511,7 +511,7 @@ struct sqlite3_api_routines {
#define sqlite3_value_free sqlite3_api->value_free
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
/* Version 3.8.12 and later */
/* Version 3.9.0 and later */
#define sqlite3_value_subtype sqlite3_api->value_subtype
#define sqlite3_result_subtype sqlite3_api->result_subtype
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
+7
View File
@@ -196,6 +196,7 @@
# include <intrin.h>
# pragma intrinsic(_byteswap_ushort)
# pragma intrinsic(_byteswap_ulong)
# pragma intrinsic(_ReadWriteBarrier)
# else
# include <cmnintrin.h>
# endif
@@ -1917,6 +1918,12 @@ struct Index {
/* Return true if index X is a UNIQUE index */
#define IsUniqueIndex(X) ((X)->onError!=OE_None)
/* The Index.aiColumn[] values are normally positive integer. But
** there are some negative values that have special meaning:
*/
#define XN_ROWID (-1) /* Indexed column is the rowid */
#define XN_EXPR (-2) /* Indexed column is an expression */
/*
** Each sample stored in the sqlite_stat3 table is represented in memory
** using a structure of this type. See documentation at the top of the
+5 -7
View File
@@ -6377,7 +6377,6 @@ static int tclLoadStaticExtensionCmd(
extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_json_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
@@ -6385,7 +6384,6 @@ static int tclLoadStaticExtensionCmd(
extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_fts5_init(sqlite3*,char**,const sqlite3_api_routines*);
static const struct {
const char *zExtName;
int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
@@ -6393,13 +6391,9 @@ static int tclLoadStaticExtensionCmd(
{ "amatch", sqlite3_amatch_init },
{ "closure", sqlite3_closure_init },
{ "eval", sqlite3_eval_init },
#ifdef SQLITE_ENABLE_FTS5
{ "fts5", sqlite3_fts5_init },
#endif
{ "fileio", sqlite3_fileio_init },
{ "fuzzer", sqlite3_fuzzer_init },
{ "ieee754", sqlite3_ieee_init },
{ "json", sqlite3_json_init },
{ "nextchar", sqlite3_nextchar_init },
{ "percentile", sqlite3_percentile_init },
{ "regexp", sqlite3_regexp_init },
@@ -6426,7 +6420,11 @@ static int tclLoadStaticExtensionCmd(
Tcl_AppendResult(interp, "no such extension: ", zName, (char*)0);
return TCL_ERROR;
}
rc = aExtension[i].pInit(db, &zErrMsg, 0);
if( aExtension[i].pInit ){
rc = aExtension[i].pInit(db, &zErrMsg, 0);
}else{
rc = SQLITE_OK;
}
if( rc!=SQLITE_OK || zErrMsg ){
Tcl_AppendResult(interp, "initialization of ", zName, " failed: ", zErrMsg,
(char*)0);
+6
View File
@@ -167,6 +167,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_JSON1
Tcl_SetVar2(interp, "sqlite_options", "json1", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "json1", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_ATTACH
Tcl_SetVar2(interp, "sqlite_options", "attach", "0", TCL_GLOBAL_ONLY);
#else
+5 -5
View File
@@ -384,7 +384,7 @@ void sqlite3Update(
if( pWInfo==0 ) goto update_cleanup;
okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
for(i=0; i<nPk; i++){
assert( pPk->aiColumn[i]>=(-1) );
assert( pPk->aiColumn[i]>=0 );
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i],
iPk+i);
}
@@ -564,7 +564,7 @@ void sqlite3Update(
}
if( !isView ){
int j1 = 0; /* Address of jump instruction */
int addr1 = 0; /* Address of jump instruction */
int bReplace = 0; /* True if REPLACE conflict resolution might happen */
/* Do constraint checks. */
@@ -580,9 +580,9 @@ void sqlite3Update(
/* Delete the index entries associated with the current record. */
if( bReplace || chngKey ){
if( pPk ){
j1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey);
addr1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey);
}else{
j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid);
addr1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid);
}
VdbeCoverageNeverTaken(v);
}
@@ -593,7 +593,7 @@ void sqlite3Update(
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
}
if( bReplace || chngKey ){
sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeJumpHere(v, addr1);
}
if( hasFK ){
+23 -17
View File
@@ -5671,12 +5671,12 @@ case OP_MemMax: { /* in2 */
}
#endif /* SQLITE_OMIT_AUTOINCREMENT */
/* Opcode: IfPos P1 P2 * * *
** Synopsis: if r[P1]>0 goto P2
/* Opcode: IfPos P1 P2 P3 * *
** Synopsis: if r[P1]>0 then r[P1]-=P3, goto P2
**
** Register P1 must contain an integer.
** If the value of register P1 is 1 or greater, jump to P2 and
** add the literal value P3 to register P1.
** If the value of register P1 is 1 or greater, subtract P3 from the
** value in P1 and jump to P2.
**
** If the initial value of register P1 is less than 1, then the
** value is unchanged and control passes through to the next instruction.
@@ -5685,38 +5685,44 @@ case OP_IfPos: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
VdbeBranchTaken( pIn1->u.i>0, 2);
if( pIn1->u.i>0 ) goto jump_to_p2;
if( pIn1->u.i>0 ){
pIn1->u.i -= pOp->p3;
goto jump_to_p2;
}
break;
}
/* Opcode: IfNeg P1 P2 P3 * *
** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2
/* Opcode: SetIfNotPos P1 P2 P3 * *
** Synopsis: if r[P1]<=0 then r[P2]=P3
**
** Register P1 must contain an integer. Add literal P3 to the value in
** register P1 then if the value of register P1 is less than zero, jump to P2.
** Register P1 must contain an integer.
** If the value of register P1 is not positive (if it is less than 1) then
** set the value of register P2 to be the integer P3.
*/
case OP_IfNeg: { /* jump, in1 */
case OP_SetIfNotPos: { /* in1, in2 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
pIn1->u.i += pOp->p3;
VdbeBranchTaken(pIn1->u.i<0, 2);
if( pIn1->u.i<0 ) goto jump_to_p2;
if( pIn1->u.i<=0 ){
pOut = out2Prerelease(p, pOp);
pOut->u.i = pOp->p3;
}
break;
}
/* Opcode: IfNotZero P1 P2 P3 * *
** Synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2
** Synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2
**
** Register P1 must contain an integer. If the content of register P1 is
** initially nonzero, then add P3 to P1 and jump to P2. If register P1 is
** initially zero, leave it unchanged and fall through.
** initially nonzero, then subtract P3 from the value in register P1 and
** jump to P2. If register P1 is initially zero, leave it unchanged
** and fall through.
*/
case OP_IfNotZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
VdbeBranchTaken(pIn1->u.i<0, 2);
if( pIn1->u.i ){
pIn1->u.i += pOp->p3;
pIn1->u.i -= pOp->p3;
goto jump_to_p2;
}
break;
+1 -1
View File
@@ -248,7 +248,7 @@ int sqlite3_blob_open(
int j;
for(j=0; j<pIdx->nKeyCol; j++){
/* FIXME: Be smarter about indexes that use expressions */
if( pIdx->aiColumn[j]==iCol || pIdx->aiColumn[j]==(-2) ){
if( pIdx->aiColumn[j]==iCol || pIdx->aiColumn[j]==XN_EXPR ){
zFault = "indexed";
}
}
+3 -1
View File
@@ -937,7 +937,9 @@ int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
if( rc==SQLITE_OK ){
rc = pModule->xBegin(pVTab->pVtab);
if( rc==SQLITE_OK ){
int iSvpt = db->nStatement + db->nSavepoint;
addToVTrans(db, pVTab);
if( iSvpt ) rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, iSvpt-1);
}
}
}
@@ -1143,7 +1145,7 @@ int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
*/
void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
Table *pTab = pMod->pEpoTab;
if( (pTab = pMod->pEpoTab)!=0 ){
if( pTab!=0 ){
sqlite3DeleteColumnNames(db, pTab);
sqlite3VtabClear(db, pTab);
sqlite3DbFree(db, pTab);
+40 -17
View File
@@ -189,12 +189,12 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
while( pScan->iEquiv<=pScan->nEquiv ){
iCur = pScan->aiCur[pScan->iEquiv-1];
iColumn = pScan->aiColumn[pScan->iEquiv-1];
if( iColumn==(-2) && pScan->pIdxExpr==0 ) return 0;
if( iColumn==XN_EXPR && pScan->pIdxExpr==0 ) return 0;
while( (pWC = pScan->pWC)!=0 ){
for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
if( pTerm->leftCursor==iCur
&& pTerm->u.leftColumn==iColumn
&& (iColumn!=(-2)
&& (iColumn!=XN_EXPR
|| sqlite3ExprCompare(pTerm->pExpr->pLeft,pScan->pIdxExpr,iCur)==0)
&& (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
){
@@ -288,7 +288,7 @@ static WhereTerm *whereScanInit(
if( pIdx ){
j = iColumn;
iColumn = pIdx->aiColumn[j];
if( iColumn==(-2) ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
if( iColumn==XN_EXPR ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
}
if( pIdx && iColumn>=0 ){
pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
@@ -485,14 +485,20 @@ static LogEst estLog(LogEst N){
** Convert OP_Column opcodes to OP_Copy in previously generated code.
**
** This routine runs over generated VDBE code and translates OP_Column
** opcodes into OP_Copy, and OP_Rowid into OP_Null, when the table is being
** accessed via co-routine instead of via table lookup.
** opcodes into OP_Copy when the table is being accessed via co-routine
** instead of via table lookup.
**
** If the bIncrRowid parameter is 0, then any OP_Rowid instructions on
** cursor iTabCur are transformed into OP_Null. Or, if bIncrRowid is non-zero,
** then each OP_Rowid is transformed into an instruction to increment the
** value stored in its output register.
*/
static void translateColumnToCopy(
Vdbe *v, /* The VDBE containing code to translate */
int iStart, /* Translate from this opcode to the end */
int iTabCur, /* OP_Column/OP_Rowid references to this table */
int iRegister /* The first column is in this register */
int iRegister, /* The first column is in this register */
int bIncrRowid /* If non-zero, transform OP_rowid to OP_AddImm(1) */
){
VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart);
int iEnd = sqlite3VdbeCurrentAddr(v);
@@ -504,9 +510,16 @@ static void translateColumnToCopy(
pOp->p2 = pOp->p3;
pOp->p3 = 0;
}else if( pOp->opcode==OP_Rowid ){
pOp->opcode = OP_Null;
pOp->p1 = 0;
pOp->p3 = 0;
if( bIncrRowid ){
/* Increment the value stored in the P2 operand of the OP_Rowid. */
pOp->opcode = OP_AddImm;
pOp->p1 = pOp->p2;
pOp->p2 = 1;
}else{
pOp->opcode = OP_Null;
pOp->p1 = 0;
pOp->p3 = 0;
}
}
}
}
@@ -614,6 +627,8 @@ static void constructAutomaticIndex(
Expr *pPartial = 0; /* Partial Index Expression */
int iContinue = 0; /* Jump here to skip excluded rows */
struct SrcList_item *pTabItem; /* FROM clause term being indexed */
int addrCounter; /* Address where integer counter is initialized */
int regBase; /* Array of registers where record is assembled */
/* Generate code to skip over the creation and initialization of the
** transient index on 2nd and subsequent iterations of the loop. */
@@ -727,7 +742,7 @@ static void constructAutomaticIndex(
}
}
assert( n==nKeyCol );
pIdx->aiColumn[n] = -1;
pIdx->aiColumn[n] = XN_ROWID;
pIdx->azColl[n] = "BINARY";
/* Create the automatic index */
@@ -742,6 +757,7 @@ static void constructAutomaticIndex(
pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
if( pTabItem->fg.viaCoroutine ){
int regYield = pTabItem->regReturn;
addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
VdbeCoverage(v);
@@ -755,12 +771,15 @@ static void constructAutomaticIndex(
pLoop->wsFlags |= WHERE_PARTIALIDX;
}
regRecord = sqlite3GetTempReg(pParse);
sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0);
regBase = sqlite3GenerateIndexKey(
pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0
);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
if( pTabItem->fg.viaCoroutine ){
translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult);
sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult, 1);
sqlite3VdbeGoto(v, addrTop);
pTabItem->fg.viaCoroutine = 0;
}else{
@@ -2242,7 +2261,9 @@ static int whereLoopAddBtreeIndex(
int iCol = pProbe->aiColumn[saved_nEq];
pNew->wsFlags |= WHERE_COLUMN_EQ;
assert( saved_nEq==pNew->u.btree.nEq );
if( iCol==(-1) || (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1) ){
if( iCol==XN_ROWID
|| (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
){
if( iCol>=0 && pProbe->uniqNotNull==0 ){
pNew->wsFlags |= WHERE_UNQ_WANTED;
}else{
@@ -2442,7 +2463,7 @@ static int indexMightHelpWithOrderBy(
}
}else if( (aColExpr = pIndex->aColExpr)!=0 ){
for(jj=0; jj<pIndex->nKeyCol; jj++){
if( pIndex->aiColumn[jj]!=(-2) ) continue;
if( pIndex->aiColumn[jj]!=XN_EXPR ) continue;
if( sqlite3ExprCompare(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
return 1;
}
@@ -3230,7 +3251,8 @@ static i8 wherePathSatisfiesOrderBy(
nKeyCol = pIndex->nKeyCol;
nColumn = pIndex->nColumn;
assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) );
assert( pIndex->aiColumn[nColumn-1]==(-1) || !HasRowid(pIndex->pTable));
assert( pIndex->aiColumn[nColumn-1]==XN_ROWID
|| !HasRowid(pIndex->pTable));
isOrderDistinct = IsUniqueIndex(pIndex);
}
@@ -3262,7 +3284,7 @@ static i8 wherePathSatisfiesOrderBy(
revIdx = pIndex->aSortOrder[j];
if( iColumn==pIndex->pTable->iPKey ) iColumn = -1;
}else{
iColumn = -1;
iColumn = XN_ROWID;
revIdx = 0;
}
@@ -4506,7 +4528,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
*/
if( pTabItem->fg.viaCoroutine && !db->mallocFailed ){
translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur,
pTabItem->regResult);
pTabItem->regResult, 0);
continue;
}
@@ -4562,6 +4584,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
if( !HasRowid(pTab) ){
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
x = pPk->aiColumn[x];
assert( x>=0 );
}
x = sqlite3ColumnOfIndex(pIdx, x);
if( x>=0 ){
+8 -7
View File
@@ -46,8 +46,8 @@ static void explainAppendTerm(
*/
static const char *explainIndexColumnName(Index *pIdx, int i){
i = pIdx->aiColumn[i];
if( i==(-2) ) return "<expr>";
if( i==(-1) ) return "rowid";
if( i==XN_EXPR ) return "<expr>";
if( i==XN_ROWID ) return "rowid";
return pIdx->pTable->aCol[i].zName;
}
@@ -514,7 +514,7 @@ static int codeAllEqualityTerms(
sqlite3VdbeJumpHere(v, j);
for(j=0; j<nSkip; j++){
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, j, regBase+j);
testcase( pIdx->aiColumn[j]==(-2) );
testcase( pIdx->aiColumn[j]==XN_EXPR );
VdbeComment((v, "%s", explainIndexColumnName(pIdx, j)));
}
}
@@ -1266,7 +1266,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
int j1 = 0; /* Address of jump operation */
int jmp1 = 0; /* Address of jump operation */
if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){
pAndExpr->pLeft = pOrExpr;
pOrExpr = pAndExpr;
@@ -1293,7 +1293,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
if( HasRowid(pTab) ){
r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0);
j1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, r,iSet);
jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0,
r,iSet);
VdbeCoverage(v);
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
@@ -1323,7 +1324,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** need to insert the key into the temp table, as it will never
** be tested for. */
if( iSet ){
j1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk);
jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk);
VdbeCoverage(v);
}
if( iSet>=0 ){
@@ -1342,7 +1343,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
/* Jump here (skipping the main loop body subroutine) if the
** current sub-WHERE row is a duplicate from prior sub-WHEREs. */
if( j1 ) sqlite3VdbeJumpHere(v, j1);
if( jmp1 ) sqlite3VdbeJumpHere(v, jmp1);
/* The pSubWInfo->untestedTerms flag means that this OR term
** contained one or more AND term from a notReady table. The
-1
View File
@@ -950,7 +950,6 @@ static void exprAnalyze(
pNew = pTerm;
}
exprCommute(pParse, pDup);
pLeft = sqlite3ExprSkipCollate(pDup->pLeft);
pNew->leftCursor = iCur;
pNew->u.leftColumn = iColumn;
testcase( (prereqLeft | extraRight) != prereqLeft );
+21
View File
@@ -17,6 +17,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix autoindex5
# Schema is from the Debian security database
#
@@ -103,6 +104,26 @@ do_execsql_test autoindex5-1.1 {
OR sp.release = 'wheezy' OR sp.release = 'squeeze' )
ORDER BY sp.name, st.bug_name, sp.release, sp.subrelease;
} {/SEARCH SUBQUERY 2 USING AUTOMATIC COVERING INDEX .bug_name=/}
#-------------------------------------------------------------------------
# Test that ticket [8a2adec1] has been fixed.
#
do_execsql_test 2.1 {
CREATE TABLE one(o);
INSERT INTO one DEFAULT VALUES;
CREATE TABLE t1(x, z);
INSERT INTO t1 VALUES('aaa', 4.0);
INSERT INTO t1 VALUES('aaa', 4.0);
CREATE VIEW vvv AS
SELECT * FROM t1
UNION ALL
SELECT 0, 0 WHERE 0;
SELECT (
SELECT sum(z) FROM vvv WHERE x='aaa'
) FROM one;
} {8.0}
finish_test
+34
View File
@@ -151,4 +151,38 @@ do_execsql_test fkey1-4.2 {
PRAGMA table_info="""1";
} {0 {"2} TEXT 0 {} 1 1 {"3} TEXT 0 {} 0}
#-------------------------------------------------------------------------
#
do_execsql_test fkey1-5.1 {
CREATE TABLE t11(
x INTEGER PRIMARY KEY,
parent REFERENCES t11 ON DELETE CASCADE
);
INSERT INTO t11 VALUES (1, NULL), (2, 1), (3, 2);
} {}
# The REPLACE part of this statement deletes the row (2, 1). Then the
# DELETE CASCADE caused by deleting that row removes the (3, 2) row. Which
# would have been the parent of the new row being inserted. Causing an
# FK violation.
#
do_catchsql_test fkey1-5.2 {
INSERT OR REPLACE INTO t11 VALUES (2, 3);
} {1 {FOREIGN KEY constraint failed}}
# A similar test to the above.
do_execsql_test fkey1-5.3 {
CREATE TABLE Foo (
Id INTEGER PRIMARY KEY,
ParentId INTEGER REFERENCES Foo(Id) ON DELETE CASCADE, C1
);
INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (1, null, 'A');
INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (2, 1, 'A-2-1');
INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (3, 2, 'A-3-2');
INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (4, 3, 'A-4-3');
}
do_catchsql_test fkey1-5.4 {
INSERT OR REPLACE INTO Foo(Id, ParentId, C1) VALUES (2, 3, 'A-2-3');
} {1 {FOREIGN KEY constraint failed}}
finish_test
+34
View File
@@ -178,4 +178,38 @@ do_execsql_test 3.8 {
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
} {X'0200000002000000'}
#-------------------------------------------------------------------------
# Test that the xSavepoint is invoked correctly if the first write
# operation within a transaction is to a virtual table.
#
do_catchsql_test 4.1.1 {
CREATE VIRTUAL TABLE t0 USING fts4;
BEGIN;
INSERT INTO t0(rowid, content) SELECT
1, 'abc' UNION ALL SELECT
2, 'def' UNION ALL SELECT
1, 'ghi';
} {1 {constraint failed}}
do_execsql_test 4.1.2 {
COMMIT;
}
do_execsql_test 4.1.3 {
SELECT * FROM t0 WHERE t0 MATCH 'abc';
INSERT INTO t0(t0) VALUES('integrity-check');
} {}
do_execsql_test 4.2.1 {
CREATE VIRTUAL TABLE t01 USING fts4;
BEGIN;
SAVEPOINT abc;
INSERT INTO t01 VALUES('a b c');
ROLLBACK TO abc;
COMMIT;
}
do_execsql_test 4.2.2 {
SELECT * FROM t01 WHERE t01 MATCH 'b';
INSERT INTO t01(t01) VALUES('integrity-check');
} {}
finish_test
+32
View File
@@ -122,6 +122,8 @@ proc balanced_andor_tree {nEntry} {
return $tree
}
if 1 {
# Test that queries like "1 AND 2 AND 3 AND 4..." are transformed to
# balanced trees by FTS.
#
@@ -202,5 +204,35 @@ do_faultsim_test fts3expr3-fault-1 -faults oom-* -body {
faultsim_test_result [list 0 $::result]
}
}
#-------------------------------------------------------------------
foreach {tn expr res} {
1 {1 OR 2 OR 3 OR 4} {OR {OR {P 1} {P 2}} {OR {P 3} {P 4}}}
2 {1 OR (2 AND 3 AND 4 AND 5)}
{OR {P 1} {AND {AND {P 2} {P 3}} {AND {P 4} {P 5}}}}
3 {(2 AND 3 AND 4 AND 5) OR 1}
{OR {AND {AND {P 2} {P 3}} {AND {P 4} {P 5}}} {P 1}}
4 {1 AND (2 OR 3 OR 4 OR 5)}
{AND {P 1} {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}}}
5 {(2 OR 3 OR 4 OR 5) AND 1}
{AND {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}} {P 1}}
6 {(2 OR 3 OR 4 OR 5) NOT 1}
{NOT {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}} {P 1}}
7 {1 NOT (2 OR 3 OR 4 OR 5)}
{NOT {P 1} {OR {OR {P 2} {P 3}} {OR {P 4} {P 5}}}}
8 {(1 OR 2 OR 3 OR 4) NOT (5 AND 6 AND 7 AND 8)}
{NOT {OR {OR {P 1} {P 2}} {OR {P 3} {P 4}}} {AND {AND {P 5} {P 6}} {AND {P 7} {P 8}}}}
} {
do_test 5.1.$tn {
test_fts3expr2 $expr
} $res
}
set sqlite_fts3_enable_parentheses 0
finish_test
-7
View File
@@ -1051,7 +1051,6 @@ int main(int argc, char **argv){
/* Print the description, if there is one */
if( !quietFlag ){
int i;
zDbName = azSrcDb[iSrcDb];
i = strlen(zDbName) - 1;
while( i>0 && zDbName[i-1]!='/' && zDbName[i-1]!='\\' ){ i--; }
@@ -1127,12 +1126,6 @@ int main(int argc, char **argv){
}
rc = sqlite3_open_v2("main.db", &db, openFlags, zVfs);
if( rc ) fatalError("cannot open inmem database");
#ifdef SQLITE_ENABLE_JSON1
{
extern int sqlite3_json_init(sqlite3*);
sqlite3_json_init(db);
}
#endif
if( cellSzCkFlag ) runSql(db, "PRAGMA cell_size_check=ON", runFlags);
setAlarm(iTimeout);
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
BIN
View File
Binary file not shown.
+15
View File
@@ -62,6 +62,21 @@ do_execsql_test index3-2.2eqp {
EXPLAIN QUERY PLAN
SELECT a FROM t1 WHERE b='ab005xy' COLLATE nocase;
} {/USING INDEX/}
do_execsql_test index3-2.3 {
SELECT name FROM sqlite_master WHERE tbl_name='t1' ORDER BY name
} {sqlite_autoindex_t1_1 sqlite_autoindex_t1_2 t1 t1c t1d}
do_execsql_test index3-2.4 {
CREATE TABLE t2a(a integer, b, PRIMARY KEY(a));
CREATE TABLE t2b("a" integer, b, PRIMARY KEY("a"));
CREATE TABLE t2c([a] integer, b, PRIMARY KEY([a]));
CREATE TABLE t2d('a' integer, b, PRIMARY KEY('a'));
}
do_execsql_test index3-2.5 {
SELECT name FROM sqlite_master WHERE tbl_name LIKE 't2_' ORDER BY name
} {t2a t2b t2c t2d}
# This test corrupts the database file so it must be the last test
+5 -1
View File
@@ -15,7 +15,11 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
load_static_extension db json
ifcapable !json1 {
finish_test
return
}
do_execsql_test json101-1.1.00 {
SELECT json_array(1,2.5,null,'hello');
} {[1,2.5,null,"hello"]}
+5 -1
View File
@@ -18,7 +18,11 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
load_static_extension db json
ifcapable !json1 {
finish_test
return
}
do_execsql_test json102-100 {
SELECT json_object('ex','[52,3.14159]');
} {{{"ex":"[52,3.14159]"}}}
+161
View File
@@ -0,0 +1,161 @@
# 2015-10-06
#
# 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 test cases for the [b65cb2c8d91f6685841d7d1e13b6]
# bug: Correct handling of LIMIT and OFFSET on a UNION ALL query where
# the right-hand SELECT contains an ORDER BY in a subquery.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !compound {
finish_test
return
}
do_execsql_test offset1-1.1 {
CREATE TABLE t1(a,b);
INSERT INTO t1 VALUES(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e');
CREATE TABLE t2(x,y);
INSERT INTO t2 VALUES(8,'y'),(9,'z'),(6,'w'),(7,'x');
SELECT count(*) FROM t1, t2;
} {20}
do_execsql_test offset1-1.2.0 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 3 OFFSET 0;
} {1 a 2 b 3 c}
do_execsql_test offset1-1.2.1 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 3 OFFSET 1;
} {2 b 3 c 4 d}
do_execsql_test offset1-1.2.2 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 3 OFFSET 2;
} {3 c 4 d 5 e}
do_execsql_test offset1-1.2.3 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 3 OFFSET 3;
} {4 d 5 e 6 w}
do_execsql_test offset1-1.2.4 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 3 OFFSET 4;
} {5 e 6 w 7 x}
do_execsql_test offset1-1.2.5 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 3 OFFSET 5;
} {6 w 7 x 8 y}
do_execsql_test offset1-1.2.6 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 3 OFFSET 6;
} {7 x 8 y 9 z}
do_execsql_test offset1-1.2.7 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 3 OFFSET 7;
} {8 y 9 z}
do_execsql_test offset1-1.2.8 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 3 OFFSET 8;
} {9 z}
do_execsql_test offset1-1.2.9 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 3 OFFSET 9;
} {}
do_execsql_test offset1-1.3.0 {
SELECT * FROM t1 LIMIT 0;
} {}
do_execsql_test offset1-1.4.0 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 0 OFFSET 1;
} {}
do_execsql_test offset1-1.4.1 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 1 OFFSET 1;
} {2 b}
do_execsql_test offset1-1.4.2 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 2 OFFSET 1;
} {2 b 3 c}
do_execsql_test offset1-1.4.3 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 3 OFFSET 1;
} {2 b 3 c 4 d}
do_execsql_test offset1-1.4.4 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 4 OFFSET 1;
} {2 b 3 c 4 d 5 e}
do_execsql_test offset1-1.4.5 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 5 OFFSET 1;
} {2 b 3 c 4 d 5 e 6 w}
do_execsql_test offset1-1.4.6 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 6 OFFSET 1;
} {2 b 3 c 4 d 5 e 6 w 7 x}
do_execsql_test offset1-1.4.7 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 7 OFFSET 1;
} {2 b 3 c 4 d 5 e 6 w 7 x 8 y}
do_execsql_test offset1-1.4.8 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 8 OFFSET 1;
} {2 b 3 c 4 d 5 e 6 w 7 x 8 y 9 z}
do_execsql_test offset1-1.4.9 {
SELECT a, b FROM t1
UNION ALL
SELECT * FROM (SELECT x, y FROM t2 ORDER BY y)
LIMIT 9 OFFSET 1;
} {2 b 3 c 4 d 5 e 6 w 7 x 8 y 9 z}
finish_test
+8
View File
@@ -78,6 +78,7 @@ array set ::Configs [strip_comments {
-DSQLITE_DEFAULT_FILE_FORMAT=4
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
-DSQLITE_ENABLE_STMT_SCANSTATUS
--enable-json1
}
"Check-Symbols" {
-DSQLITE_MEMDEBUG=1
@@ -95,6 +96,7 @@ array set ::Configs [strip_comments {
-DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_STMT_SCANSTATUS
--enable-json1 --enable-fts5
}
"Debug-One" {
--disable-shared
@@ -135,6 +137,7 @@ array set ::Configs [strip_comments {
-DSQLITE_OMIT_PROGRESS_CALLBACK=1
-DSQLITE_OMIT_VIRTUALTABLE=1
-DSQLITE_TEMP_STORE=3
--enable-json1
}
"Device-Two" {
-DSQLITE_4_BYTE_ALIGNED_MALLOC=1
@@ -152,6 +155,7 @@ array set ::Configs [strip_comments {
-DSQLITE_OMIT_TRACE=1
-DSQLITE_TEMP_STORE=3
-DSQLITE_THREADSAFE=2
--enable-json1 --enable-fts5
}
"Locking-Style" {
-O2
@@ -163,6 +167,7 @@ array set ::Configs [strip_comments {
-DSQLITE_DEFAULT_MEMSTATUS=0
-DSQLITE_THREADSAFE=2
-DSQLITE_OS_UNIX=1
-DSQLITE_ENABLE_JSON1=1
-DSQLITE_ENABLE_LOCKING_STYLE=1
-DUSE_PREAD=1
-DSQLITE_ENABLE_RTREE=1
@@ -174,6 +179,7 @@ array set ::Configs [strip_comments {
-DSQLITE_DEBUG=1
-DSQLITE_PREFER_PROXY_LOCKING=1
-DSQLITE_ENABLE_API_ARMOR=1
--enable-json1 --enable-fts5
}
"Extra-Robustness" {
-DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
@@ -187,6 +193,7 @@ array set ::Configs [strip_comments {
-DSQLITE_ENABLE_FTS4_PARENTHESIS
-DSQLITE_DISABLE_FTS4_DEFERRED
-DSQLITE_ENABLE_RTREE
--enable-json1 --enable-fts5
}
"No-lookaside" {
-DSQLITE_TEST_REALLOC_STRESS=1
@@ -197,6 +204,7 @@ array set ::Configs [strip_comments {
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_FTS4
-DSQLITE_ENABLE_RTREE
--enable-json1
}
# The next group of configurations are used only by the
+30 -28
View File
@@ -76,40 +76,42 @@ do_execsql_test 1.5 {
do_execsql_test 1.6 {
SELECT word, distance, matchlen FROM demo
WHERE word MATCH 'amstedam*' AND distance <= 100;
WHERE word MATCH 'amstedam*' AND distance <= 100
ORDER BY distance, word;
} {
amsterdam 100 9 amsterdamh 100 9
amsterdamm 100 9 amsterdamn 100 9
amsterdama 100 9 amsterdame 100 9
amsterdami 100 9 amsterdamo 100 9
amsterdamu 100 9 amsterdamy 100 9
amsterdammetje 100 9 amsterdamania 100 9
amsterdamb 100 9 amsterdamf 100 9
amsterdamp 100 9 amsterdamv 100 9
amsterdamw 100 9 amsterdamweg 100 9
amsterdamc 100 9 amsterdamg 100 9
amsterdamj 100 9 amsterdamk 100 9
amsterdamq 100 9 amsterdams 100 9
amsterdamx 100 9 amsterdamz 100 9
amsterdamsestraat 100 9 amsterdamd 100 9
amsterdamt 100 9 amsterdaml 100 9
amsterdamlaan 100 9 amsterdamr 100 9
amsterdam 100 9 amsterdama 100 9
amsterdamania 100 9 amsterdamb 100 9
amsterdamc 100 9 amsterdamd 100 9
amsterdame 100 9 amsterdamf 100 9
amsterdamg 100 9 amsterdamh 100 9
amsterdami 100 9 amsterdamj 100 9
amsterdamk 100 9 amsterdaml 100 9
amsterdamlaan 100 9 amsterdamm 100 9
amsterdammetje 100 9 amsterdamn 100 9
amsterdamo 100 9 amsterdamp 100 9
amsterdamq 100 9 amsterdamr 100 9
amsterdams 100 9 amsterdamsestraat 100 9
amsterdamt 100 9 amsterdamu 100 9
amsterdamv 100 9 amsterdamw 100 9
amsterdamweg 100 9 amsterdamx 100 9
amsterdamy 100 9 amsterdamz 100 9
}
do_execsql_test 1.7 {
SELECT word, distance, matchlen FROM demo
WHERE word MATCH 'amstedam*' AND distance <= 100 AND top=20;
WHERE word MATCH 'amstedam*' AND distance <= 100 AND top=20
ORDER BY distance, word;
} {
amsterdam 100 9 amsterdamh 100 9
amsterdamm 100 9 amsterdamn 100 9
amsterdama 100 9 amsterdame 100 9
amsterdami 100 9 amsterdamo 100 9
amsterdamu 100 9 amsterdamy 100 9
amsterdammetje 100 9 amsterdamania 100 9
amsterdamb 100 9 amsterdamf 100 9
amsterdamp 100 9 amsterdamv 100 9
amsterdamw 100 9 amsterdamweg 100 9
amsterdamc 100 9 amsterdamg 100 9
amsterdam 100 9 amsterdama 100 9
amsterdamania 100 9 amsterdamb 100 9
amsterdamc 100 9 amsterdame 100 9
amsterdamf 100 9 amsterdamg 100 9
amsterdamh 100 9 amsterdami 100 9
amsterdamm 100 9 amsterdammetje 100 9
amsterdamn 100 9 amsterdamo 100 9
amsterdamp 100 9 amsterdamu 100 9
amsterdamv 100 9 amsterdamw 100 9
amsterdamweg 100 9 amsterdamy 100 9
}
+5 -1
View File
@@ -75,8 +75,12 @@ do_execsql_test tabfunc01-2.1 {
INSERT INTO t1(x) VALUES(2),(3);
SELECT *, '|' FROM t1, generate_series(1,x) ORDER BY 1, 2
} {2 1 | 2 2 | 3 1 | 3 2 | 3 3 |}
do_execsql_test tabfunc01-2.2 {
SELECT *, '|' FROM (SELECT x FROM t1) AS y, generate_series(1,y.x)
ORDER BY 1, 2;
} {2 1 | 2 2 | 3 1 | 3 2 | 3 3 |}
do_execsql_test tabfunc01-2.50 {
SELECT * FROM generate_series() LIMIT 5;
} {0 1 2 3 4}
+8
View File
@@ -63,6 +63,14 @@ foreach {tn uri file} {
#
if {$tn>14} break
#
# NOTE: When running on Tcl 8.6 (or higher?) on Windows, a colon within
# the file name no longer tries to access an alternate data stream
# (ADS) named "test.db" for the "http" file, causing some spurious
# failures of this test.
#
if {$tn==12 && $::tcl_version>=8.6} continue
#
# NOTE: On Windows, we need to account for the fact that the current
# directory does not start with a forward slash.
+7
View File
@@ -499,6 +499,13 @@ do_test view-14.1 {
SELECT * FROM temp.t1;
}
} {1 {view t1 is circularly defined}}
do_test view-14.2 {
catchsql {
DROP VIEW IF EXISTS temp.t1;
CREATE TEMP VIEW t1(a,b) AS SELECT a,b FROM t1;
SELECT * FROM temp.t1;
}
} {1 {view t1 is circularly defined}}
# Tickets #1688, #1709
#
-44
View File
@@ -1,44 +0,0 @@
/*
** A utility for printing the differences between two SQLite database files.
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define PAGESIZE 1024
static int db1 = -1;
static int db2 = -1;
int main(int argc, char **argv){
int iPg;
unsigned char a1[PAGESIZE], a2[PAGESIZE];
if( argc!=3 ){
fprintf(stderr,"Usage: %s FILENAME FILENAME\n", argv[0]);
exit(1);
}
db1 = open(argv[1], O_RDONLY);
if( db1<0 ){
fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]);
exit(1);
}
db2 = open(argv[2], O_RDONLY);
if( db2<0 ){
fprintf(stderr,"%s: can't open %s\n", argv[0], argv[2]);
exit(1);
}
iPg = 1;
while( read(db1, a1, PAGESIZE)==PAGESIZE && read(db2,a2,PAGESIZE)==PAGESIZE ){
if( memcmp(a1,a2,PAGESIZE) ){
printf("Page %d\n", iPg);
}
iPg++;
}
printf("%d pages checked\n", iPg-1);
close(db1);
close(db2);
}
-6
View File
@@ -726,12 +726,6 @@ int main(int argc, char **argv){
#ifndef SQLITE_OMIT_TRACE
sqlite3_trace(db, verboseFlag ? traceCallback : traceNoop, 0);
#endif
#ifdef SQLITE_ENABLE_JSON1
{
extern int sqlite3_json_init(sqlite3*);
sqlite3_json_init(db);
}
#endif
sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0);
sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0);
sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 1000000);
+4 -1
View File
@@ -211,7 +211,8 @@ proc copy_file {filename} {
puts $out "#if 0"
} elseif {!$linemacros && [regexp {^#line} $line]} {
# Skip #line directives.
} elseif {$addstatic && ![regexp {^(static|typedef)} $line]} {
} elseif {$addstatic
&& ![regexp {^(static|typedef|SQLITE_PRIVATE)} $line]} {
# Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before
# functions if this header file does not need it.
if {![info exists varonly_hdr($tail)]
@@ -378,6 +379,8 @@ foreach file {
fts3_icu.c
sqlite3rbu.c
dbstat.c
json1.c
fts5.c
} {
copy_file tsrc/$file
}
+2 -1
View File
@@ -71,6 +71,7 @@ fconfigure stdout -translation lf
set filelist [subst {
$TOP/src/sqlite.h.in
$TOP/ext/rtree/sqlite3rtree.h
$TOP/ext/fts5/fts5.h
}]
# These are the functions that accept a variable number of arguments. They
@@ -97,7 +98,7 @@ foreach file $filelist {
# File sqlite3rtree.h contains a line "#include <sqlite3.h>". Omit this
# line when copying sqlite3rtree.h into sqlite3.h.
#
if {[string match {*#include*<sqlite3.h>*} $line]} continue
if {[string match {*#include*[<"]sqlite3.h[>"]*} $line]} continue
regsub -- --VERS-- $line $zVersion line
regsub -- --VERSION-NUMBER-- $line $nVersion line
-23
View File
@@ -1,23 +0,0 @@
#
# Extract opcode documentation for sqliteVdbe.c and generate HTML
#
BEGIN {
print "<html><body bgcolor=white>"
print "<h1>SQLite Virtual Database Engine Opcodes</h1>"
print "<table>"
}
/ Opcode: /,/\*\// {
if( $2=="Opcode:" ){
printf "<tr><td>%s&nbsp;%s&nbsp;%s&nbsp;%s</td>\n<td>\n", $3, $4, $5, $6
}else if( $1=="*/" ){
printf "</td></tr>\n"
}else if( NF>1 ){
sub(/^ *\*\* /,"")
gsub(/</,"&lt;")
gsub(/&/,"&amp;")
print
}
}
END {
print "</table></body></html>"
}
-111
View File
@@ -1,111 +0,0 @@
# Run this TCL script using "testfixture" in order get a report that shows
# how much disk space is used by a particular data to actually store data
# versus how much space is unused.
#
# Get the name of the database to analyze
#
if {[llength $argv]!=1} {
puts stderr "Usage: $argv0 database-name"
exit 1
}
set file_to_analyze [lindex $argv 0]
# Open the database
#
sqlite db [lindex $argv 0]
set DB [btree_open [lindex $argv 0]]
# Output the schema for the generated report
#
puts \
{BEGIN;
CREATE TABLE space_used(
name clob, -- Name of a table or index in the database file
is_index boolean, -- TRUE if it is an index, false for a table
payload int, -- Total amount of data stored in this table or index
pri_pages int, -- Number of primary pages used
ovfl_pages int, -- Number of overflow pages used
pri_unused int, -- Number of unused bytes on primary pages
ovfl_unused int -- Number of unused bytes on overflow pages
);}
# This query will be used to find the root page number for every index and
# table in the database.
#
set sql {
SELECT name, type, rootpage FROM sqlite_master
UNION ALL
SELECT 'sqlite_master', 'table', 2
ORDER BY 1
}
# Initialize variables used for summary statistics.
#
set total_size 0
set total_primary 0
set total_overflow 0
set total_unused_primary 0
set total_unused_ovfl 0
# Analyze every table in the database, one at a time.
#
foreach {name type rootpage} [db eval $sql] {
set cursor [btree_cursor $DB $rootpage 0]
set go [btree_first $cursor]
set size 0
catch {unset pg_used}
set unused_ovfl 0
set n_overflow 0
while {$go==0} {
set payload [btree_payload_size $cursor]
incr size $payload
set stat [btree_cursor_dump $cursor]
set pgno [lindex $stat 0]
set freebytes [lindex $stat 4]
set pg_used($pgno) $freebytes
if {$payload>238} {
set n [expr {($payload-238+1019)/1020}]
incr n_overflow $n
incr unused_ovfl [expr {$n*1020+238-$payload}]
}
set go [btree_next $cursor]
}
btree_close_cursor $cursor
set n_primary [llength [array names pg_used]]
set unused_primary 0
foreach x [array names pg_used] {incr unused_primary $pg_used($x)}
regsub -all ' $name '' name
puts -nonewline "INSERT INTO space_used VALUES('$name'"
puts -nonewline ",[expr {$type=="index"}]"
puts ",$size,$n_primary,$n_overflow,$unused_primary,$unused_ovfl);"
incr total_size $size
incr total_primary $n_primary
incr total_overflow $n_overflow
incr total_unused_primary $unused_primary
incr total_unused_ovfl $unused_ovfl
}
# Output summary statistics:
#
puts "-- Total payload size: $total_size"
puts "-- Total pages used: $total_primary primary and $total_overflow overflow"
set file_pgcnt [expr {[file size [lindex $argv 0]]/1024}]
puts -nonewline "-- Total unused bytes on primary pages: $total_unused_primary"
if {$total_primary>0} {
set upp [expr {$total_unused_primary/$total_primary}]
puts " (avg $upp bytes/page)"
} else {
puts ""
}
puts -nonewline "-- Total unused bytes on overflow pages: $total_unused_ovfl"
if {$total_overflow>0} {
set upp [expr {$total_unused_ovfl/$total_overflow}]
puts " (avg $upp bytes/page)"
} else {
puts ""
}
set n_free [expr {$file_pgcnt-$total_primary-$total_overflow}]
if {$n_free>0} {incr n_free -1}
puts "-- Total pages on freelist: $n_free"
puts "COMMIT;"