mirror of
https://github.com/status-im/sqlcipher.git
synced 2026-08-31 14:31:11 +00:00
Merge branch 'prerelease'
This commit is contained in:
+84
-42
@@ -1,16 +1,27 @@
|
||||
# SQLCipher Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [unreleased] - [unreleased]
|
||||
## [4.1.0] - (March 2019 - [4.1.0 changes])
|
||||
- Defer reading salt from header until key derivation is triggered
|
||||
- Clarify usage of sqlite3_rekey for plaintext databases in header
|
||||
- Normalize attach behavior when key is not yet derived
|
||||
- Adds PRAGMA cipher_settings to query current database codec settings
|
||||
- Adds PRAGMA cipher_default_settings to query current default SQLCipher options
|
||||
- PRAGMA cipher_hmac_pgno is now deprecated
|
||||
- PRAGMA cipher_hmac_salt_mask is now deprecated
|
||||
- PRAGMA fast_kdf_iter is now deprecated
|
||||
- Clear codec data buffers if a crypographic provider operation fails
|
||||
- Disable backup API for encrypted databases (this was previously documented as not-working and non-supported, but will now explicitly error out on initialization)
|
||||
- Updates baseline to upstream SQLite 3.27.2
|
||||
|
||||
## [4.0.1] - 2018-12-17
|
||||
## [4.0.1] - (December 2018 - [4.0.1 changes])
|
||||
- Based on upstream SQLite 3.26.0 (addresses SQLite “Magellan” issue)
|
||||
- Adds PRAGMA cipher_compatibility and cipher_default_compatibility which take automatcially configure appropriate compatibility settings for the specified SQLCipher major version number
|
||||
- Filters attach statements with KEY parameters from readline history
|
||||
- Fixes crash in command line shell with empty input (i.e. ^D)
|
||||
- Fixes warnings when compiled with strict-prototypes
|
||||
|
||||
## [4.0.0] - 2018-11-30
|
||||
## [4.0.0] - (November 2018 - [4.0.0 changes])
|
||||
### Changed
|
||||
- Default page size for databases increased to 4096 bytes (up from 1024) *
|
||||
- Default PBKDF2 iterations increased to 256,000 (up from 64,000) *
|
||||
@@ -43,7 +54,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Fixes compilation with --disable-amalgamation
|
||||
- Removes sqlcipher.xcodeproj build support
|
||||
|
||||
## [3.4.2] - 2017-12-21
|
||||
## [3.4.2] - (December 2017 - [3.4.2 changes])
|
||||
### Added
|
||||
- Added support for building with LibreSSL
|
||||
|
||||
@@ -58,14 +69,14 @@ All notable changes to this project will be documented in this file.
|
||||
- Guard OpenSSL initialization and cleanup routines
|
||||
- Allow additional linker options to be passed via command line for Windows platforms
|
||||
|
||||
## [3.4.1] - 2016-12-28
|
||||
## [3.4.1] - (December 2016 - [3.4.1 changes])
|
||||
### Added
|
||||
- Added support for OpenSSL 1.1.0
|
||||
|
||||
### Changed
|
||||
- Merged upstream SQLite 3.15.2
|
||||
|
||||
## [3.4.0] - 2016-04-05
|
||||
## [3.4.0] - (April 2016 - [3.4.0 changes])
|
||||
### Added
|
||||
- Added `PRAGMA cipher_provider_version`
|
||||
|
||||
@@ -75,14 +86,14 @@ All notable changes to this project will be documented in this file.
|
||||
### Deprecated
|
||||
- Deprecated `PRAGMA cipher` command
|
||||
|
||||
## [3.3.1] - 2015-07-13
|
||||
## [3.3.1] - (July 2015 - [3.3.1 changes])
|
||||
### Changed
|
||||
- Merge upstream SQLite 3.8.10.2
|
||||
- Fixed segfault when provided an invalid cipher name
|
||||
- Check for codec context when performing `PRAGMA cipher_store_pass`
|
||||
- Remove extraneous null check in `PRAGMA cipher_migrate`
|
||||
|
||||
## [3.3.0] - 2015-03-25
|
||||
## [3.3.0] - (March 2015 - [3.3.0 changes])
|
||||
### Added
|
||||
- Added FIPS API calls within the OpenSSL crypto provider
|
||||
- `PRAGMA cipher_default_page_size` - support for attaching non-default page sizes
|
||||
@@ -90,7 +101,7 @@ All notable changes to this project will be documented in this file.
|
||||
### Changed
|
||||
- Merged upstream SQLite 3.8.8.3
|
||||
|
||||
## [3.2.0] - 2014-09-30
|
||||
## [3.2.0] - (September 2014 - [3.2.0 changes])
|
||||
### Added
|
||||
- Added `PRAGMA cipher_store_pass`
|
||||
|
||||
@@ -98,14 +109,14 @@ All notable changes to this project will be documented in this file.
|
||||
- Merged upstream SQLite 3.8.6
|
||||
- Renmed README to README.md
|
||||
|
||||
## [3.1.0] - 2014-04-23
|
||||
## [3.1.0] - (April 2014 - [3.1.0 changes])
|
||||
### Added
|
||||
- Added `PRAGMA cipher_profile`
|
||||
|
||||
### Changed
|
||||
- Merged upstream SQLite 3.8.4.3
|
||||
|
||||
## [3.0.1] - 2013-12-06
|
||||
## [3.0.1] - (December 2013 - [3.0.1 changes])
|
||||
### Added
|
||||
- Added `PRAGMA cipher_add_random` to source external entropy
|
||||
|
||||
@@ -113,7 +124,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Fix `PRAGMA cipher_migrate` to handle passphrases longer than 64 characters & raw keys
|
||||
- Improvements to the libtomcrypt provider
|
||||
|
||||
## [3.0.0] - 2013-11-05
|
||||
## [3.0.0] - (November 2013 - [3.0.0 changes])
|
||||
### Added
|
||||
- Added `PRAGMA cipher_migrate` to migrate older database file formats
|
||||
|
||||
@@ -128,33 +139,64 @@ All notable changes to this project will be documented in this file.
|
||||
### Security
|
||||
- Change KDF iteration length from 4,000 to 64,000
|
||||
|
||||
[unreleased]: https://github.com/sqlcipher/sqlcipher/compare/v4.0.1...prerelease
|
||||
[4.0.1]: https://github.com/sqlcipher/sqlcipher/compare/v4.0.0...v4.0.1
|
||||
[4.0.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.4.2...v4.0.0
|
||||
[3.4.2]: https://github.com/sqlcipher/sqlcipher/compare/v3.4.1...v3.4.2
|
||||
[3.4.1]: https://github.com/sqlcipher/sqlcipher/compare/v3.4.0...v3.4.1
|
||||
[3.4.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.1...v3.4.0
|
||||
[3.3.1]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.0...v3.3.1
|
||||
[3.3.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.2.0...v3.3.0
|
||||
[3.2.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.1.0...v3.2.0
|
||||
[3.1.0]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.1...v3.1.0
|
||||
[3.0.1]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.0...v3.0.1
|
||||
[3.0.0]: https://github.com/sqlcipher/sqlcipher/compare/v2.2.0...v3.0.0
|
||||
[2.2.0]: https://github.com/sqlcipher/sqlcipher/compare/v2.1.1...v2.2.0
|
||||
[2.1.1]: https://github.com/sqlcipher/sqlcipher/compare/v2.1.0...v2.1.1
|
||||
[2.1.0]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.6...v2.1.0
|
||||
[2.0.6]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.5...v2.0.6
|
||||
[2.0.5]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.3...v2.0.5
|
||||
[2.0.3]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.0...v2.0.3
|
||||
[2.0.0]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.10...v2.0.0
|
||||
[1.1.10]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.9...v1.1.10
|
||||
[1.1.9]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.8...v1.1.9
|
||||
[1.1.8]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.7...v1.1.8
|
||||
[1.1.7]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.6...v1.1.7
|
||||
[1.1.6]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.5...v1.1.6
|
||||
[1.1.5]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.4...v1.1.5
|
||||
[1.1.4]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.3...v1.1.4
|
||||
[1.1.3]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.2...v1.1.3
|
||||
[1.1.2]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.1...v1.1.1
|
||||
[1.1.1]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.0...v1.1.1
|
||||
[1.1.0]: https://github.com/sqlcipher/sqlcipher/compare/617ed01...v1.1.0
|
||||
[unreleased]: https://github.com/sqlcipher/sqlcipher/compare/v4.1.0...prerelease
|
||||
[4.1.0]: https://github.com/sqlcipher/sqlcipher/tree/v4.1.0
|
||||
[4.1.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v4.0.1...v4.1.0
|
||||
[4.0.1]: https://github.com/sqlcipher/sqlcipher/tree/v4.0.1
|
||||
[4.0.1 changes]: https://github.com/sqlcipher/sqlcipher/compare/v4.0.0...v4.0.1
|
||||
[4.0.0]: https://github.com/sqlcipher/sqlcipher/tree/v4.0.0
|
||||
[4.0.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v3.4.2...v4.0.0
|
||||
[3.4.2]: https://github.com/sqlcipher/sqlcipher/tree/v3.4.2
|
||||
[3.4.2 changes]: https://github.com/sqlcipher/sqlcipher/compare/v3.4.1...v3.4.2
|
||||
[3.4.1]: https://github.com/sqlcipher/sqlcipher/tree/v3.4.1
|
||||
[3.4.1 changes]: https://github.com/sqlcipher/sqlcipher/compare/v3.4.0...v3.4.1
|
||||
[3.4.0]: https://github.com/sqlcipher/sqlcipher/tree/v3.4.0
|
||||
[3.4.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.1...v3.4.0
|
||||
[3.3.1]: https://github.com/sqlcipher/sqlcipher/tree/v3.3.1
|
||||
[3.3.1 changes]: https://github.com/sqlcipher/sqlcipher/compare/v3.3.0...v3.3.1
|
||||
[3.3.0]: https://github.com/sqlcipher/sqlcipher/tree/v3.3.0
|
||||
[3.3.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v3.2.0...v3.3.0
|
||||
[3.2.0]: https://github.com/sqlcipher/sqlcipher/tree/v3.2.0
|
||||
[3.2.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v3.1.0...v3.2.0
|
||||
[3.1.0]: https://github.com/sqlcipher/sqlcipher/tree/v3.1.0
|
||||
[3.1.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.1...v3.1.0
|
||||
[3.0.1]: https://github.com/sqlcipher/sqlcipher/tree/v3.0.1
|
||||
[3.0.1 changes]: https://github.com/sqlcipher/sqlcipher/compare/v3.0.0...v3.0.1
|
||||
[3.0.0]: https://github.com/sqlcipher/sqlcipher/tree/v3.0.0
|
||||
[3.0.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v2.2.0...v3.0.0
|
||||
[2.2.0]: https://github.com/sqlcipher/sqlcipher/tree/v2.2.0
|
||||
[2.2.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v2.1.1...v2.2.0
|
||||
[2.1.1]: https://github.com/sqlcipher/sqlcipher/tree/v2.1.1
|
||||
[2.1.1 changes]: https://github.com/sqlcipher/sqlcipher/compare/v2.1.0...v2.1.1
|
||||
[2.1.0]: https://github.com/sqlcipher/sqlcipher/tree/v2.1.0
|
||||
[2.1.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.6...v2.1.0
|
||||
[2.0.6]: https://github.com/sqlcipher/sqlcipher/tree/v2.0.6
|
||||
[2.0.6 changes]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.5...v2.0.6
|
||||
[2.0.5]: https://github.com/sqlcipher/sqlcipher/tree/v2.0.5
|
||||
[2.0.5 changes]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.3...v2.0.5
|
||||
[2.0.3]: https://github.com/sqlcipher/sqlcipher/tree/v2.0.3
|
||||
[2.0.3 changes]: https://github.com/sqlcipher/sqlcipher/compare/v2.0.0...v2.0.3
|
||||
[2.0.0]: https://github.com/sqlcipher/sqlcipher/tree/v2.0.0
|
||||
[2.0.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.10...v2.0.0
|
||||
[1.1.10]: https://github.com/sqlcipher/sqlcipher/tree/v1.1.10
|
||||
[1.1.10 changes]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.9...v1.1.10
|
||||
[1.1.9]: https://github.com/sqlcipher/sqlcipher/tree/v1.1.9
|
||||
[1.1.9 changes]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.8...v1.1.9
|
||||
[1.1.8]: https://github.com/sqlcipher/sqlcipher/tree/v1.1.8
|
||||
[1.1.8 changes]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.7...v1.1.8
|
||||
[1.1.7]: https://github.com/sqlcipher/sqlcipher/tree/v1.1.7
|
||||
[1.1.7 changes]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.6...v1.1.7
|
||||
[1.1.6]: https://github.com/sqlcipher/sqlcipher/tree/v1.1.6
|
||||
[1.1.6 changes]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.5...v1.1.6
|
||||
[1.1.5]: https://github.com/sqlcipher/sqlcipher/tree/v1.1.5
|
||||
[1.1.5 changes]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.4...v1.1.5
|
||||
[1.1.4]: https://github.com/sqlcipher/sqlcipher/tree/v1.1.4
|
||||
[1.1.4 changes]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.3...v1.1.4
|
||||
[1.1.3]: https://github.com/sqlcipher/sqlcipher/tree/v1.1.3
|
||||
[1.1.3 changes]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.2...v1.1.3
|
||||
[1.1.2]: https://github.com/sqlcipher/sqlcipher/tree/v1.1.2
|
||||
[1.1.2 changes]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.1...v1.1.1
|
||||
[1.1.1]: https://github.com/sqlcipher/sqlcipher/tree/v1.1.1
|
||||
[1.1.1 changes]: https://github.com/sqlcipher/sqlcipher/compare/v1.1.0...v1.1.1
|
||||
[1.1.0]: https://github.com/sqlcipher/sqlcipher/tree/v1.1.0
|
||||
[1.1.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/617ed01...v1.1.0
|
||||
|
||||
+37
-6
@@ -472,6 +472,7 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/nextchar.c \
|
||||
$(TOP)/ext/misc/normalize.c \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/prefixes.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/remember.c \
|
||||
$(TOP)/ext/misc/series.c \
|
||||
@@ -608,7 +609,8 @@ FUZZDATA = \
|
||||
$(TOP)/test/fuzzdata4.db \
|
||||
$(TOP)/test/fuzzdata5.db \
|
||||
$(TOP)/test/fuzzdata6.db \
|
||||
$(TOP)/test/fuzzdata7.db
|
||||
$(TOP)/test/fuzzdata7.db \
|
||||
$(TOP)/test/fuzzdata8.db
|
||||
|
||||
# Standard options to testfixture
|
||||
#
|
||||
@@ -631,6 +633,12 @@ FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
|
||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_DESERIALIZE
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4
|
||||
#FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS5
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c
|
||||
DBFUZZ_OPT =
|
||||
|
||||
@@ -689,7 +697,7 @@ ossshell$(TEXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.
|
||||
$(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS)
|
||||
|
||||
sessionfuzz$(TEXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h
|
||||
$(CC) $(CFLAGS) -I. -o $@ $(TOP)/test/sessionfuzz.c $(TLIBS)
|
||||
$(LTLINK) -o $@ $(TOP)/test/sessionfuzz.c $(TLIBS)
|
||||
|
||||
dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h
|
||||
$(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS)
|
||||
@@ -702,11 +710,26 @@ DBFUZZ2_OPTS = \
|
||||
-DSQLITE_ENABLE_DBSTAT_VTAB \
|
||||
-DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_ENABLE_FTS4 \
|
||||
-DSQLITE_EANBLE_FTS5
|
||||
-DSQLITE_ENABLE_FTS5
|
||||
|
||||
dbfuzz2: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
|
||||
clang-6.0 -I. -g -O0 -fsanitize=fuzzer,undefined,address -o dbfuzz2 \
|
||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c
|
||||
dbfuzz2$(TEXE): $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
|
||||
$(CC) $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \
|
||||
-DSTANDALONE -o dbfuzz2 \
|
||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS)
|
||||
mkdir -p dbfuzz2-dir
|
||||
cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
|
||||
|
||||
dbfuzz2-asan: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
|
||||
clang-6.0 $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \
|
||||
-fsanitize=fuzzer,undefined,address -o dbfuzz2-asan \
|
||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS)
|
||||
mkdir -p dbfuzz2-dir
|
||||
cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
|
||||
|
||||
dbfuzz2-msan: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
|
||||
clang-6.0 $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \
|
||||
-fsanitize=fuzzer,undefined,memory -o dbfuzz2-msan \
|
||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS)
|
||||
mkdir -p dbfuzz2-dir
|
||||
cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
|
||||
|
||||
@@ -1085,6 +1108,7 @@ SHELL_SRC = \
|
||||
$(TOP)/ext/expert/sqlite3expert.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.h \
|
||||
$(TOP)/ext/misc/zipfile.c \
|
||||
$(TOP)/ext/misc/memtrace.c \
|
||||
$(TOP)/src/test_windirent.c
|
||||
|
||||
shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
|
||||
@@ -1222,6 +1246,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DESERIALIZE
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlcipher.la
|
||||
TESTFIXTURE_SRC1 = sqlite3.c
|
||||
@@ -1324,6 +1349,9 @@ dbdump$(TEXE): $(TOP)/ext/misc/dbdump.c sqlite3.lo
|
||||
$(LTLINK) -DDBDUMP_STANDALONE -o $@ \
|
||||
$(TOP)/ext/misc/dbdump.c sqlite3.lo $(TLIBS)
|
||||
|
||||
dbtotxt$(TEXE): $(TOP)/tool/dbtotxt.c
|
||||
$(LTLINK)-o $@ $(TOP)/tool/dbtotxt.c
|
||||
|
||||
showdb$(TEXE): $(TOP)/tool/showdb.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/tool/showdb.c sqlite3.lo $(TLIBS)
|
||||
|
||||
@@ -1339,6 +1367,9 @@ showwal$(TEXE): $(TOP)/tool/showwal.c sqlite3.lo
|
||||
showshm$(TEXE): $(TOP)/tool/showshm.c
|
||||
$(LTLINK) -o $@ $(TOP)/tool/showshm.c
|
||||
|
||||
index_usage$(TEXE): $(TOP)/tool/index_usage.c sqlite3.lo
|
||||
$(LTLINK) $(SHELL_OPT) -o $@ $(TOP)/tool/index_usage.c sqlite3.lo $(TLIBS)
|
||||
|
||||
changeset$(TEXE): $(TOP)/ext/session/changeset.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/ext/session/changeset.c sqlite3.lo $(TLIBS)
|
||||
|
||||
|
||||
+21
-4
@@ -1534,6 +1534,7 @@ TESTEXT = \
|
||||
$(TOP)\ext\misc\nextchar.c \
|
||||
$(TOP)\ext\misc\normalize.c \
|
||||
$(TOP)\ext\misc\percentile.c \
|
||||
$(TOP)\ext\misc\prefixes.c \
|
||||
$(TOP)\ext\misc\regexp.c \
|
||||
$(TOP)\ext\misc\remember.c \
|
||||
$(TOP)\ext\misc\series.c \
|
||||
@@ -1632,7 +1633,8 @@ FUZZDATA = \
|
||||
$(TOP)\test\fuzzdata4.db \
|
||||
$(TOP)\test\fuzzdata5.db \
|
||||
$(TOP)\test\fuzzdata6.db \
|
||||
$(TOP)\test\fuzzdata7.db
|
||||
$(TOP)\test\fuzzdata7.db \
|
||||
$(TOP)\test\fuzzdata8.db
|
||||
# <</mark>>
|
||||
|
||||
# Additional compiler options for the shell. These are only effective
|
||||
@@ -1650,7 +1652,13 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
#
|
||||
MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5
|
||||
FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000 -DSQLITE_PRINTF_PRECISION_LIMIT=1000
|
||||
FUZZCHECK_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000 -DSQLITE_PRINTF_PRECISION_LIMIT=1000
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DESERIALIZE
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
|
||||
FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c
|
||||
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
|
||||
DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
|
||||
@@ -1737,10 +1745,10 @@ dbfuzz.exe: $(TOP)\test\dbfuzz.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(DBFUZZ_COMPILE_OPTS) $(TOP)\test\dbfuzz.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
fuzzcheck.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(FUZZCHECK_COMPILE_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
$(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
ossshell.exe: $(OSSSHELL_SRC) $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) $(FUZZCHECK_COMPILE_OPTS) $(OSSSHELL_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
$(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(OSSSHELL_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
sessionfuzz.exe: zlib $(TOP)\test\sessionfuzz.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -I$(ZLIBINCDIR) $(TOP)\test\sessionfuzz.c /link $(LDFLAGS) $(LTLINKOPTS) /LIBPATH:$(ZLIBLIBDIR) $(ZLIBLIB)
|
||||
@@ -2137,6 +2145,7 @@ SHELL_SRC = \
|
||||
$(TOP)\ext\misc\completion.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.h \
|
||||
$(TOP)\ext\misc\memtrace.c \
|
||||
$(TOP)\src\test_windirent.c
|
||||
|
||||
# If use of zlib is enabled, add the "zipfile.c" source file.
|
||||
@@ -2305,6 +2314,7 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
|
||||
@@ -2432,6 +2442,9 @@ testloadext.lo: $(TOP)\src\test_loadext.c $(SQLITE3H)
|
||||
testloadext.dll: testloadext.lo
|
||||
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /OUT:$@ testloadext.lo
|
||||
|
||||
dbtotxt.exe: $(TOP)\tool\dbtotxt.c
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\dbtotxt.c /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
showdb.exe: $(TOP)\tool\showdb.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\tool\showdb.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
@@ -2451,6 +2464,10 @@ showwal.exe: $(TOP)\tool\showwal.c $(SQLITE3C) $(SQLITE3H)
|
||||
showshm.exe: $(TOP)\tool\showshm.c
|
||||
$(LTLINK) $(NO_WARN) $(TOP)\tool\showshm.c /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
index_usage.exe: $(TOP)\tool\index_usage.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
$(TOP)\tool\index_usage.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
|
||||
|
||||
changeset.exe: $(TOP)\ext\session\changeset.c $(SQLITE3C) $(SQLITE3H)
|
||||
$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 \
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
"requires_arc": false,
|
||||
"source": {
|
||||
"git": "https://github.com/sqlcipher/sqlcipher.git",
|
||||
"tag": "v4.0.1"
|
||||
"tag": "v4.1.0"
|
||||
},
|
||||
"summary": "Full Database Encryption for SQLite.",
|
||||
"version": "4.0.1",
|
||||
"version": "4.1.0",
|
||||
"subspecs": [
|
||||
{
|
||||
"compiler_flags": [
|
||||
|
||||
@@ -283,6 +283,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_INTROSPECTION_PRAGMAS=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
!ENDIF
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
!ENDIF
|
||||
@@ -937,6 +938,7 @@ LIBRESOBJS =
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
!ENDIF
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlcipher 3.26.0.
|
||||
# Generated by GNU Autoconf 2.69 for sqlcipher 3.27.2.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
@@ -587,8 +587,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlcipher'
|
||||
PACKAGE_TARNAME='sqlcipher'
|
||||
PACKAGE_VERSION='3.26.0'
|
||||
PACKAGE_STRING='sqlcipher 3.26.0'
|
||||
PACKAGE_VERSION='3.27.2'
|
||||
PACKAGE_STRING='sqlcipher 3.27.2'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1337,7 +1337,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 sqlcipher 3.26.0 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlcipher 3.27.2 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1402,7 +1402,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlcipher 3.26.0:";;
|
||||
short | recursive ) echo "Configuration of sqlcipher 3.27.2:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1538,7 +1538,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlcipher configure 3.26.0
|
||||
sqlcipher configure 3.27.2
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -1957,7 +1957,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 sqlcipher $as_me 3.26.0, which was
|
||||
It was created by sqlcipher $as_me 3.27.2, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -13754,7 +13754,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 sqlcipher $as_me 3.26.0, which was
|
||||
This file was extended by sqlcipher $as_me 3.27.2, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -13820,7 +13820,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="\\
|
||||
sqlcipher config.status 3.26.0
|
||||
sqlcipher config.status 3.27.2
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
@@ -243,8 +243,10 @@ do_setup_rec_test $tn.12.1 {
|
||||
CREATE INDEX t7_idx_00000062 ON t7(b);
|
||||
CREATE INDEX t7_idx_00000061 ON t7(a);
|
||||
MULTI-INDEX OR
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?)
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?)
|
||||
INDEX 1
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?)
|
||||
INDEX 2
|
||||
SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?)
|
||||
}
|
||||
|
||||
# rowid terms.
|
||||
|
||||
+78
-50
@@ -320,6 +320,14 @@ int sqlite3Fts3Never(int b) { assert( !b ); return b; }
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This variable is set to false when running tests for which the on disk
|
||||
** structures should not be corrupt. Otherwise, true. If it is false, extra
|
||||
** assert() conditions in the fts3 code are activated - conditions that are
|
||||
** only true if it is guaranteed that the fts3 database is not corrupt.
|
||||
*/
|
||||
int sqlite3_fts3_may_be_corrupt = 1;
|
||||
|
||||
/*
|
||||
** Write a 64-bit variable-length integer to memory starting at p[0].
|
||||
** The length of data written will be between 1 and FTS3_VARINT_MAX bytes.
|
||||
@@ -338,7 +346,7 @@ int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
|
||||
}
|
||||
|
||||
#define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \
|
||||
v = (v & mask1) | ( (*ptr++) << shift ); \
|
||||
v = (v & mask1) | ( (*(const unsigned char*)(ptr++)) << shift ); \
|
||||
if( (v & mask2)==0 ){ var = v; return ret; }
|
||||
#define GETVARINT_INIT(v, ptr, shift, mask1, mask2, var, ret) \
|
||||
v = (*ptr++); \
|
||||
@@ -376,20 +384,21 @@ int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
|
||||
** a non-negative 32-bit integer before it is returned.
|
||||
*/
|
||||
int sqlite3Fts3GetVarint32(const char *p, int *pi){
|
||||
const unsigned char *ptr = (const unsigned char*)p;
|
||||
u32 a;
|
||||
|
||||
#ifndef fts3GetVarint32
|
||||
GETVARINT_INIT(a, p, 0, 0x00, 0x80, *pi, 1);
|
||||
GETVARINT_INIT(a, ptr, 0, 0x00, 0x80, *pi, 1);
|
||||
#else
|
||||
a = (*p++);
|
||||
a = (*ptr++);
|
||||
assert( a & 0x80 );
|
||||
#endif
|
||||
|
||||
GETVARINT_STEP(a, p, 7, 0x7F, 0x4000, *pi, 2);
|
||||
GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *pi, 3);
|
||||
GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *pi, 4);
|
||||
GETVARINT_STEP(a, ptr, 7, 0x7F, 0x4000, *pi, 2);
|
||||
GETVARINT_STEP(a, ptr, 14, 0x3FFF, 0x200000, *pi, 3);
|
||||
GETVARINT_STEP(a, ptr, 21, 0x1FFFFF, 0x10000000, *pi, 4);
|
||||
a = (a & 0x0FFFFFFF );
|
||||
*pi = (int)(a | ((u32)(*p & 0x07) << 28));
|
||||
*pi = (int)(a | ((u32)(*ptr & 0x07) << 28));
|
||||
assert( 0==(a & 0x80000000) );
|
||||
assert( *pi>=0 );
|
||||
return 5;
|
||||
@@ -560,13 +569,18 @@ static int fts3DestroyMethod(sqlite3_vtab *pVtab){
|
||||
sqlite3 *db = p->db; /* Database handle */
|
||||
|
||||
/* Drop the shadow tables */
|
||||
if( p->zContentTbl==0 ){
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName);
|
||||
}
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName);
|
||||
fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName);
|
||||
fts3DbExec(&rc, db,
|
||||
"DROP TABLE IF EXISTS %Q.'%q_segments';"
|
||||
"DROP TABLE IF EXISTS %Q.'%q_segdir';"
|
||||
"DROP TABLE IF EXISTS %Q.'%q_docsize';"
|
||||
"DROP TABLE IF EXISTS %Q.'%q_stat';"
|
||||
"%s DROP TABLE IF EXISTS %Q.'%q_content';",
|
||||
zDb, p->zName,
|
||||
zDb, p->zName,
|
||||
zDb, p->zName,
|
||||
zDb, p->zName,
|
||||
(p->zContentTbl ? "--" : ""), zDb,p->zName
|
||||
);
|
||||
|
||||
/* If everything has worked, invoke fts3DisconnectMethod() to free the
|
||||
** memory associated with the Fts3Table structure and return SQLITE_OK.
|
||||
@@ -798,10 +812,10 @@ static void fts3Appendf(
|
||||
** memory.
|
||||
*/
|
||||
static char *fts3QuoteId(char const *zInput){
|
||||
int nRet;
|
||||
sqlite3_int64 nRet;
|
||||
char *zRet;
|
||||
nRet = 2 + (int)strlen(zInput)*2 + 1;
|
||||
zRet = sqlite3_malloc(nRet);
|
||||
zRet = sqlite3_malloc64(nRet);
|
||||
if( zRet ){
|
||||
int i;
|
||||
char *z = zRet;
|
||||
@@ -982,7 +996,7 @@ static int fts3PrefixParameter(
|
||||
}
|
||||
}
|
||||
|
||||
aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex);
|
||||
aIndex = sqlite3_malloc64(sizeof(struct Fts3Index) * nIndex);
|
||||
*apIndex = aIndex;
|
||||
if( !aIndex ){
|
||||
return SQLITE_NOMEM;
|
||||
@@ -1061,7 +1075,7 @@ static int fts3ContentColumns(
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
const char **azCol; /* Output array */
|
||||
int nStr = 0; /* Size of all column names (incl. 0x00) */
|
||||
sqlite3_int64 nStr = 0; /* Size of all column names (incl. 0x00) */
|
||||
int nCol; /* Number of table columns */
|
||||
int i; /* Used to iterate through columns */
|
||||
|
||||
@@ -1071,11 +1085,11 @@ static int fts3ContentColumns(
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
for(i=0; i<nCol; i++){
|
||||
const char *zCol = sqlite3_column_name(pStmt, i);
|
||||
nStr += (int)strlen(zCol) + 1;
|
||||
nStr += strlen(zCol) + 1;
|
||||
}
|
||||
|
||||
/* Allocate and populate the array to return. */
|
||||
azCol = (const char **)sqlite3_malloc(sizeof(char *) * nCol + nStr);
|
||||
azCol = (const char **)sqlite3_malloc64(sizeof(char *) * nCol + nStr);
|
||||
if( azCol==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1123,7 +1137,7 @@ static int fts3InitVtab(
|
||||
Fts3Table *p = 0; /* Pointer to allocated vtab */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int i; /* Iterator variable */
|
||||
int nByte; /* Size of allocation used for *p */
|
||||
sqlite3_int64 nByte; /* Size of allocation used for *p */
|
||||
int iCol; /* Column index */
|
||||
int nString = 0; /* Bytes required to hold all column names */
|
||||
int nCol = 0; /* Number of columns in the FTS table */
|
||||
@@ -1157,10 +1171,10 @@ static int fts3InitVtab(
|
||||
nName = (int)strlen(argv[2]) + 1;
|
||||
|
||||
nByte = sizeof(const char *) * (argc-2);
|
||||
aCol = (const char **)sqlite3_malloc(nByte);
|
||||
aCol = (const char **)sqlite3_malloc64(nByte);
|
||||
if( aCol ){
|
||||
memset((void*)aCol, 0, nByte);
|
||||
azNotindexed = (char **)sqlite3_malloc(nByte);
|
||||
azNotindexed = (char **)sqlite3_malloc64(nByte);
|
||||
}
|
||||
if( azNotindexed ){
|
||||
memset(azNotindexed, 0, nByte);
|
||||
@@ -1355,7 +1369,7 @@ static int fts3InitVtab(
|
||||
nName + /* zName */
|
||||
nDb + /* zDb */
|
||||
nString; /* Space for azColumn strings */
|
||||
p = (Fts3Table*)sqlite3_malloc(nByte);
|
||||
p = (Fts3Table*)sqlite3_malloc64(nByte);
|
||||
if( p==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto fts3_init_out;
|
||||
@@ -2134,7 +2148,7 @@ static int fts3PutColNumber(char **pp, int iCol){
|
||||
** updated appropriately. The caller is responsible for insuring
|
||||
** that there is enough space in *pp to hold the complete output.
|
||||
*/
|
||||
static void fts3PoslistMerge(
|
||||
static int fts3PoslistMerge(
|
||||
char **pp, /* Output buffer */
|
||||
char **pp1, /* Left input list */
|
||||
char **pp2 /* Right input list */
|
||||
@@ -2147,11 +2161,17 @@ static void fts3PoslistMerge(
|
||||
int iCol1; /* The current column index in pp1 */
|
||||
int iCol2; /* The current column index in pp2 */
|
||||
|
||||
if( *p1==POS_COLUMN ) fts3GetVarint32(&p1[1], &iCol1);
|
||||
if( *p1==POS_COLUMN ){
|
||||
fts3GetVarint32(&p1[1], &iCol1);
|
||||
if( iCol1==0 ) return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
else if( *p1==POS_END ) iCol1 = POSITION_LIST_END;
|
||||
else iCol1 = 0;
|
||||
|
||||
if( *p2==POS_COLUMN ) fts3GetVarint32(&p2[1], &iCol2);
|
||||
if( *p2==POS_COLUMN ){
|
||||
fts3GetVarint32(&p2[1], &iCol2);
|
||||
if( iCol2==0 ) return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
else if( *p2==POS_END ) iCol2 = POSITION_LIST_END;
|
||||
else iCol2 = 0;
|
||||
|
||||
@@ -2199,6 +2219,7 @@ static void fts3PoslistMerge(
|
||||
*pp = p;
|
||||
*pp1 = p1 + 1;
|
||||
*pp2 = p2 + 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2263,10 +2284,9 @@ static int fts3PoslistPhraseMerge(
|
||||
p += sqlite3Fts3PutVarint(p, iCol1);
|
||||
}
|
||||
|
||||
assert( *p1!=POS_END && *p1!=POS_COLUMN );
|
||||
assert( *p2!=POS_END && *p2!=POS_COLUMN );
|
||||
fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2;
|
||||
fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
|
||||
if( iPos1<0 || iPos2<0 ) break;
|
||||
|
||||
while( 1 ){
|
||||
if( iPos2==iPos1+nToken
|
||||
@@ -2492,6 +2512,7 @@ static int fts3DoclistOrMerge(
|
||||
char *a2, int n2, /* Second doclist */
|
||||
char **paOut, int *pnOut /* OUT: Malloc'd doclist */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_int64 i1 = 0;
|
||||
sqlite3_int64 i2 = 0;
|
||||
sqlite3_int64 iPrev = 0;
|
||||
@@ -2535,7 +2556,7 @@ static int fts3DoclistOrMerge(
|
||||
** A symetric argument may be made if the doclists are in descending
|
||||
** order.
|
||||
*/
|
||||
aOut = sqlite3_malloc(n1+n2+FTS3_VARINT_MAX-1);
|
||||
aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING);
|
||||
if( !aOut ) return SQLITE_NOMEM;
|
||||
|
||||
p = aOut;
|
||||
@@ -2546,7 +2567,8 @@ static int fts3DoclistOrMerge(
|
||||
|
||||
if( p2 && p1 && iDiff==0 ){
|
||||
fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1);
|
||||
fts3PoslistMerge(&p, &p1, &p2);
|
||||
rc = fts3PoslistMerge(&p, &p1, &p2);
|
||||
if( rc ) break;
|
||||
fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1);
|
||||
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
|
||||
}else if( !p2 || (p1 && iDiff<0) ){
|
||||
@@ -2560,10 +2582,16 @@ static int fts3DoclistOrMerge(
|
||||
}
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(aOut);
|
||||
p = aOut = 0;
|
||||
}else{
|
||||
assert( (p-aOut)<=n1+n2+FTS3_VARINT_MAX-1 );
|
||||
memset(&aOut[(p-aOut)], 0, FTS3_BUFFER_PADDING);
|
||||
}
|
||||
*paOut = aOut;
|
||||
*pnOut = (int)(p-aOut);
|
||||
assert( *pnOut<=n1+n2+FTS3_VARINT_MAX-1 );
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2598,7 +2626,7 @@ static int fts3DoclistPhraseMerge(
|
||||
|
||||
assert( nDist>0 );
|
||||
if( bDescDoclist ){
|
||||
aOut = sqlite3_malloc(*pnRight + FTS3_VARINT_MAX);
|
||||
aOut = sqlite3_malloc64((sqlite3_int64)*pnRight + FTS3_VARINT_MAX);
|
||||
if( aOut==0 ) return SQLITE_NOMEM;
|
||||
}else{
|
||||
aOut = aRight;
|
||||
@@ -2782,6 +2810,7 @@ static int fts3TermSelectMerge(
|
||||
pTS->anOutput[0] = nDoclist;
|
||||
if( pTS->aaOutput[0] ){
|
||||
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
|
||||
memset(&pTS->aaOutput[0][nDoclist], 0, FTS3_VARINT_MAX);
|
||||
}else{
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -2833,8 +2862,8 @@ static int fts3SegReaderCursorAppend(
|
||||
){
|
||||
if( (pCsr->nSegment%16)==0 ){
|
||||
Fts3SegReader **apNew;
|
||||
int nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*);
|
||||
apNew = (Fts3SegReader **)sqlite3_realloc(pCsr->apSegment, nByte);
|
||||
sqlite3_int64 nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*);
|
||||
apNew = (Fts3SegReader **)sqlite3_realloc64(pCsr->apSegment, nByte);
|
||||
if( !apNew ){
|
||||
sqlite3Fts3SegReaderFree(pNew);
|
||||
return SQLITE_NOMEM;
|
||||
@@ -2898,7 +2927,7 @@ static int fts3SegReaderCursor(
|
||||
|
||||
/* If zTerm is not NULL, and this segment is not stored entirely on its
|
||||
** root node, the range of leaves scanned can be reduced. Do this. */
|
||||
if( iStartBlock && zTerm ){
|
||||
if( iStartBlock && zTerm && zRoot ){
|
||||
sqlite3_int64 *pi = (isPrefix ? &iLeavesEndBlock : 0);
|
||||
rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &iStartBlock, pi);
|
||||
if( rc!=SQLITE_OK ) goto finished;
|
||||
@@ -3840,7 +3869,6 @@ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Fts3Table *p = (Fts3Table*)pVtab;
|
||||
UNUSED_PARAMETER(iSavepoint);
|
||||
assert( p->inTransaction );
|
||||
assert( p->mxSavepoint >= iSavepoint );
|
||||
TESTONLY( p->mxSavepoint = iSavepoint );
|
||||
sqlite3Fts3PendingTermsClear(p);
|
||||
return SQLITE_OK;
|
||||
@@ -4615,9 +4643,10 @@ static int fts3EvalIncrPhraseNext(
|
||||
if( bEof==0 ){
|
||||
int nList = 0;
|
||||
int nByte = a[p->nToken-1].nList;
|
||||
char *aDoclist = sqlite3_malloc(nByte+1);
|
||||
char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING);
|
||||
if( !aDoclist ) return SQLITE_NOMEM;
|
||||
memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
|
||||
memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING);
|
||||
|
||||
for(i=0; i<(p->nToken-1); i++){
|
||||
if( a[i].bIgnore==0 ){
|
||||
@@ -5008,7 +5037,7 @@ static int fts3EvalStart(Fts3Cursor *pCsr){
|
||||
if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){
|
||||
Fts3TokenAndCost *aTC;
|
||||
Fts3Expr **apOr;
|
||||
aTC = (Fts3TokenAndCost *)sqlite3_malloc(
|
||||
aTC = (Fts3TokenAndCost *)sqlite3_malloc64(
|
||||
sizeof(Fts3TokenAndCost) * nToken
|
||||
+ sizeof(Fts3Expr *) * nOr * 2
|
||||
);
|
||||
@@ -5319,7 +5348,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
|
||||
&& (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
|
||||
){
|
||||
Fts3Expr *p;
|
||||
int nTmp = 0; /* Bytes of temp space */
|
||||
sqlite3_int64 nTmp = 0; /* Bytes of temp space */
|
||||
char *aTmp; /* Temp space for PoslistNearMerge() */
|
||||
|
||||
/* Allocate temporary working space. */
|
||||
@@ -5328,7 +5357,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
|
||||
nTmp += p->pRight->pPhrase->doclist.nList;
|
||||
}
|
||||
nTmp += p->pPhrase->doclist.nList;
|
||||
aTmp = sqlite3_malloc(nTmp*2);
|
||||
aTmp = sqlite3_malloc64(nTmp*2);
|
||||
if( !aTmp ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
res = 0;
|
||||
@@ -5598,15 +5627,14 @@ static void fts3EvalRestart(
|
||||
** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase
|
||||
** expression nodes.
|
||||
*/
|
||||
static void fts3EvalUpdateCounts(Fts3Expr *pExpr){
|
||||
static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){
|
||||
if( pExpr ){
|
||||
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
||||
if( pPhrase && pPhrase->doclist.pList ){
|
||||
int iCol = 0;
|
||||
char *p = pPhrase->doclist.pList;
|
||||
|
||||
assert( *p );
|
||||
while( 1 ){
|
||||
do{
|
||||
u8 c = 0;
|
||||
int iCnt = 0;
|
||||
while( 0xFE & (*p | c) ){
|
||||
@@ -5622,11 +5650,11 @@ static void fts3EvalUpdateCounts(Fts3Expr *pExpr){
|
||||
if( *p==0x00 ) break;
|
||||
p++;
|
||||
p += fts3GetVarint32(p, &iCol);
|
||||
}
|
||||
}while( iCol<nCol );
|
||||
}
|
||||
|
||||
fts3EvalUpdateCounts(pExpr->pLeft);
|
||||
fts3EvalUpdateCounts(pExpr->pRight);
|
||||
fts3EvalUpdateCounts(pExpr->pLeft, nCol);
|
||||
fts3EvalUpdateCounts(pExpr->pRight, nCol);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5670,7 +5698,7 @@ static int fts3EvalGatherStats(
|
||||
for(p=pRoot; p; p=p->pLeft){
|
||||
Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight);
|
||||
assert( pE->aMI==0 );
|
||||
pE->aMI = (u32 *)sqlite3_malloc(pTab->nColumn * 3 * sizeof(u32));
|
||||
pE->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
|
||||
if( !pE->aMI ) return SQLITE_NOMEM;
|
||||
memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
|
||||
}
|
||||
@@ -5696,7 +5724,7 @@ static int fts3EvalGatherStats(
|
||||
);
|
||||
|
||||
if( rc==SQLITE_OK && pCsr->isEof==0 ){
|
||||
fts3EvalUpdateCounts(pRoot);
|
||||
fts3EvalUpdateCounts(pRoot, pTab->nColumn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,8 @@ SQLITE_EXTENSION_INIT3
|
||||
*/
|
||||
#define FTS3_VARINT_MAX 10
|
||||
|
||||
#define FTS3_BUFFER_PADDING 8
|
||||
|
||||
/*
|
||||
** FTS4 virtual tables may maintain multiple indexes - one index of all terms
|
||||
** in the document set and zero or more prefix indexes. All indexes are stored
|
||||
@@ -127,6 +129,18 @@ SQLITE_EXTENSION_INIT3
|
||||
#define POS_COLUMN (1) /* Column-list terminator */
|
||||
#define POS_END (0) /* Position-list terminator */
|
||||
|
||||
/*
|
||||
** The assert_fts3_nc() macro is similar to the assert() macro, except that it
|
||||
** is used for assert() conditions that are true only if it can be
|
||||
** guranteed that the database is not corrupt.
|
||||
*/
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
extern int sqlite3_fts3_may_be_corrupt;
|
||||
# define assert_fts3_nc(x) assert(sqlite3_fts3_may_be_corrupt || (x))
|
||||
#else
|
||||
# define assert_fts3_nc(x) assert(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This section provides definitions to allow the
|
||||
** FTS3 extension to be compiled outside of the
|
||||
|
||||
+5
-5
@@ -66,7 +66,7 @@ static int fts3auxConnectMethod(
|
||||
char const *zFts3; /* Name of fts3 table */
|
||||
int nDb; /* Result of strlen(zDb) */
|
||||
int nFts3; /* Result of strlen(zFts3) */
|
||||
int nByte; /* Bytes of space to allocate here */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate here */
|
||||
int rc; /* value returned by declare_vtab() */
|
||||
Fts3auxTable *p; /* Virtual table object to return */
|
||||
|
||||
@@ -98,7 +98,7 @@ static int fts3auxConnectMethod(
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
|
||||
p = (Fts3auxTable *)sqlite3_malloc(nByte);
|
||||
p = (Fts3auxTable *)sqlite3_malloc64(nByte);
|
||||
if( !p ) return SQLITE_NOMEM;
|
||||
memset(p, 0, nByte);
|
||||
|
||||
@@ -248,7 +248,7 @@ static int fts3auxCloseMethod(sqlite3_vtab_cursor *pCursor){
|
||||
static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){
|
||||
if( nSize>pCsr->nStat ){
|
||||
struct Fts3auxColstats *aNew;
|
||||
aNew = (struct Fts3auxColstats *)sqlite3_realloc(pCsr->aStat,
|
||||
aNew = (struct Fts3auxColstats *)sqlite3_realloc64(pCsr->aStat,
|
||||
sizeof(struct Fts3auxColstats) * nSize
|
||||
);
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
@@ -416,15 +416,15 @@ static int fts3auxFilterMethod(
|
||||
assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) );
|
||||
if( zStr ){
|
||||
pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr);
|
||||
pCsr->filter.nTerm = sqlite3_value_bytes(apVal[0]);
|
||||
if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM;
|
||||
pCsr->filter.nTerm = (int)strlen(pCsr->filter.zTerm);
|
||||
}
|
||||
}
|
||||
|
||||
if( iLe>=0 ){
|
||||
pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe]));
|
||||
pCsr->nStop = sqlite3_value_bytes(apVal[iLe]);
|
||||
if( pCsr->zStop==0 ) return SQLITE_NOMEM;
|
||||
pCsr->nStop = (int)strlen(pCsr->zStop);
|
||||
}
|
||||
|
||||
if( iLangid>=0 ){
|
||||
|
||||
@@ -122,8 +122,8 @@ static int fts3isspace(char c){
|
||||
** zero the memory before returning a pointer to it. If unsuccessful,
|
||||
** return NULL.
|
||||
*/
|
||||
static void *fts3MallocZero(int nByte){
|
||||
void *pRet = sqlite3_malloc(nByte);
|
||||
static void *fts3MallocZero(sqlite3_int64 nByte){
|
||||
void *pRet = sqlite3_malloc64(nByte);
|
||||
if( pRet ) memset(pRet, 0, nByte);
|
||||
return pRet;
|
||||
}
|
||||
@@ -198,7 +198,7 @@ static int getNextToken(
|
||||
if( rc==SQLITE_OK ){
|
||||
const char *zToken;
|
||||
int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;
|
||||
int nByte; /* total space to allocate */
|
||||
sqlite3_int64 nByte; /* total space to allocate */
|
||||
|
||||
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -252,8 +252,8 @@ static int getNextToken(
|
||||
** Enlarge a memory allocation. If an out-of-memory allocation occurs,
|
||||
** then free the old allocation.
|
||||
*/
|
||||
static void *fts3ReallocOrFree(void *pOrig, int nNew){
|
||||
void *pRet = sqlite3_realloc(pOrig, nNew);
|
||||
static void *fts3ReallocOrFree(void *pOrig, sqlite3_int64 nNew){
|
||||
void *pRet = sqlite3_realloc64(pOrig, nNew);
|
||||
if( !pRet ){
|
||||
sqlite3_free(pOrig);
|
||||
}
|
||||
@@ -497,7 +497,6 @@ static int getNextNode(
|
||||
int nConsumed = 0;
|
||||
pParse->nNest++;
|
||||
rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed);
|
||||
if( rc==SQLITE_OK && !*ppExpr ){ rc = SQLITE_DONE; }
|
||||
*pnConsumed = (int)(zInput - z) + 1 + nConsumed;
|
||||
return rc;
|
||||
}else if( *zInput==')' ){
|
||||
@@ -796,7 +795,7 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
|
||||
if( rc==SQLITE_OK ){
|
||||
if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
|
||||
Fts3Expr **apLeaf;
|
||||
apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
|
||||
apLeaf = (Fts3Expr **)sqlite3_malloc64(sizeof(Fts3Expr *) * nMaxDepth);
|
||||
if( 0==apLeaf ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1216,7 +1215,7 @@ static void fts3ExprTestCommon(
|
||||
zExpr = (const char *)sqlite3_value_text(argv[1]);
|
||||
nExpr = sqlite3_value_bytes(argv[1]);
|
||||
nCol = argc-2;
|
||||
azCol = (char **)sqlite3_malloc(nCol*sizeof(char *));
|
||||
azCol = (char **)sqlite3_malloc64(nCol*sizeof(char *));
|
||||
if( !azCol ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
goto exprtest_out;
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
/*
|
||||
** Malloc and Free functions
|
||||
*/
|
||||
static void *fts3HashMalloc(int n){
|
||||
void *p = sqlite3_malloc(n);
|
||||
static void *fts3HashMalloc(sqlite3_int64 n){
|
||||
void *p = sqlite3_malloc64(n);
|
||||
if( p ){
|
||||
memset(p, 0, n);
|
||||
}
|
||||
|
||||
+2
-2
@@ -60,7 +60,7 @@ static int icuCreate(
|
||||
if( argc>0 ){
|
||||
n = strlen(argv[0])+1;
|
||||
}
|
||||
p = (IcuTokenizer *)sqlite3_malloc(sizeof(IcuTokenizer)+n);
|
||||
p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n);
|
||||
if( !p ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -117,7 +117,7 @@ static int icuOpen(
|
||||
nInput = strlen(zInput);
|
||||
}
|
||||
nChar = nInput+1;
|
||||
pCsr = (IcuCursor *)sqlite3_malloc(
|
||||
pCsr = (IcuCursor *)sqlite3_malloc64(
|
||||
sizeof(IcuCursor) + /* IcuCursor */
|
||||
((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */
|
||||
(nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */
|
||||
|
||||
+41
-23
@@ -178,7 +178,7 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){
|
||||
aOut = &p->aMatchinfo[p->nElem+2];
|
||||
xRet = fts3MIBufferFree;
|
||||
}else{
|
||||
aOut = (u32*)sqlite3_malloc(p->nElem * sizeof(u32));
|
||||
aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32));
|
||||
if( aOut ){
|
||||
xRet = sqlite3_free;
|
||||
if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32));
|
||||
@@ -433,7 +433,8 @@ static void fts3SnippetDetails(
|
||||
int j;
|
||||
u64 mPhrase = (u64)1 << i;
|
||||
u64 mPos = (u64)1 << (iCsr - iStart);
|
||||
assert( iCsr>=iStart );
|
||||
assert( iCsr>=iStart && (iCsr - iStart)<=64 );
|
||||
assert( i>=0 && i<=64 );
|
||||
if( (mCover|mCovered)&mPhrase ){
|
||||
iScore++;
|
||||
}else{
|
||||
@@ -475,11 +476,14 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
||||
int iFirst = 0;
|
||||
pPhrase->pList = pCsr;
|
||||
fts3GetDeltaPosition(&pCsr, &iFirst);
|
||||
assert( iFirst>=0 );
|
||||
pPhrase->pHead = pCsr;
|
||||
pPhrase->pTail = pCsr;
|
||||
pPhrase->iHead = iFirst;
|
||||
pPhrase->iTail = iFirst;
|
||||
if( iFirst<0 ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
}else{
|
||||
pPhrase->pHead = pCsr;
|
||||
pPhrase->pTail = pCsr;
|
||||
pPhrase->iHead = iFirst;
|
||||
pPhrase->iTail = iFirst;
|
||||
}
|
||||
}else{
|
||||
assert( rc!=SQLITE_OK || (
|
||||
pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0
|
||||
@@ -516,7 +520,7 @@ static int fts3BestSnippet(
|
||||
int rc; /* Return Code */
|
||||
int nList; /* Number of phrases in expression */
|
||||
SnippetIter sIter; /* Iterates through snippet candidates */
|
||||
int nByte; /* Number of bytes of space to allocate */
|
||||
sqlite3_int64 nByte; /* Number of bytes of space to allocate */
|
||||
int iBestScore = -1; /* Best snippet score found so far */
|
||||
int i; /* Loop counter */
|
||||
|
||||
@@ -534,7 +538,7 @@ static int fts3BestSnippet(
|
||||
** the required space using malloc().
|
||||
*/
|
||||
nByte = sizeof(SnippetPhrase) * nList;
|
||||
sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc(nByte);
|
||||
sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc64(nByte);
|
||||
if( !sIter.aPhrase ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -604,8 +608,8 @@ static int fts3StringAppend(
|
||||
** appended data.
|
||||
*/
|
||||
if( pStr->n+nAppend+1>=pStr->nAlloc ){
|
||||
int nAlloc = pStr->nAlloc+nAppend+100;
|
||||
char *zNew = sqlite3_realloc(pStr->z, nAlloc);
|
||||
sqlite3_int64 nAlloc = pStr->nAlloc+(sqlite3_int64)nAppend+100;
|
||||
char *zNew = sqlite3_realloc64(pStr->z, nAlloc);
|
||||
if( !zNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -660,6 +664,7 @@ static int fts3SnippetShift(
|
||||
|
||||
for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++);
|
||||
for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++);
|
||||
assert( (nSnippet-1-nRight)<=63 && (nSnippet-1-nRight)>=0 );
|
||||
nDesired = (nLeft-nRight)/2;
|
||||
|
||||
/* Ideally, the start of the snippet should be pushed forward in the
|
||||
@@ -852,7 +857,7 @@ static int fts3ColumnlistCount(char **ppCollist){
|
||||
/*
|
||||
** This function gathers 'y' or 'b' data for a single phrase.
|
||||
*/
|
||||
static void fts3ExprLHits(
|
||||
static int fts3ExprLHits(
|
||||
Fts3Expr *pExpr, /* Phrase expression node */
|
||||
MatchInfo *p /* Matchinfo context */
|
||||
){
|
||||
@@ -882,25 +887,29 @@ static void fts3ExprLHits(
|
||||
if( *pIter!=0x01 ) break;
|
||||
pIter++;
|
||||
pIter += fts3GetVarint32(pIter, &iCol);
|
||||
if( iCol>=p->nCol ) return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Gather the results for matchinfo directives 'y' and 'b'.
|
||||
*/
|
||||
static void fts3ExprLHitGather(
|
||||
static int fts3ExprLHitGather(
|
||||
Fts3Expr *pExpr,
|
||||
MatchInfo *p
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
assert( (pExpr->pLeft==0)==(pExpr->pRight==0) );
|
||||
if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){
|
||||
if( pExpr->pLeft ){
|
||||
fts3ExprLHitGather(pExpr->pLeft, p);
|
||||
fts3ExprLHitGather(pExpr->pRight, p);
|
||||
rc = fts3ExprLHitGather(pExpr->pLeft, p);
|
||||
if( rc==SQLITE_OK ) rc = fts3ExprLHitGather(pExpr->pRight, p);
|
||||
}else{
|
||||
fts3ExprLHits(pExpr, p);
|
||||
rc = fts3ExprLHits(pExpr, p);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1117,11 +1126,12 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
||||
int i;
|
||||
int iCol;
|
||||
int nToken = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
/* Allocate and populate the array of LcsIterator objects. The array
|
||||
** contains one element for each matchable phrase in the query.
|
||||
**/
|
||||
aIter = sqlite3_malloc(sizeof(LcsIterator) * pCsr->nPhrase);
|
||||
aIter = sqlite3_malloc64(sizeof(LcsIterator) * pCsr->nPhrase);
|
||||
if( !aIter ) return SQLITE_NOMEM;
|
||||
memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
|
||||
(void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
|
||||
@@ -1137,13 +1147,16 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
||||
int nLive = 0; /* Number of iterators in aIter not at EOF */
|
||||
|
||||
for(i=0; i<pInfo->nPhrase; i++){
|
||||
int rc;
|
||||
LcsIterator *pIt = &aIter[i];
|
||||
rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
if( rc!=SQLITE_OK ) goto matchinfo_lcs_out;
|
||||
if( pIt->pRead ){
|
||||
pIt->iPos = pIt->iPosOffset;
|
||||
fts3LcsIteratorAdvance(&aIter[i]);
|
||||
fts3LcsIteratorAdvance(pIt);
|
||||
if( pIt->pRead==0 ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
goto matchinfo_lcs_out;
|
||||
}
|
||||
nLive++;
|
||||
}
|
||||
}
|
||||
@@ -1175,8 +1188,9 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
||||
pInfo->aMatchinfo[iCol] = nLcs;
|
||||
}
|
||||
|
||||
matchinfo_lcs_out:
|
||||
sqlite3_free(aIter);
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1272,7 +1286,7 @@ static int fts3MatchinfoValues(
|
||||
case FTS3_MATCHINFO_LHITS: {
|
||||
int nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32);
|
||||
memset(pInfo->aMatchinfo, 0, nZero);
|
||||
fts3ExprLHitGather(pCsr->pExpr, pInfo);
|
||||
rc = fts3ExprLHitGather(pCsr->pExpr, pInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1424,6 +1438,10 @@ void sqlite3Fts3Snippet(
|
||||
return;
|
||||
}
|
||||
|
||||
/* Limit the snippet length to 64 tokens. */
|
||||
if( nToken<-64 ) nToken = -64;
|
||||
if( nToken>+64 ) nToken = +64;
|
||||
|
||||
for(nSnippet=1; 1; nSnippet++){
|
||||
|
||||
int iSnip; /* Loop counter 0..nSnippet-1 */
|
||||
@@ -1566,7 +1584,7 @@ void sqlite3Fts3Offsets(
|
||||
if( rc!=SQLITE_OK ) goto offsets_out;
|
||||
|
||||
/* Allocate the array of TermOffset iterators. */
|
||||
sCtx.aTerm = (TermOffset *)sqlite3_malloc(sizeof(TermOffset)*nToken);
|
||||
sCtx.aTerm = (TermOffset *)sqlite3_malloc64(sizeof(TermOffset)*nToken);
|
||||
if( 0==sCtx.aTerm ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto offsets_out;
|
||||
|
||||
@@ -68,9 +68,9 @@ static int fts3termConnectMethod(
|
||||
char const *zFts3; /* Name of fts3 table */
|
||||
int nDb; /* Result of strlen(zDb) */
|
||||
int nFts3; /* Result of strlen(zFts3) */
|
||||
int nByte; /* Bytes of space to allocate here */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate here */
|
||||
int rc; /* value returned by declare_vtab() */
|
||||
Fts3termTable *p; /* Virtual table object to return */
|
||||
Fts3termTable *p; /* Virtual table object to return */
|
||||
int iIndex = 0;
|
||||
|
||||
UNUSED_PARAMETER(pCtx);
|
||||
@@ -96,7 +96,7 @@ static int fts3termConnectMethod(
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
nByte = sizeof(Fts3termTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
|
||||
p = (Fts3termTable *)sqlite3_malloc(nByte);
|
||||
p = (Fts3termTable *)sqlite3_malloc64(nByte);
|
||||
if( !p ) return SQLITE_NOMEM;
|
||||
memset(p, 0, nByte);
|
||||
|
||||
|
||||
+30
-1
@@ -574,6 +574,33 @@ static int SQLITE_TCLAPI fts3_test_varint_cmd(
|
||||
** End of tokenizer code.
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
** sqlite3_fts3_may_be_corrupt BOOLEAN
|
||||
**
|
||||
** Set or clear the global "may-be-corrupt" flag. Return the old value.
|
||||
*/
|
||||
static int SQLITE_TCLAPI fts3_may_be_corrupt(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int bOld = sqlite3_fts3_may_be_corrupt;
|
||||
|
||||
if( objc!=2 && objc!=1 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "?BOOLEAN?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc==2 ){
|
||||
int bNew;
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[1], &bNew) ) return TCL_ERROR;
|
||||
sqlite3_fts3_may_be_corrupt = bNew;
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(bOld));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
int Sqlitetestfts3_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(interp, "fts3_near_match", fts3_near_match_cmd, 0, 0);
|
||||
Tcl_CreateObjCommand(interp,
|
||||
@@ -582,10 +609,12 @@ int Sqlitetestfts3_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "fts3_test_tokenizer", fts3_test_tokenizer_cmd, 0, 0
|
||||
);
|
||||
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "fts3_test_varint", fts3_test_varint_cmd, 0, 0
|
||||
);
|
||||
Tcl_CreateObjCommand(
|
||||
interp, "sqlite3_fts3_may_be_corrupt", fts3_may_be_corrupt, 0, 0
|
||||
);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_FTS3 || SQLITE_ENABLE_FTS4 */
|
||||
|
||||
@@ -122,7 +122,7 @@ static int fts3tokDequoteArray(
|
||||
nByte += (int)(strlen(argv[i]) + 1);
|
||||
}
|
||||
|
||||
*pazDequote = azDequote = sqlite3_malloc(sizeof(char *)*argc + nByte);
|
||||
*pazDequote = azDequote = sqlite3_malloc64(sizeof(char *)*argc + nByte);
|
||||
if( azDequote==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
|
||||
+10
-7
@@ -82,7 +82,7 @@ typedef struct unicode_cursor unicode_cursor;
|
||||
|
||||
struct unicode_tokenizer {
|
||||
sqlite3_tokenizer base;
|
||||
int bRemoveDiacritic;
|
||||
int eRemoveDiacritic;
|
||||
int nException;
|
||||
int *aiException;
|
||||
};
|
||||
@@ -155,7 +155,7 @@ static int unicodeAddExceptions(
|
||||
int *aNew; /* New aiException[] array */
|
||||
int nNew; /* Number of valid entries in array aNew[] */
|
||||
|
||||
aNew = sqlite3_realloc(p->aiException, (p->nException+nEntry)*sizeof(int));
|
||||
aNew = sqlite3_realloc64(p->aiException,(p->nException+nEntry)*sizeof(int));
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
nNew = p->nException;
|
||||
|
||||
@@ -227,17 +227,20 @@ static int unicodeCreate(
|
||||
pNew = (unicode_tokenizer *) sqlite3_malloc(sizeof(unicode_tokenizer));
|
||||
if( pNew==NULL ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(unicode_tokenizer));
|
||||
pNew->bRemoveDiacritic = 1;
|
||||
pNew->eRemoveDiacritic = 1;
|
||||
|
||||
for(i=0; rc==SQLITE_OK && i<nArg; i++){
|
||||
const char *z = azArg[i];
|
||||
int n = (int)strlen(z);
|
||||
|
||||
if( n==19 && memcmp("remove_diacritics=1", z, 19)==0 ){
|
||||
pNew->bRemoveDiacritic = 1;
|
||||
pNew->eRemoveDiacritic = 1;
|
||||
}
|
||||
else if( n==19 && memcmp("remove_diacritics=0", z, 19)==0 ){
|
||||
pNew->bRemoveDiacritic = 0;
|
||||
pNew->eRemoveDiacritic = 0;
|
||||
}
|
||||
else if( n==19 && memcmp("remove_diacritics=2", z, 19)==0 ){
|
||||
pNew->eRemoveDiacritic = 2;
|
||||
}
|
||||
else if( n>=11 && memcmp("tokenchars=", z, 11)==0 ){
|
||||
rc = unicodeAddExceptions(pNew, 1, &z[11], n-11);
|
||||
@@ -341,7 +344,7 @@ static int unicodeNext(
|
||||
|
||||
/* Grow the output buffer if required. */
|
||||
if( (zOut-pCsr->zToken)>=(pCsr->nAlloc-4) ){
|
||||
char *zNew = sqlite3_realloc(pCsr->zToken, pCsr->nAlloc+64);
|
||||
char *zNew = sqlite3_realloc64(pCsr->zToken, pCsr->nAlloc+64);
|
||||
if( !zNew ) return SQLITE_NOMEM;
|
||||
zOut = &zNew[zOut - pCsr->zToken];
|
||||
pCsr->zToken = zNew;
|
||||
@@ -350,7 +353,7 @@ static int unicodeNext(
|
||||
|
||||
/* Write the folded case of the last character read to the output */
|
||||
zEnd = z;
|
||||
iOut = sqlite3FtsUnicodeFold((int)iCode, p->bRemoveDiacritic);
|
||||
iOut = sqlite3FtsUnicodeFold((int)iCode, p->eRemoveDiacritic);
|
||||
if( iOut ){
|
||||
WRITE_UTF8(zOut, iOut);
|
||||
}
|
||||
|
||||
+45
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** 2012 May 25
|
||||
** 2012-05-25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
@@ -159,32 +159,48 @@ int sqlite3FtsUnicodeIsalnum(int c){
|
||||
** E"). The resuls of passing a codepoint that corresponds to an
|
||||
** uppercase letter are undefined.
|
||||
*/
|
||||
static int remove_diacritic(int c){
|
||||
static int remove_diacritic(int c, int bComplex){
|
||||
unsigned short aDia[] = {
|
||||
0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
|
||||
2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
|
||||
2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
|
||||
2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
|
||||
3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928,
|
||||
3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234,
|
||||
4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504,
|
||||
6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529,
|
||||
61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726,
|
||||
61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122,
|
||||
62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536,
|
||||
62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730,
|
||||
62924, 63050, 63082, 63274, 63390,
|
||||
3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896,
|
||||
3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106,
|
||||
4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344,
|
||||
4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198,
|
||||
6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468,
|
||||
61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704,
|
||||
61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914,
|
||||
61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218,
|
||||
62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554,
|
||||
62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766,
|
||||
62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
|
||||
63182, 63242, 63274, 63310, 63368, 63390,
|
||||
};
|
||||
char aChar[] = {
|
||||
'\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c',
|
||||
'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r',
|
||||
's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o',
|
||||
'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r',
|
||||
'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h',
|
||||
'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a',
|
||||
'e', 'i', 'o', 'u', 'y',
|
||||
#define HIBIT ((unsigned char)0x80)
|
||||
unsigned char aChar[] = {
|
||||
'\0', 'a', 'c', 'e', 'i', 'n',
|
||||
'o', 'u', 'y', 'y', 'a', 'c',
|
||||
'd', 'e', 'e', 'g', 'h', 'i',
|
||||
'j', 'k', 'l', 'n', 'o', 'r',
|
||||
's', 't', 'u', 'u', 'w', 'y',
|
||||
'z', 'o', 'u', 'a', 'i', 'o',
|
||||
'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
|
||||
'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
|
||||
'e', 'i', 'o', 'r', 'u', 's',
|
||||
't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
|
||||
'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', 'a', 'b',
|
||||
'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
|
||||
'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
|
||||
'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
|
||||
'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
|
||||
's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
|
||||
'w', 'x', 'y', 'z', 'h', 't',
|
||||
'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
|
||||
'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
|
||||
'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
|
||||
};
|
||||
|
||||
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
|
||||
@@ -201,7 +217,8 @@ static int remove_diacritic(int c){
|
||||
}
|
||||
}
|
||||
assert( key>=aDia[iRes] );
|
||||
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
|
||||
if( bComplex==0 && (aChar[iRes] & 0x80) ) return c;
|
||||
return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F);
|
||||
}
|
||||
|
||||
|
||||
@@ -214,8 +231,8 @@ int sqlite3FtsUnicodeIsdiacritic(int c){
|
||||
unsigned int mask1 = 0x000361F8;
|
||||
if( c<768 || c>817 ) return 0;
|
||||
return (c < 768+32) ?
|
||||
(mask0 & (1 << (c-768))) :
|
||||
(mask1 & (1 << (c-768-32)));
|
||||
(mask0 & ((unsigned int)1 << (c-768))) :
|
||||
(mask1 & ((unsigned int)1 << (c-768-32)));
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +245,7 @@ int sqlite3FtsUnicodeIsdiacritic(int c){
|
||||
** The results are undefined if the value passed to this function
|
||||
** is less than zero.
|
||||
*/
|
||||
int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
|
||||
int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
|
||||
/* Each entry in the following array defines a rule for folding a range
|
||||
** of codepoints to lower case. The rule applies to a range of nRange
|
||||
** codepoints starting at codepoint iCode.
|
||||
@@ -351,7 +368,9 @@ int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
|
||||
assert( ret>0 );
|
||||
}
|
||||
|
||||
if( bRemoveDiacritic ) ret = remove_diacritic(ret);
|
||||
if( eRemoveDiacritic ){
|
||||
ret = remove_diacritic(ret, eRemoveDiacritic==2);
|
||||
}
|
||||
}
|
||||
|
||||
else if( c>=66560 && c<66600 ){
|
||||
|
||||
+31
-16
@@ -396,10 +396,12 @@ static int fts3SqlStmt(
|
||||
|
||||
pStmt = p->aStmt[eStmt];
|
||||
if( !pStmt ){
|
||||
int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB;
|
||||
char *zSql;
|
||||
if( eStmt==SQL_CONTENT_INSERT ){
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist);
|
||||
}else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){
|
||||
f &= ~SQLITE_PREPARE_NO_VTAB;
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist);
|
||||
}else{
|
||||
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName);
|
||||
@@ -407,8 +409,7 @@ static int fts3SqlStmt(
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v3(p->db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
|
||||
&pStmt, NULL);
|
||||
rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL);
|
||||
sqlite3_free(zSql);
|
||||
assert( rc==SQLITE_OK || pStmt==0 );
|
||||
p->aStmt[eStmt] = pStmt;
|
||||
@@ -566,7 +567,7 @@ static sqlite3_int64 getAbsoluteLevel(
|
||||
int iLevel /* Level of segments */
|
||||
){
|
||||
sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */
|
||||
assert( iLangid>=0 );
|
||||
assert_fts3_nc( iLangid>=0 );
|
||||
assert( p->nIndex>0 );
|
||||
assert( iIndex>=0 && iIndex<p->nIndex );
|
||||
|
||||
@@ -1408,7 +1409,7 @@ static int fts3SegReaderNext(
|
||||
** b-tree node. And that the final byte of the doclist is 0x00. If either
|
||||
** of these statements is untrue, then the data structure is corrupt.
|
||||
*/
|
||||
if( (&pReader->aNode[pReader->nNode] - pReader->aDoclist)<pReader->nDoclist
|
||||
if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode)
|
||||
|| (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
|
||||
){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
@@ -1608,8 +1609,13 @@ int sqlite3Fts3SegReaderNew(
|
||||
Fts3SegReader *pReader; /* Newly allocated SegReader object */
|
||||
int nExtra = 0; /* Bytes to allocate segment root node */
|
||||
|
||||
assert( iStartLeaf<=iEndLeaf );
|
||||
assert( zRoot!=0 || nRoot==0 );
|
||||
#ifdef CORRUPT_DB
|
||||
assert( zRoot!=0 || CORRUPT_DB );
|
||||
#endif
|
||||
|
||||
if( iStartLeaf==0 ){
|
||||
if( iEndLeaf!=0 ) return FTS_CORRUPT_VTAB;
|
||||
nExtra = nRoot + FTS3_NODE_PADDING;
|
||||
}
|
||||
|
||||
@@ -1629,7 +1635,7 @@ int sqlite3Fts3SegReaderNew(
|
||||
pReader->aNode = (char *)&pReader[1];
|
||||
pReader->rootOnly = 1;
|
||||
pReader->nNode = nRoot;
|
||||
memcpy(pReader->aNode, zRoot, nRoot);
|
||||
if( nRoot ) memcpy(pReader->aNode, zRoot, nRoot);
|
||||
memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING);
|
||||
}else{
|
||||
pReader->iCurrentBlock = iStartLeaf-1;
|
||||
@@ -2249,6 +2255,11 @@ static int fts3SegWriterAdd(
|
||||
nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm);
|
||||
nSuffix = nTerm-nPrefix;
|
||||
|
||||
/* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of
|
||||
** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when
|
||||
** compared with BINARY collation. This indicates corruption. */
|
||||
if( nSuffix<=0 ) return FTS_CORRUPT_VTAB;
|
||||
|
||||
/* Figure out how many bytes are required by this new entry */
|
||||
nReq = sqlite3Fts3VarintLen(nPrefix) + /* varint containing prefix size */
|
||||
sqlite3Fts3VarintLen(nSuffix) + /* varint containing suffix size */
|
||||
@@ -2956,7 +2967,9 @@ int sqlite3Fts3SegReaderStep(
|
||||
}else{
|
||||
iDelta = iDocid - iPrev;
|
||||
}
|
||||
assert( iDelta>0 || (nDoclist==0 && iDelta==iDocid) );
|
||||
if( iDelta<=0 && (nDoclist>0 || iDelta!=iDocid) ){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
assert( nDoclist>0 || iDelta==iDocid );
|
||||
|
||||
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
|
||||
@@ -3322,14 +3335,16 @@ static void fts3DecodeIntArray(
|
||||
const char *zBuf, /* The BLOB containing the varints */
|
||||
int nBuf /* size of the BLOB */
|
||||
){
|
||||
int i, j;
|
||||
UNUSED_PARAMETER(nBuf);
|
||||
for(i=j=0; i<N; i++){
|
||||
sqlite3_int64 x;
|
||||
j += sqlite3Fts3GetVarint(&zBuf[j], &x);
|
||||
assert(j<=nBuf);
|
||||
a[i] = (u32)(x & 0xffffffff);
|
||||
int i = 0;
|
||||
if( nBuf && (zBuf[nBuf-1]&0x80)==0 ){
|
||||
int j;
|
||||
for(i=j=0; i<N && j<nBuf; i++){
|
||||
sqlite3_int64 x;
|
||||
j += sqlite3Fts3GetVarint(&zBuf[j], &x);
|
||||
a[i] = (u32)(x & 0xffffffff);
|
||||
}
|
||||
}
|
||||
while( i<N ) a[i++] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3735,7 +3750,7 @@ static int nodeReaderNext(NodeReader *p){
|
||||
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);
|
||||
|
||||
if( nPrefix>p->iOff || nSuffix>p->nNode-p->iOff ){
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -3745,7 +3760,7 @@ static int nodeReaderNext(NodeReader *p){
|
||||
if( p->iChild==0 ){
|
||||
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
|
||||
if( (p->nNode-p->iOff)<p->nDoclist ){
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
p->aDoclist = &p->aNode[p->iOff];
|
||||
p->iOff += p->nDoclist;
|
||||
|
||||
@@ -9,11 +9,12 @@ proc print_rd {map} {
|
||||
set nRange 1
|
||||
set iFirst [lindex $map 0 0]
|
||||
set cPrev [lindex $map 0 1]
|
||||
set fPrev [lindex $map 0 2]
|
||||
|
||||
foreach m [lrange $map 1 end] {
|
||||
foreach {i c} $m {}
|
||||
foreach {i c f} $m {}
|
||||
|
||||
if {$cPrev == $c} {
|
||||
if {$cPrev == $c && $fPrev==$f} {
|
||||
for {set j [expr $iFirst+$nRange]} {$j<$i} {incr j} {
|
||||
if {[info exists tl_lookup_table($j)]==0} break
|
||||
}
|
||||
@@ -29,13 +30,16 @@ proc print_rd {map} {
|
||||
|
||||
lappend lRange [list $iFirst $nRange]
|
||||
lappend aChar $cPrev
|
||||
lappend aFlag $fPrev
|
||||
|
||||
set iFirst $i
|
||||
set cPrev $c
|
||||
set fPrev $f
|
||||
set nRange 1
|
||||
}
|
||||
lappend lRange [list $iFirst $nRange]
|
||||
lappend aChar $cPrev
|
||||
lappend aFlag $fPrev
|
||||
|
||||
puts "/*"
|
||||
puts "** If the argument is a codepoint corresponding to a lowercase letter"
|
||||
@@ -45,7 +49,7 @@ proc print_rd {map} {
|
||||
puts "** E\"). The resuls of passing a codepoint that corresponds to an"
|
||||
puts "** uppercase letter are undefined."
|
||||
puts "*/"
|
||||
puts "static int ${::remove_diacritic}(int c)\{"
|
||||
puts "static int ${::remove_diacritic}(int c, int bComplex)\{"
|
||||
puts " unsigned short aDia\[\] = \{"
|
||||
puts -nonewline " 0, "
|
||||
set i 1
|
||||
@@ -59,14 +63,19 @@ proc print_rd {map} {
|
||||
}
|
||||
puts ""
|
||||
puts " \};"
|
||||
puts " char aChar\[\] = \{"
|
||||
puts -nonewline " '\\0', "
|
||||
puts "#define HIBIT ((unsigned char)0x80)"
|
||||
puts " unsigned char aChar\[\] = \{"
|
||||
puts -nonewline " '\\0', "
|
||||
set i 1
|
||||
foreach c $aChar {
|
||||
set str "'$c', "
|
||||
if {$c == ""} { set str "'\\0', " }
|
||||
foreach c $aChar f $aFlag {
|
||||
if { $f } {
|
||||
set str "'$c'|HIBIT, "
|
||||
} else {
|
||||
set str "'$c', "
|
||||
}
|
||||
if {$c == ""} { set str "'\\0', " }
|
||||
|
||||
if {($i % 12)==0} {puts "" ; puts -nonewline " " }
|
||||
if {($i % 6)==0} {puts "" ; puts -nonewline " " }
|
||||
incr i
|
||||
puts -nonewline "$str"
|
||||
}
|
||||
@@ -87,7 +96,8 @@ proc print_rd {map} {
|
||||
}
|
||||
}
|
||||
assert( key>=aDia[iRes] );
|
||||
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);}
|
||||
if( bComplex==0 && (aChar[iRes] & 0x80) ) return c;
|
||||
return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F);}
|
||||
puts "\}"
|
||||
}
|
||||
|
||||
@@ -95,7 +105,8 @@ proc print_isdiacritic {zFunc map} {
|
||||
|
||||
set lCode [list]
|
||||
foreach m $map {
|
||||
foreach {code char} $m {}
|
||||
foreach {code char flag} $m {}
|
||||
if {$flag} continue
|
||||
if {$code && $char == ""} { lappend lCode $code }
|
||||
}
|
||||
set lCode [lsort -integer $lCode]
|
||||
@@ -124,8 +135,8 @@ proc print_isdiacritic {zFunc map} {
|
||||
|
||||
puts " if( c<$iFirst || c>$iLast ) return 0;"
|
||||
puts " return (c < $iFirst+32) ?"
|
||||
puts " (mask0 & (1 << (c-$iFirst))) :"
|
||||
puts " (mask1 & (1 << (c-$iFirst-32)));"
|
||||
puts " (mask0 & ((unsigned int)1 << (c-$iFirst))) :"
|
||||
puts " (mask1 & ((unsigned int)1 << (c-$iFirst-32)));"
|
||||
puts "\}"
|
||||
}
|
||||
|
||||
@@ -472,7 +483,7 @@ proc print_fold {zFunc} {
|
||||
puts "** The results are undefined if the value passed to this function"
|
||||
puts "** is less than zero."
|
||||
puts "*/"
|
||||
puts "int ${zFunc}\(int c, int bRemoveDiacritic)\{"
|
||||
puts "int ${zFunc}\(int c, int eRemoveDiacritic)\{"
|
||||
|
||||
set liOff [tl_generate_ioff_table $lRecord]
|
||||
tl_print_table_header
|
||||
@@ -516,7 +527,9 @@ proc print_fold {zFunc} {
|
||||
assert( ret>0 );
|
||||
}
|
||||
|
||||
if( bRemoveDiacritic ) ret = ${::remove_diacritic}(ret);
|
||||
if( eRemoveDiacritic ){
|
||||
ret = ${::remove_diacritic}(ret, eRemoveDiacritic==2);
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
||||
@@ -605,10 +618,6 @@ proc print_categories {lMap} {
|
||||
|
||||
set nCat [expr [llength [array names C]] + 1]
|
||||
puts [code {
|
||||
int sqlite3Fts5UnicodeNCat(void) {
|
||||
return $nCat;
|
||||
}
|
||||
|
||||
int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
||||
aArray[0] = 1;
|
||||
switch( zCat[0] ){
|
||||
@@ -691,7 +700,7 @@ proc print_categories {lMap} {
|
||||
static u16 aFts5UnicodeMap[] = {$aMapArray};
|
||||
static u16 aFts5UnicodeData[] = {$aDataArray};
|
||||
|
||||
int sqlite3Fts5UnicodeCategory(int iCode) {
|
||||
int sqlite3Fts5UnicodeCategory(u32 iCode) {
|
||||
int iRes = -1;
|
||||
int iHi;
|
||||
int iLo;
|
||||
@@ -774,7 +783,7 @@ proc print_test_categories {lMap} {
|
||||
aArray[0] = 1;
|
||||
}
|
||||
|
||||
c = sqlite3Fts5UnicodeCategory(i);
|
||||
c = sqlite3Fts5UnicodeCategory((u32)i);
|
||||
if( aArray[c]==0 ){
|
||||
*piCode = i;
|
||||
return 1;
|
||||
@@ -829,7 +838,7 @@ proc print_fold_test {zFunc mappings} {
|
||||
proc print_fileheader {} {
|
||||
puts [string trim {
|
||||
/*
|
||||
** 2012 May 25
|
||||
** 2012-05-25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
|
||||
@@ -7,12 +7,24 @@
|
||||
# character that it should be replaced with, or an empty string if the
|
||||
# codepoint should simply be removed from the input. Examples:
|
||||
#
|
||||
# { 224 a } (replace codepoint 224 to "a")
|
||||
# { 769 "" } (remove codepoint 769 from input)
|
||||
# { 224 a 0 } (replace codepoint 224 to "a")
|
||||
# { 769 "" 0 } (remove codepoint 769 from input)
|
||||
#
|
||||
# Mappings are only returned for non-upper case codepoints. It is assumed
|
||||
# that the input has already been folded to lower case.
|
||||
#
|
||||
# The third value in the list is always either 0 or 1. 0 if the
|
||||
# UnicodeData.txt file maps the codepoint to a single ASCII character and
|
||||
# a diacritic, or 1 if the mapping is indirect. For example, consider the
|
||||
# two entries:
|
||||
#
|
||||
# 1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC
|
||||
# 1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8
|
||||
#
|
||||
# The first codepoint is a direct mapping (as 006F is ASCII and 0323 is a
|
||||
# diacritic). The second is an indirect mapping, as it maps to the
|
||||
# first codepoint plus 0302 (a diacritic).
|
||||
#
|
||||
proc rd_load_unicodedata_text {zName} {
|
||||
global tl_lookup_table
|
||||
|
||||
@@ -53,18 +65,29 @@ proc rd_load_unicodedata_text {zName} {
|
||||
set iAscii [expr "0x[lindex $character_decomposition_mapping 0]"]
|
||||
set iDia [expr "0x[lindex $character_decomposition_mapping 1]"]
|
||||
|
||||
# Filter out upper-case characters, as they will be mapped to their
|
||||
# lower-case equivalents before this data is used.
|
||||
if {[info exists tl_lookup_table($iCode)]} continue
|
||||
|
||||
# Check if this is an indirect mapping. If so, set bIndirect to true
|
||||
# and change $iAscii to the indirectly mappped ASCII character.
|
||||
set bIndirect 0
|
||||
if {[info exists dia($iDia)] && [info exists mapping($iAscii)]} {
|
||||
set iAscii $mapping($iAscii)
|
||||
set bIndirect 1
|
||||
}
|
||||
|
||||
if { ($iAscii >= 97 && $iAscii <= 122)
|
||||
|| ($iAscii >= 65 && $iAscii <= 90)
|
||||
} {
|
||||
lappend lRet [list $iCode [string tolower [format %c $iAscii]]]
|
||||
lappend lRet [list $iCode [string tolower [format %c $iAscii]] $bIndirect]
|
||||
set mapping($iCode) $iAscii
|
||||
set dia($iDia) 1
|
||||
}
|
||||
}
|
||||
|
||||
foreach d [array names dia] {
|
||||
lappend lRet [list $d ""]
|
||||
lappend lRet [list $d "" 0]
|
||||
}
|
||||
set lRet [lsort -integer -index 0 $lRet]
|
||||
|
||||
|
||||
+8
-12
@@ -120,12 +120,8 @@ struct Fts5PhraseIter {
|
||||
**
|
||||
** Usually, output parameter *piPhrase is set to the phrase number, *piCol
|
||||
** to the column in which it occurs and *piOff the token offset of the
|
||||
** first token of the phrase. The exception is if the table was created
|
||||
** with the offsets=0 option specified. In this case *piOff is always
|
||||
** set to -1.
|
||||
**
|
||||
** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
|
||||
** if an error occurs.
|
||||
** first token of the phrase. Returns SQLITE_OK if successful, or an error
|
||||
** code (i.e. SQLITE_NOMEM) if an error occurs.
|
||||
**
|
||||
** This API can be quite slow if used with an FTS5 table created with the
|
||||
** "detail=none" or "detail=column" option.
|
||||
@@ -414,11 +410,11 @@ struct Fts5ExtensionApi {
|
||||
** the tokenizer substitutes "first" for "1st" and the query works
|
||||
** as expected.
|
||||
**
|
||||
** <li> By adding multiple synonyms for a single term to the FTS index.
|
||||
** In this case, when tokenizing query text, the tokenizer may
|
||||
** provide multiple synonyms for a single term within the document.
|
||||
** FTS5 then queries the index for each synonym individually. For
|
||||
** example, faced with the query:
|
||||
** <li> By querying the index for all synonyms of each query term
|
||||
** separately. In this case, when tokenizing query text, the
|
||||
** tokenizer may provide multiple synonyms for a single term
|
||||
** within the document. FTS5 then queries the index for each
|
||||
** synonym individually. For example, faced with the query:
|
||||
**
|
||||
** <codeblock>
|
||||
** ... MATCH 'first place'</codeblock>
|
||||
@@ -442,7 +438,7 @@ struct Fts5ExtensionApi {
|
||||
** "place".
|
||||
**
|
||||
** This way, even if the tokenizer does not provide synonyms
|
||||
** when tokenizing query text (it should not - to do would be
|
||||
** when tokenizing query text (it should not - to do so would be
|
||||
** inefficient), it doesn't matter if the user queries for
|
||||
** 'first + place' or '1st + place', as there are entries in the
|
||||
** FTS index corresponding to both forms of the first token.
|
||||
|
||||
+23
-5
@@ -87,6 +87,12 @@ extern int sqlite3_fts5_may_be_corrupt;
|
||||
# define assert_nc(x) assert(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A version of memcmp() that does not cause asan errors if one of the pointer
|
||||
** parameters is NULL and the number of bytes to compare is zero.
|
||||
*/
|
||||
#define fts5Memcmp(s1, s2, n) ((n)==0 ? 0 : memcmp((s1), (s2), (n)))
|
||||
|
||||
/* Mark a function parameter as unused, to suppress nuisance compiler
|
||||
** warnings. */
|
||||
#ifndef UNUSED_PARAM
|
||||
@@ -274,7 +280,7 @@ void sqlite3Fts5Put32(u8*, int);
|
||||
int sqlite3Fts5Get32(const u8*);
|
||||
|
||||
#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32)
|
||||
#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0xFFFFFFFF)
|
||||
#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF)
|
||||
|
||||
typedef struct Fts5PoslistReader Fts5PoslistReader;
|
||||
struct Fts5PoslistReader {
|
||||
@@ -309,7 +315,7 @@ int sqlite3Fts5PoslistNext64(
|
||||
);
|
||||
|
||||
/* Malloc utility */
|
||||
void *sqlite3Fts5MallocZero(int *pRc, int nByte);
|
||||
void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte);
|
||||
char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
|
||||
|
||||
/* Character set tests (like isspace(), isalpha() etc.) */
|
||||
@@ -520,9 +526,19 @@ int sqlite3Fts5PutVarint(unsigned char *p, u64 v);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
** Interface to code in fts5.c.
|
||||
** Interface to code in fts5_main.c.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Virtual-table object.
|
||||
*/
|
||||
typedef struct Fts5Table Fts5Table;
|
||||
struct Fts5Table {
|
||||
sqlite3_vtab base; /* Base class used by SQLite core */
|
||||
Fts5Config *pConfig; /* Virtual table configuration */
|
||||
Fts5Index *pIndex; /* Full-text index */
|
||||
};
|
||||
|
||||
int sqlite3Fts5GetTokenizer(
|
||||
Fts5Global*,
|
||||
const char **azArg,
|
||||
@@ -532,7 +548,9 @@ int sqlite3Fts5GetTokenizer(
|
||||
char **pzErr
|
||||
);
|
||||
|
||||
Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, Fts5Config **);
|
||||
Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
|
||||
|
||||
int sqlite3Fts5FlushToDisk(Fts5Table*);
|
||||
|
||||
/*
|
||||
** End of interface to code in fts5.c.
|
||||
@@ -788,7 +806,7 @@ int sqlite3Fts5UnicodeIsdiacritic(int c);
|
||||
int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
|
||||
|
||||
int sqlite3Fts5UnicodeCatParse(const char*, u8*);
|
||||
int sqlite3Fts5UnicodeCategory(int iCode);
|
||||
int sqlite3Fts5UnicodeCategory(u32 iCode);
|
||||
void sqlite3Fts5UnicodeAscii(u8*, u8*);
|
||||
/*
|
||||
** End of interface to code in fts5_unicode2.c.
|
||||
|
||||
+11
-9
@@ -136,7 +136,7 @@ static void fts5HighlightAppend(
|
||||
HighlightContext *p,
|
||||
const char *z, int n
|
||||
){
|
||||
if( *pRc==SQLITE_OK ){
|
||||
if( *pRc==SQLITE_OK && z ){
|
||||
if( n<0 ) n = (int)strlen(z);
|
||||
p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z);
|
||||
if( p->zOut==0 ) *pRc = SQLITE_NOMEM;
|
||||
@@ -268,7 +268,7 @@ static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){
|
||||
int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64;
|
||||
int *aNew;
|
||||
|
||||
aNew = (int*)sqlite3_realloc(p->aFirst, nNew*sizeof(int));
|
||||
aNew = (int*)sqlite3_realloc64(p->aFirst, nNew*sizeof(int));
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
p->aFirst = aNew;
|
||||
p->nFirstAlloc = nNew;
|
||||
@@ -335,11 +335,12 @@ static int fts5SnippetScore(
|
||||
int nInst;
|
||||
int nScore = 0;
|
||||
int iLast = 0;
|
||||
sqlite3_int64 iEnd = (sqlite3_int64)iPos + nToken;
|
||||
|
||||
rc = pApi->xInstCount(pFts, &nInst);
|
||||
for(i=0; i<nInst && rc==SQLITE_OK; i++){
|
||||
rc = pApi->xInst(pFts, i, &ip, &ic, &iOff);
|
||||
if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<(iPos+nToken) ){
|
||||
if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<iEnd ){
|
||||
nScore += (aSeen[ip] ? 1 : 1000);
|
||||
aSeen[ip] = 1;
|
||||
if( iFirst<0 ) iFirst = iOff;
|
||||
@@ -349,7 +350,7 @@ static int fts5SnippetScore(
|
||||
|
||||
*pnScore = nScore;
|
||||
if( piPos ){
|
||||
int iAdj = iFirst - (nToken - (iLast-iFirst)) / 2;
|
||||
sqlite3_int64 iAdj = iFirst - (nToken - (iLast-iFirst)) / 2;
|
||||
if( (iAdj+nToken)>nDocsize ) iAdj = nDocsize - nToken;
|
||||
if( iAdj<0 ) iAdj = 0;
|
||||
*piPos = iAdj;
|
||||
@@ -442,7 +443,9 @@ static void fts5SnippetFunction(
|
||||
int jj;
|
||||
|
||||
rc = pApi->xInst(pFts, ii, &ip, &ic, &io);
|
||||
if( ic!=i || rc!=SQLITE_OK ) continue;
|
||||
if( ic!=i ) continue;
|
||||
if( io>nDocsize ) rc = FTS5_CORRUPT;
|
||||
if( rc!=SQLITE_OK ) continue;
|
||||
memset(aSeen, 0, nPhrase);
|
||||
rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i,
|
||||
io, nToken, &nScore, &iAdj
|
||||
@@ -568,13 +571,13 @@ static int fts5Bm25GetData(
|
||||
int nPhrase; /* Number of phrases in query */
|
||||
sqlite3_int64 nRow = 0; /* Number of rows in table */
|
||||
sqlite3_int64 nToken = 0; /* Number of tokens in table */
|
||||
int nByte; /* Bytes of space to allocate */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate */
|
||||
int i;
|
||||
|
||||
/* Allocate the Fts5Bm25Data object */
|
||||
nPhrase = pApi->xPhraseCount(pFts);
|
||||
nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double);
|
||||
p = (Fts5Bm25Data*)sqlite3_malloc(nByte);
|
||||
p = (Fts5Bm25Data*)sqlite3_malloc64(nByte);
|
||||
if( p==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -586,6 +589,7 @@ static int fts5Bm25GetData(
|
||||
|
||||
/* Calculate the average document length for this FTS5 table */
|
||||
if( rc==SQLITE_OK ) rc = pApi->xRowCount(pFts, &nRow);
|
||||
assert( rc!=SQLITE_OK || nRow>0 );
|
||||
if( rc==SQLITE_OK ) rc = pApi->xColumnTotalSize(pFts, -1, &nToken);
|
||||
if( rc==SQLITE_OK ) p->avgdl = (double)nToken / (double)nRow;
|
||||
|
||||
@@ -710,5 +714,3 @@ int sqlite3Fts5AuxInit(fts5_api *pApi){
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
|
||||
int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){
|
||||
if( (u32)pBuf->nSpace<nByte ){
|
||||
u32 nNew = pBuf->nSpace ? pBuf->nSpace : 64;
|
||||
u64 nNew = pBuf->nSpace ? pBuf->nSpace : 64;
|
||||
u8 *pNew;
|
||||
while( nNew<nByte ){
|
||||
nNew = nNew * 2;
|
||||
}
|
||||
pNew = sqlite3_realloc(pBuf->p, nNew);
|
||||
pNew = sqlite3_realloc64(pBuf->p, nNew);
|
||||
if( pNew==0 ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
return 1;
|
||||
@@ -52,7 +52,7 @@ void sqlite3Fts5Put32(u8 *aBuf, int iVal){
|
||||
}
|
||||
|
||||
int sqlite3Fts5Get32(const u8 *aBuf){
|
||||
return (aBuf[0] << 24) + (aBuf[1] << 16) + (aBuf[2] << 8) + aBuf[3];
|
||||
return (int)((((u32)aBuf[0])<<24) + (aBuf[1]<<16) + (aBuf[2]<<8) + aBuf[3]);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -183,7 +183,7 @@ int sqlite3Fts5PoslistNext64(
|
||||
iOff = ((i64)iVal) << 32;
|
||||
fts5FastGetVarint32(a, i, iVal);
|
||||
}
|
||||
*piOff = iOff + (iVal-2);
|
||||
*piOff = iOff + ((iVal-2) & 0x7FFFFFFF);
|
||||
*pi = i;
|
||||
return 0;
|
||||
}
|
||||
@@ -244,10 +244,10 @@ int sqlite3Fts5PoslistWriterAppend(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
void *sqlite3Fts5MallocZero(int *pRc, int nByte){
|
||||
void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte){
|
||||
void *pRet = 0;
|
||||
if( *pRc==SQLITE_OK ){
|
||||
pRet = sqlite3_malloc(nByte);
|
||||
pRet = sqlite3_malloc64(nByte);
|
||||
if( pRet==0 ){
|
||||
if( nByte>0 ) *pRc = SQLITE_NOMEM;
|
||||
}else{
|
||||
|
||||
@@ -295,7 +295,7 @@ static int fts5ConfigParseSpecial(
|
||||
|
||||
if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
|
||||
const char *p = (const char*)zArg;
|
||||
int nArg = (int)strlen(zArg) + 1;
|
||||
sqlite3_int64 nArg = strlen(zArg) + 1;
|
||||
char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
|
||||
char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2);
|
||||
char *pSpace = pDel;
|
||||
@@ -425,8 +425,8 @@ static const char *fts5ConfigGobbleWord(
|
||||
){
|
||||
const char *zRet = 0;
|
||||
|
||||
int nIn = (int)strlen(zIn);
|
||||
char *zOut = sqlite3_malloc(nIn+1);
|
||||
sqlite3_int64 nIn = strlen(zIn);
|
||||
char *zOut = sqlite3_malloc64(nIn+1);
|
||||
|
||||
assert( *pRc==SQLITE_OK );
|
||||
*pbQuoted = 0;
|
||||
@@ -529,7 +529,7 @@ int sqlite3Fts5ConfigParse(
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
Fts5Config *pRet; /* New object to return */
|
||||
int i;
|
||||
int nByte;
|
||||
sqlite3_int64 nByte;
|
||||
|
||||
*ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
|
||||
if( pRet==0 ) return SQLITE_NOMEM;
|
||||
|
||||
+29
-26
@@ -211,7 +211,7 @@ static int fts5ExprGetToken(
|
||||
return tok;
|
||||
}
|
||||
|
||||
static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); }
|
||||
static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc64((sqlite3_int64)t);}
|
||||
static void fts5ParseFree(void *p){ sqlite3_free(p); }
|
||||
|
||||
int sqlite3Fts5ExprNew(
|
||||
@@ -356,8 +356,8 @@ static int fts5ExprSynonymList(
|
||||
if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){
|
||||
if( pIter->nData==0 ) continue;
|
||||
if( nIter==nAlloc ){
|
||||
int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
|
||||
Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte);
|
||||
sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
|
||||
Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc64(nByte);
|
||||
if( aNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto synonym_poslist_out;
|
||||
@@ -437,8 +437,8 @@ static int fts5ExprPhraseIsMatch(
|
||||
/* If the aStatic[] array is not large enough, allocate a large array
|
||||
** using sqlite3_malloc(). This approach could be improved upon. */
|
||||
if( pPhrase->nTerm>ArraySize(aStatic) ){
|
||||
int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
|
||||
aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte);
|
||||
sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
|
||||
aIter = (Fts5PoslistReader*)sqlite3_malloc64(nByte);
|
||||
if( !aIter ) return SQLITE_NOMEM;
|
||||
}
|
||||
memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm);
|
||||
@@ -572,7 +572,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
|
||||
/* If the aStatic[] array is not large enough, allocate a large array
|
||||
** using sqlite3_malloc(). This approach could be improved upon. */
|
||||
if( pNear->nPhrase>ArraySize(aStatic) ){
|
||||
int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
|
||||
sqlite3_int64 nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
|
||||
a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte);
|
||||
}else{
|
||||
memset(aStatic, 0, sizeof(aStatic));
|
||||
@@ -1481,8 +1481,9 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
|
||||
return pNear;
|
||||
}
|
||||
if( pNear==0 ){
|
||||
int nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
|
||||
pRet = sqlite3_malloc(nByte);
|
||||
sqlite3_int64 nByte;
|
||||
nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
|
||||
pRet = sqlite3_malloc64(nByte);
|
||||
if( pRet==0 ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1490,9 +1491,10 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
|
||||
}
|
||||
}else if( (pNear->nPhrase % SZALLOC)==0 ){
|
||||
int nNew = pNear->nPhrase + SZALLOC;
|
||||
int nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
|
||||
sqlite3_int64 nByte;
|
||||
|
||||
pRet = (Fts5ExprNearset*)sqlite3_realloc(pNear, nByte);
|
||||
nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
|
||||
pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte);
|
||||
if( pRet==0 ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -1556,8 +1558,8 @@ static int fts5ParseTokenize(
|
||||
|
||||
if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){
|
||||
Fts5ExprTerm *pSyn;
|
||||
int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
|
||||
pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte);
|
||||
sqlite3_int64 nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
|
||||
pSyn = (Fts5ExprTerm*)sqlite3_malloc64(nByte);
|
||||
if( pSyn==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1573,7 +1575,7 @@ static int fts5ParseTokenize(
|
||||
Fts5ExprPhrase *pNew;
|
||||
int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0);
|
||||
|
||||
pNew = (Fts5ExprPhrase*)sqlite3_realloc(pPhrase,
|
||||
pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase,
|
||||
sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew
|
||||
);
|
||||
if( pNew==0 ){
|
||||
@@ -1659,9 +1661,9 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
||||
|
||||
if( pAppend==0 ){
|
||||
if( (pParse->nPhrase % 8)==0 ){
|
||||
int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
|
||||
sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
|
||||
Fts5ExprPhrase **apNew;
|
||||
apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte);
|
||||
apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte);
|
||||
if( apNew==0 ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
fts5ExprPhraseFree(sCtx.pPhrase);
|
||||
@@ -1716,8 +1718,10 @@ int sqlite3Fts5ExprClonePhrase(
|
||||
if( rc==SQLITE_OK ){
|
||||
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
|
||||
if( pColsetOrig ){
|
||||
int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
|
||||
Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
|
||||
sqlite3_int64 nByte;
|
||||
Fts5Colset *pColset;
|
||||
nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
|
||||
pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
|
||||
if( pColset ){
|
||||
memcpy(pColset, pColsetOrig, nByte);
|
||||
}
|
||||
@@ -1837,7 +1841,7 @@ static Fts5Colset *fts5ParseColset(
|
||||
assert( pParse->rc==SQLITE_OK );
|
||||
assert( iCol>=0 && iCol<pParse->pConfig->nCol );
|
||||
|
||||
pNew = sqlite3_realloc(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
|
||||
pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
|
||||
if( pNew==0 ){
|
||||
pParse->rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1933,7 +1937,7 @@ Fts5Colset *sqlite3Fts5ParseColset(
|
||||
static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
|
||||
Fts5Colset *pRet;
|
||||
if( pOrig ){
|
||||
int nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
|
||||
sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
|
||||
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
|
||||
if( pRet ){
|
||||
memcpy(pRet, pOrig, nByte);
|
||||
@@ -2087,7 +2091,7 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
|
||||
|
||||
if( pParse->rc==SQLITE_OK ){
|
||||
int nChild = 0; /* Number of children of returned node */
|
||||
int nByte; /* Bytes of space to allocate for this node */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate for this node */
|
||||
|
||||
assert( (eType!=FTS5_STRING && !pNear)
|
||||
|| (eType==FTS5_STRING && !pLeft && !pRight)
|
||||
@@ -2219,7 +2223,7 @@ Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
|
||||
}
|
||||
|
||||
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
|
||||
int nByte = 0;
|
||||
sqlite3_int64 nByte = 0;
|
||||
Fts5ExprTerm *p;
|
||||
char *zQuoted;
|
||||
|
||||
@@ -2227,7 +2231,7 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
|
||||
for(p=pTerm; p; p=p->pSynonym){
|
||||
nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
|
||||
}
|
||||
zQuoted = sqlite3_malloc(nByte);
|
||||
zQuoted = sqlite3_malloc64(nByte);
|
||||
|
||||
if( zQuoted ){
|
||||
int i = 0;
|
||||
@@ -2467,7 +2471,7 @@ static void fts5ExprFunction(
|
||||
}
|
||||
|
||||
nConfig = 3 + (nArg-iArg);
|
||||
azConfig = (const char**)sqlite3_malloc(sizeof(char*) * nConfig);
|
||||
azConfig = (const char**)sqlite3_malloc64(sizeof(char*) * nConfig);
|
||||
if( azConfig==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return;
|
||||
@@ -2553,7 +2557,7 @@ static void fts5ExprIsAlnum(
|
||||
sqlite3Fts5UnicodeCatParse("N*", aArr);
|
||||
sqlite3Fts5UnicodeCatParse("Co", aArr);
|
||||
iCode = sqlite3_value_int(apVal[0]);
|
||||
sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory(iCode)]);
|
||||
sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory((u32)iCode)]);
|
||||
}
|
||||
|
||||
static void fts5ExprFold(
|
||||
@@ -2648,7 +2652,7 @@ struct Fts5PoslistPopulator {
|
||||
|
||||
Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){
|
||||
Fts5PoslistPopulator *pRet;
|
||||
pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
|
||||
pRet = sqlite3_malloc64(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
|
||||
if( pRet ){
|
||||
int i;
|
||||
memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
|
||||
@@ -2847,4 +2851,3 @@ int sqlite3Fts5ExprPhraseCollist(
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+11
-11
@@ -90,14 +90,14 @@ int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){
|
||||
if( pNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
int nByte;
|
||||
sqlite3_int64 nByte;
|
||||
memset(pNew, 0, sizeof(Fts5Hash));
|
||||
pNew->pnByte = pnByte;
|
||||
pNew->eDetail = pConfig->eDetail;
|
||||
|
||||
pNew->nSlot = 1024;
|
||||
nByte = sizeof(Fts5HashEntry*) * pNew->nSlot;
|
||||
pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte);
|
||||
pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc64(nByte);
|
||||
if( pNew->aSlot==0 ){
|
||||
sqlite3_free(pNew);
|
||||
*ppNew = 0;
|
||||
@@ -165,7 +165,7 @@ static int fts5HashResize(Fts5Hash *pHash){
|
||||
Fts5HashEntry **apNew;
|
||||
Fts5HashEntry **apOld = pHash->aSlot;
|
||||
|
||||
apNew = (Fts5HashEntry**)sqlite3_malloc(nNew*sizeof(Fts5HashEntry*));
|
||||
apNew = (Fts5HashEntry**)sqlite3_malloc64(nNew*sizeof(Fts5HashEntry*));
|
||||
if( !apNew ) return SQLITE_NOMEM;
|
||||
memset(apNew, 0, nNew*sizeof(Fts5HashEntry*));
|
||||
|
||||
@@ -259,7 +259,7 @@ int sqlite3Fts5HashWrite(
|
||||
if( p==0 ){
|
||||
/* Figure out how much space to allocate */
|
||||
char *zKey;
|
||||
int nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64;
|
||||
sqlite3_int64 nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64;
|
||||
if( nByte<128 ) nByte = 128;
|
||||
|
||||
/* Grow the Fts5Hash.aSlot[] array if necessary. */
|
||||
@@ -270,7 +270,7 @@ int sqlite3Fts5HashWrite(
|
||||
}
|
||||
|
||||
/* Allocate new Fts5HashEntry and add it to the hash table. */
|
||||
p = (Fts5HashEntry*)sqlite3_malloc(nByte);
|
||||
p = (Fts5HashEntry*)sqlite3_malloc64(nByte);
|
||||
if( !p ) return SQLITE_NOMEM;
|
||||
memset(p, 0, sizeof(Fts5HashEntry));
|
||||
p->nAlloc = nByte;
|
||||
@@ -309,12 +309,12 @@ int sqlite3Fts5HashWrite(
|
||||
** + 5 bytes for the new position offset (32-bit max).
|
||||
*/
|
||||
if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
|
||||
int nNew = p->nAlloc * 2;
|
||||
sqlite3_int64 nNew = p->nAlloc * 2;
|
||||
Fts5HashEntry *pNew;
|
||||
Fts5HashEntry **pp;
|
||||
pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
|
||||
pNew = (Fts5HashEntry*)sqlite3_realloc64(p, nNew);
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
pNew->nAlloc = nNew;
|
||||
pNew->nAlloc = (int)nNew;
|
||||
for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
|
||||
*pp = pNew;
|
||||
p = pNew;
|
||||
@@ -438,7 +438,7 @@ static int fts5HashEntrySort(
|
||||
int i;
|
||||
|
||||
*ppSorted = 0;
|
||||
ap = sqlite3_malloc(sizeof(Fts5HashEntry*) * nMergeSlot);
|
||||
ap = sqlite3_malloc64(sizeof(Fts5HashEntry*) * nMergeSlot);
|
||||
if( !ap ) return SQLITE_NOMEM;
|
||||
memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot);
|
||||
|
||||
@@ -483,7 +483,8 @@ int sqlite3Fts5HashQuery(
|
||||
|
||||
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
|
||||
zKey = fts5EntryKey(p);
|
||||
if( memcmp(zKey, pTerm, nTerm)==0 && zKey[nTerm]==0 ) break;
|
||||
assert( p->nKey+1==(int)strlen(zKey) );
|
||||
if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break;
|
||||
}
|
||||
|
||||
if( p ){
|
||||
@@ -534,4 +535,3 @@ void sqlite3Fts5HashScanEntry(
|
||||
*pnDoclist = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+154
-99
@@ -512,7 +512,6 @@ struct Fts5Iter {
|
||||
Fts5IndexIter base; /* Base class containing output vars */
|
||||
|
||||
Fts5Index *pIndex; /* Index that owns this iterator */
|
||||
Fts5Structure *pStruct; /* Database structure for this iterator */
|
||||
Fts5Buffer poslist; /* Buffer containing current poslist */
|
||||
Fts5Colset *pColset; /* Restrict matches to these columns */
|
||||
|
||||
@@ -573,7 +572,7 @@ static u16 fts5GetU16(const u8 *aIn){
|
||||
** If an OOM error is encountered, return NULL and set the error code in
|
||||
** the Fts5Index handle passed as the first argument.
|
||||
*/
|
||||
static void *fts5IdxMalloc(Fts5Index *p, int nByte){
|
||||
static void *fts5IdxMalloc(Fts5Index *p, sqlite3_int64 nByte){
|
||||
return sqlite3Fts5MallocZero(&p->rc, nByte);
|
||||
}
|
||||
|
||||
@@ -607,7 +606,7 @@ static int fts5BufferCompareBlob(
|
||||
*/
|
||||
static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){
|
||||
int nCmp = MIN(pLeft->n, pRight->n);
|
||||
int res = memcmp(pLeft->p, pRight->p, nCmp);
|
||||
int res = fts5Memcmp(pLeft->p, pRight->p, nCmp);
|
||||
return (res==0 ? (pLeft->n - pRight->n) : res);
|
||||
}
|
||||
|
||||
@@ -673,8 +672,8 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
||||
if( rc==SQLITE_OK ){
|
||||
u8 *aOut = 0; /* Read blob data into this buffer */
|
||||
int nByte = sqlite3_blob_bytes(p->pReader);
|
||||
int nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
|
||||
pRet = (Fts5Data*)sqlite3_malloc(nAlloc);
|
||||
sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
|
||||
pRet = (Fts5Data*)sqlite3_malloc64(nAlloc);
|
||||
if( pRet ){
|
||||
pRet->nn = nByte;
|
||||
aOut = pRet->p = (u8*)&pRet[1];
|
||||
@@ -690,6 +689,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
||||
pRet = 0;
|
||||
}else{
|
||||
/* TODO1: Fix this */
|
||||
pRet->p[nByte] = 0x00;
|
||||
pRet->szLeaf = fts5GetU16(&pRet->p[2]);
|
||||
}
|
||||
}
|
||||
@@ -729,7 +729,8 @@ static int fts5IndexPrepareStmt(
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( zSql ){
|
||||
p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
|
||||
SQLITE_PREPARE_PERSISTENT, ppStmt, 0);
|
||||
SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB,
|
||||
ppStmt, 0);
|
||||
}else{
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -770,23 +771,12 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
|
||||
if( p->rc!=SQLITE_OK ) return;
|
||||
|
||||
if( p->pDeleter==0 ){
|
||||
int rc;
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
char *zSql = sqlite3_mprintf(
|
||||
"DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?",
|
||||
pConfig->zDb, pConfig->zName
|
||||
);
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
|
||||
SQLITE_PREPARE_PERSISTENT, &p->pDeleter, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
p->rc = rc;
|
||||
return;
|
||||
}
|
||||
if( fts5IndexPrepareStmt(p, &p->pDeleter, zSql) ) return;
|
||||
}
|
||||
|
||||
sqlite3_bind_int64(p->pDeleter, 1, iFirst);
|
||||
@@ -858,7 +848,7 @@ static int fts5StructureDecode(
|
||||
int iLvl;
|
||||
int nLevel = 0;
|
||||
int nSegment = 0;
|
||||
int nByte; /* Bytes of space to allocate at pRet */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate at pRet */
|
||||
Fts5Structure *pRet = 0; /* Structure object to return */
|
||||
|
||||
/* Grab the cookie value */
|
||||
@@ -869,6 +859,11 @@ static int fts5StructureDecode(
|
||||
** structure record. */
|
||||
i += fts5GetVarint32(&pData[i], nLevel);
|
||||
i += fts5GetVarint32(&pData[i], nSegment);
|
||||
if( nLevel>FTS5_MAX_SEGMENT || nLevel<0
|
||||
|| nSegment>FTS5_MAX_SEGMENT || nSegment<0
|
||||
){
|
||||
return FTS5_CORRUPT;
|
||||
}
|
||||
nByte = (
|
||||
sizeof(Fts5Structure) + /* Main structure */
|
||||
sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */
|
||||
@@ -891,25 +886,35 @@ static int fts5StructureDecode(
|
||||
}else{
|
||||
i += fts5GetVarint32(&pData[i], pLvl->nMerge);
|
||||
i += fts5GetVarint32(&pData[i], nTotal);
|
||||
assert( nTotal>=pLvl->nMerge );
|
||||
if( nTotal<pLvl->nMerge ) rc = FTS5_CORRUPT;
|
||||
pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc,
|
||||
nTotal * sizeof(Fts5StructureSegment)
|
||||
);
|
||||
nSegment -= nTotal;
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
pLvl->nSeg = nTotal;
|
||||
for(iSeg=0; iSeg<nTotal; iSeg++){
|
||||
Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
|
||||
if( i>=nData ){
|
||||
rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid);
|
||||
i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst);
|
||||
i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast);
|
||||
i += fts5GetVarint32(&pData[i], pSeg->iSegid);
|
||||
i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst);
|
||||
i += fts5GetVarint32(&pData[i], pSeg->pgnoLast);
|
||||
if( pSeg->pgnoLast<pSeg->pgnoFirst ){
|
||||
rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( iLvl>0 && pLvl[-1].nMerge && nTotal==0 ) rc = FTS5_CORRUPT;
|
||||
if( iLvl==nLevel-1 && pLvl->nMerge ) rc = FTS5_CORRUPT;
|
||||
}
|
||||
}
|
||||
if( nSegment!=0 && rc==SQLITE_OK ) rc = FTS5_CORRUPT;
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
fts5StructureRelease(pRet);
|
||||
pRet = 0;
|
||||
@@ -927,12 +932,12 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
|
||||
if( *pRc==SQLITE_OK ){
|
||||
Fts5Structure *pStruct = *ppStruct;
|
||||
int nLevel = pStruct->nLevel;
|
||||
int nByte = (
|
||||
sqlite3_int64 nByte = (
|
||||
sizeof(Fts5Structure) + /* Main structure */
|
||||
sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */
|
||||
);
|
||||
|
||||
pStruct = sqlite3_realloc(pStruct, nByte);
|
||||
pStruct = sqlite3_realloc64(pStruct, nByte);
|
||||
if( pStruct ){
|
||||
memset(&pStruct->aLevel[nLevel], 0, sizeof(Fts5StructureLevel));
|
||||
pStruct->nLevel++;
|
||||
@@ -957,10 +962,10 @@ static void fts5StructureExtendLevel(
|
||||
if( *pRc==SQLITE_OK ){
|
||||
Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
|
||||
Fts5StructureSegment *aNew;
|
||||
int nByte;
|
||||
sqlite3_int64 nByte;
|
||||
|
||||
nByte = (pLvl->nSeg + nExtra) * sizeof(Fts5StructureSegment);
|
||||
aNew = sqlite3_realloc(pLvl->aSeg, nByte);
|
||||
aNew = sqlite3_realloc64(pLvl->aSeg, nByte);
|
||||
if( aNew ){
|
||||
if( bInsert==0 ){
|
||||
memset(&aNew[pLvl->nSeg], 0, sizeof(Fts5StructureSegment) * nExtra);
|
||||
@@ -1474,10 +1479,10 @@ static Fts5DlidxIter *fts5DlidxIterInit(
|
||||
int bDone = 0;
|
||||
|
||||
for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
|
||||
int nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl);
|
||||
sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl);
|
||||
Fts5DlidxIter *pNew;
|
||||
|
||||
pNew = (Fts5DlidxIter*)sqlite3_realloc(pIter, nByte);
|
||||
pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte);
|
||||
if( pNew==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1647,12 +1652,13 @@ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
|
||||
int nNew; /* Bytes of new data */
|
||||
|
||||
iOff += fts5GetVarint32(&a[iOff], nNew);
|
||||
if( iOff+nNew>pIter->pLeaf->nn ){
|
||||
if( iOff+nNew>pIter->pLeaf->szLeaf || nKeep>pIter->term.n || nNew==0 ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
return;
|
||||
}
|
||||
pIter->term.n = nKeep;
|
||||
fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]);
|
||||
assert( pIter->term.n<=pIter->term.nSpace );
|
||||
iOff += nNew;
|
||||
pIter->iTermLeafOffset = iOff;
|
||||
pIter->iTermLeafPgno = pIter->iLeafPgno;
|
||||
@@ -1717,7 +1723,7 @@ static void fts5SegIterInit(
|
||||
if( p->rc==SQLITE_OK ){
|
||||
pIter->iLeafOffset = 4;
|
||||
assert_nc( pIter->pLeaf->nn>4 );
|
||||
assert( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
|
||||
assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
|
||||
pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
|
||||
fts5SegIterLoadTerm(p, pIter, 0);
|
||||
fts5SegIterLoadNPos(p, pIter);
|
||||
@@ -1773,7 +1779,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
|
||||
/* If necessary, grow the pIter->aRowidOffset[] array. */
|
||||
if( iRowidOffset>=pIter->nRowidOffset ){
|
||||
int nNew = pIter->nRowidOffset + 8;
|
||||
int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int));
|
||||
int *aNew = (int*)sqlite3_realloc64(pIter->aRowidOffset,nNew*sizeof(int));
|
||||
if( aNew==0 ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
break;
|
||||
@@ -2227,10 +2233,10 @@ static void fts5LeafSeek(
|
||||
int szLeaf = pIter->pLeaf->szLeaf;
|
||||
int n = pIter->pLeaf->nn;
|
||||
|
||||
int nMatch = 0;
|
||||
int nKeep = 0;
|
||||
int nNew = 0;
|
||||
int iTermOff;
|
||||
u32 nMatch = 0;
|
||||
u32 nKeep = 0;
|
||||
u32 nNew = 0;
|
||||
u32 iTermOff;
|
||||
int iPgidx; /* Current offset in pgidx */
|
||||
int bEndOfPage = 0;
|
||||
|
||||
@@ -2254,15 +2260,15 @@ static void fts5LeafSeek(
|
||||
|
||||
assert( nKeep>=nMatch );
|
||||
if( nKeep==nMatch ){
|
||||
int nCmp;
|
||||
int i;
|
||||
nCmp = MIN(nNew, nTerm-nMatch);
|
||||
u32 nCmp;
|
||||
u32 i;
|
||||
nCmp = (u32)MIN(nNew, nTerm-nMatch);
|
||||
for(i=0; i<nCmp; i++){
|
||||
if( a[iOff+i]!=pTerm[nMatch+i] ) break;
|
||||
}
|
||||
nMatch += i;
|
||||
|
||||
if( nTerm==nMatch ){
|
||||
if( (u32)nTerm==nMatch ){
|
||||
if( i==nNew ){
|
||||
goto search_success;
|
||||
}else{
|
||||
@@ -2306,6 +2312,7 @@ static void fts5LeafSeek(
|
||||
iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff);
|
||||
if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
return;
|
||||
}else{
|
||||
nKeep = 0;
|
||||
iTermOff = iOff;
|
||||
@@ -2318,8 +2325,11 @@ static void fts5LeafSeek(
|
||||
}
|
||||
|
||||
search_success:
|
||||
|
||||
pIter->iLeafOffset = iOff + nNew;
|
||||
if( pIter->iLeafOffset>n || nNew<1 ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
return;
|
||||
}
|
||||
pIter->iTermLeafOffset = pIter->iLeafOffset;
|
||||
pIter->iTermLeafPgno = pIter->iLeafPgno;
|
||||
|
||||
@@ -2426,7 +2436,7 @@ static void fts5SegIterSeekInit(
|
||||
** 4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points
|
||||
** to an entry with a term greater than or equal to (pTerm/nTerm).
|
||||
*/
|
||||
assert( p->rc!=SQLITE_OK /* 1 */
|
||||
assert_nc( p->rc!=SQLITE_OK /* 1 */
|
||||
|| pIter->pLeaf==0 /* 2 */
|
||||
|| fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */
|
||||
|| (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */
|
||||
@@ -2524,7 +2534,7 @@ static void fts5AssertComparisonResult(
|
||||
assert( pRes->iFirst==i1 );
|
||||
}else{
|
||||
int nMin = MIN(p1->term.n, p2->term.n);
|
||||
int res = memcmp(p1->term.p, p2->term.p, nMin);
|
||||
int res = fts5Memcmp(p1->term.p, p2->term.p, nMin);
|
||||
if( res==0 ) res = p1->term.n - p2->term.n;
|
||||
|
||||
if( res==0 ){
|
||||
@@ -2747,7 +2757,6 @@ static void fts5MultiIterFree(Fts5Iter *pIter){
|
||||
for(i=0; i<pIter->nSeg; i++){
|
||||
fts5SegIterClear(&pIter->aSeg[i]);
|
||||
}
|
||||
fts5StructureRelease(pIter->pStruct);
|
||||
fts5BufferFree(&pIter->poslist);
|
||||
sqlite3_free(pIter);
|
||||
}
|
||||
@@ -3095,7 +3104,8 @@ static void fts5SegiterPoslist(
|
||||
Fts5Colset *pColset,
|
||||
Fts5Buffer *pBuf
|
||||
){
|
||||
if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
|
||||
if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+FTS5_DATA_ZERO_PADDING) ){
|
||||
memset(&pBuf->p[pBuf->n+pSeg->nPos], 0, FTS5_DATA_ZERO_PADDING);
|
||||
if( pColset==0 ){
|
||||
fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
|
||||
}else{
|
||||
@@ -3393,9 +3403,7 @@ static void fts5MultiIterNew(
|
||||
if( pNew==0 ) return;
|
||||
pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC));
|
||||
pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY));
|
||||
pNew->pStruct = pStruct;
|
||||
pNew->pColset = pColset;
|
||||
fts5StructureRef(pStruct);
|
||||
if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){
|
||||
fts5IterSetOutputCb(&p->rc, pNew);
|
||||
}
|
||||
@@ -3573,24 +3581,24 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
|
||||
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
|
||||
for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
|
||||
int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid;
|
||||
if( iId<=FTS5_MAX_SEGMENT ){
|
||||
aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32);
|
||||
if( iId<=FTS5_MAX_SEGMENT && iId>0 ){
|
||||
aUsed[(iId-1) / 32] |= (u32)1 << ((iId-1) % 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; aUsed[i]==0xFFFFFFFF; i++);
|
||||
mask = aUsed[i];
|
||||
for(iSegid=0; mask & (1 << iSegid); iSegid++);
|
||||
for(iSegid=0; mask & ((u32)1 << iSegid); iSegid++);
|
||||
iSegid += 1 + i*32;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
|
||||
for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
|
||||
assert( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
|
||||
assert_nc( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
|
||||
}
|
||||
}
|
||||
assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
|
||||
assert_nc( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
|
||||
|
||||
{
|
||||
sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p);
|
||||
@@ -3598,7 +3606,7 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
|
||||
u8 aBlob[2] = {0xff, 0xff};
|
||||
sqlite3_bind_int(pIdxSelect, 1, iSegid);
|
||||
sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC);
|
||||
assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
|
||||
assert_nc( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
|
||||
p->rc = sqlite3_reset(pIdxSelect);
|
||||
sqlite3_bind_null(pIdxSelect, 2);
|
||||
}
|
||||
@@ -3668,7 +3676,7 @@ static int fts5WriteDlidxGrow(
|
||||
int nLvl
|
||||
){
|
||||
if( p->rc==SQLITE_OK && nLvl>=pWriter->nDlidx ){
|
||||
Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc(
|
||||
Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc64(
|
||||
pWriter->aDlidx, sizeof(Fts5DlidxWriter) * nLvl
|
||||
);
|
||||
if( aDlidx==0 ){
|
||||
@@ -3747,8 +3755,10 @@ static void fts5WriteBtreeTerm(
|
||||
int nTerm, const u8 *pTerm /* First term on new page */
|
||||
){
|
||||
fts5WriteFlushBtree(p, pWriter);
|
||||
fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm);
|
||||
pWriter->iBtPage = pWriter->writer.pgno;
|
||||
if( p->rc==SQLITE_OK ){
|
||||
fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm);
|
||||
pWriter->iBtPage = pWriter->writer.pgno;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3899,6 +3909,7 @@ static void fts5WriteAppendTerm(
|
||||
int nPrefix; /* Bytes of prefix compression for term */
|
||||
Fts5PageWriter *pPage = &pWriter->writer;
|
||||
Fts5Buffer *pPgidx = &pWriter->writer.pgidx;
|
||||
int nMin = MIN(pPage->term.n, nTerm);
|
||||
|
||||
assert( p->rc==SQLITE_OK );
|
||||
assert( pPage->buf.n>=4 );
|
||||
@@ -3908,6 +3919,7 @@ static void fts5WriteAppendTerm(
|
||||
if( (pPage->buf.n + pPgidx->n + nTerm + 2)>=p->pConfig->pgsz ){
|
||||
if( pPage->buf.n>4 ){
|
||||
fts5WriteFlushLeaf(p, pWriter);
|
||||
if( p->rc!=SQLITE_OK ) return;
|
||||
}
|
||||
fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING);
|
||||
}
|
||||
@@ -3940,13 +3952,14 @@ static void fts5WriteAppendTerm(
|
||||
** inefficient, but still correct. */
|
||||
int n = nTerm;
|
||||
if( pPage->term.n ){
|
||||
n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
|
||||
n = 1 + fts5PrefixCompress(nMin, pPage->term.p, pTerm);
|
||||
}
|
||||
fts5WriteBtreeTerm(p, pWriter, n, pTerm);
|
||||
if( p->rc!=SQLITE_OK ) return;
|
||||
pPage = &pWriter->writer;
|
||||
}
|
||||
}else{
|
||||
nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
|
||||
nPrefix = fts5PrefixCompress(nMin, pPage->term.p, pTerm);
|
||||
fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix);
|
||||
}
|
||||
|
||||
@@ -3993,7 +4006,7 @@ static void fts5WriteAppendRowid(
|
||||
if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){
|
||||
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
|
||||
}else{
|
||||
assert( p->rc || iRowid>pWriter->iPrevRowid );
|
||||
assert_nc( p->rc || iRowid>pWriter->iPrevRowid );
|
||||
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
|
||||
}
|
||||
pWriter->iPrevRowid = iRowid;
|
||||
@@ -4115,7 +4128,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
|
||||
int i;
|
||||
Fts5Buffer buf;
|
||||
memset(&buf, 0, sizeof(Fts5Buffer));
|
||||
for(i=0; i<pIter->nSeg; i++){
|
||||
for(i=0; i<pIter->nSeg && p->rc==SQLITE_OK; i++){
|
||||
Fts5SegIter *pSeg = &pIter->aSeg[i];
|
||||
if( pSeg->pSeg==0 ){
|
||||
/* no-op */
|
||||
@@ -4133,35 +4146,43 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
|
||||
u8 aHdr[4] = {0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
iLeafRowid = FTS5_SEGMENT_ROWID(iId, pSeg->iTermLeafPgno);
|
||||
pData = fts5DataRead(p, iLeafRowid);
|
||||
pData = fts5LeafRead(p, iLeafRowid);
|
||||
if( pData ){
|
||||
fts5BufferZero(&buf);
|
||||
fts5BufferGrow(&p->rc, &buf, pData->nn);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
|
||||
fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff, &pData->p[iOff]);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
/* Set the szLeaf field */
|
||||
fts5PutU16(&buf.p[2], (u16)buf.n);
|
||||
}
|
||||
if( iOff>pData->szLeaf ){
|
||||
/* This can occur if the pages that the segments occupy overlap - if
|
||||
** a single page has been assigned to more than one segment. In
|
||||
** this case a prior iteration of this loop may have corrupted the
|
||||
** segment currently being trimmed. */
|
||||
p->rc = FTS5_CORRUPT;
|
||||
}else{
|
||||
fts5BufferZero(&buf);
|
||||
fts5BufferGrow(&p->rc, &buf, pData->nn);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
|
||||
fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
/* Set the szLeaf field */
|
||||
fts5PutU16(&buf.p[2], (u16)buf.n);
|
||||
}
|
||||
|
||||
/* Set up the new page-index array */
|
||||
fts5BufferAppendVarint(&p->rc, &buf, 4);
|
||||
if( pSeg->iLeafPgno==pSeg->iTermLeafPgno
|
||||
&& pSeg->iEndofDoclist<pData->szLeaf
|
||||
){
|
||||
int nDiff = pData->szLeaf - pSeg->iEndofDoclist;
|
||||
fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4);
|
||||
fts5BufferAppendBlob(&p->rc, &buf,
|
||||
pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff]
|
||||
);
|
||||
}
|
||||
/* Set up the new page-index array */
|
||||
fts5BufferAppendVarint(&p->rc, &buf, 4);
|
||||
if( pSeg->iLeafPgno==pSeg->iTermLeafPgno
|
||||
&& pSeg->iEndofDoclist<pData->szLeaf
|
||||
){
|
||||
int nDiff = pData->szLeaf - pSeg->iEndofDoclist;
|
||||
fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4);
|
||||
fts5BufferAppendBlob(&p->rc, &buf,
|
||||
pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff]
|
||||
);
|
||||
}
|
||||
|
||||
pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno;
|
||||
fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid);
|
||||
fts5DataWrite(p, iLeafRowid, buf.p, buf.n);
|
||||
}
|
||||
fts5DataRelease(pData);
|
||||
pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno;
|
||||
fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid);
|
||||
fts5DataWrite(p, iLeafRowid, buf.p, buf.n);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4253,7 +4274,7 @@ static void fts5IndexMergeLevel(
|
||||
const u8 *pTerm;
|
||||
|
||||
pTerm = fts5MultiIterTerm(pIter, &nTerm);
|
||||
if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){
|
||||
if( nTerm!=term.n || fts5Memcmp(pTerm, term.p, nTerm) ){
|
||||
if( pnRem && writer.nLeafWritten>nRem ){
|
||||
break;
|
||||
}
|
||||
@@ -4508,6 +4529,7 @@ static void fts5FlushOneHash(Fts5Index *p){
|
||||
/* Write the term for this entry to disk. */
|
||||
sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
|
||||
fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
|
||||
if( p->rc!=SQLITE_OK ) break;
|
||||
|
||||
assert( writer.bFirstRowidInPage==0 );
|
||||
if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
|
||||
@@ -4530,6 +4552,7 @@ static void fts5FlushOneHash(Fts5Index *p){
|
||||
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
|
||||
writer.bFirstRowidInPage = 0;
|
||||
fts5WriteDlidxAppend(p, &writer, iRowid);
|
||||
if( p->rc!=SQLITE_OK ) break;
|
||||
}else{
|
||||
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
|
||||
}
|
||||
@@ -4587,7 +4610,7 @@ static void fts5FlushOneHash(Fts5Index *p){
|
||||
/* TODO2: Doclist terminator written here. */
|
||||
/* pBuf->p[pBuf->n++] = '\0'; */
|
||||
assert( pBuf->n<=pBuf->nSpace );
|
||||
sqlite3Fts5HashScanNext(pHash);
|
||||
if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash);
|
||||
}
|
||||
sqlite3Fts5HashClear(pHash);
|
||||
fts5WriteFinish(p, &writer, &pgnoLast);
|
||||
@@ -4631,7 +4654,7 @@ static Fts5Structure *fts5IndexOptimizeStruct(
|
||||
Fts5Structure *pStruct
|
||||
){
|
||||
Fts5Structure *pNew = 0;
|
||||
int nByte = sizeof(Fts5Structure);
|
||||
sqlite3_int64 nByte = sizeof(Fts5Structure);
|
||||
int nSeg = pStruct->nSegment;
|
||||
int i;
|
||||
|
||||
@@ -4761,11 +4784,13 @@ static void fts5AppendPoslist(
|
||||
Fts5Buffer *pBuf
|
||||
){
|
||||
int nData = pMulti->base.nData;
|
||||
int nByte = nData + 9 + 9 + FTS5_DATA_ZERO_PADDING;
|
||||
assert( nData>0 );
|
||||
if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nData+9+9) ){
|
||||
if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nByte) ){
|
||||
fts5BufferSafeAppendVarint(pBuf, iDelta);
|
||||
fts5BufferSafeAppendVarint(pBuf, nData*2);
|
||||
fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData);
|
||||
memset(&pBuf->p[pBuf->n], 0, FTS5_DATA_ZERO_PADDING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4946,6 +4971,8 @@ static void fts5MergePrefixLists(
|
||||
int iOff2 = 0;
|
||||
u8 *a1 = &i1.aPoslist[i1.nSize];
|
||||
u8 *a2 = &i2.aPoslist[i2.nSize];
|
||||
int nCopy;
|
||||
u8 *aCopy;
|
||||
|
||||
i64 iPrev = 0;
|
||||
Fts5PoslistWriter writer;
|
||||
@@ -4977,7 +5004,7 @@ static void fts5MergePrefixLists(
|
||||
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
|
||||
if( iPos1<0 ) break;
|
||||
}else{
|
||||
assert( iPos2!=iPrev );
|
||||
assert_nc( iPos2!=iPrev );
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
|
||||
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
|
||||
if( iPos2<0 ) break;
|
||||
@@ -4989,11 +5016,16 @@ static void fts5MergePrefixLists(
|
||||
if( iPos1!=iPrev ){
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
|
||||
}
|
||||
fts5BufferSafeAppendBlob(&tmp, &a1[iOff1], i1.nPoslist-iOff1);
|
||||
aCopy = &a1[iOff1];
|
||||
nCopy = i1.nPoslist - iOff1;
|
||||
}else{
|
||||
assert( iPos2>=0 && iPos2!=iPrev );
|
||||
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
|
||||
fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2);
|
||||
aCopy = &a2[iOff2];
|
||||
nCopy = i2.nPoslist - iOff2;
|
||||
}
|
||||
if( nCopy>0 ){
|
||||
fts5BufferSafeAppendBlob(&tmp, aCopy, nCopy);
|
||||
}
|
||||
|
||||
/* WRITEPOSLISTSIZE */
|
||||
@@ -5001,6 +5033,7 @@ static void fts5MergePrefixLists(
|
||||
fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
|
||||
fts5DoclistIterNext(&i1);
|
||||
fts5DoclistIterNext(&i2);
|
||||
assert( out.n<=(p1->n+p2->n+9) );
|
||||
if( i1.aPoslist==0 || i2.aPoslist==0 ) break;
|
||||
}
|
||||
}
|
||||
@@ -5102,7 +5135,7 @@ static void fts5SetupPrefixIter(
|
||||
}
|
||||
fts5MultiIterFree(p1);
|
||||
|
||||
pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n);
|
||||
pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING);
|
||||
if( pData ){
|
||||
pData->p = (u8*)&pData[1];
|
||||
pData->nn = pData->szLeaf = doclist.n;
|
||||
@@ -5864,11 +5897,11 @@ static void fts5IndexIntegrityCheckSegment(
|
||||
|
||||
iOff = fts5LeafFirstTermOff(pLeaf);
|
||||
iRowidOff = fts5LeafFirstRowidOff(pLeaf);
|
||||
if( iRowidOff>=iOff ){
|
||||
if( iRowidOff>=iOff || iOff>=pLeaf->szLeaf ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
}else{
|
||||
iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm);
|
||||
res = memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm));
|
||||
res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm));
|
||||
if( res==0 ) res = nTerm - nIdxTerm;
|
||||
if( res<0 ) p->rc = FTS5_CORRUPT;
|
||||
}
|
||||
@@ -6263,7 +6296,7 @@ static void fts5DecodeFunction(
|
||||
u8 *a = 0;
|
||||
Fts5Buffer s; /* Build up text to return here */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int nSpace = 0;
|
||||
sqlite3_int64 nSpace = 0;
|
||||
int eDetailNone = (sqlite3_user_data(pCtx)!=0);
|
||||
|
||||
assert( nArg==2 );
|
||||
@@ -6279,8 +6312,7 @@ static void fts5DecodeFunction(
|
||||
nSpace = n + FTS5_DATA_ZERO_PADDING;
|
||||
a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace);
|
||||
if( a==0 ) goto decode_out;
|
||||
memcpy(a, aBlob, n);
|
||||
|
||||
if( n>0 ) memcpy(a, aBlob, n);
|
||||
|
||||
fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno);
|
||||
|
||||
@@ -6375,6 +6407,9 @@ static void fts5DecodeFunction(
|
||||
iPgidxOff = szLeaf = fts5GetU16(&a[2]);
|
||||
if( iPgidxOff<n ){
|
||||
fts5GetVarint32(&a[iPgidxOff], iTermOff);
|
||||
}else if( iPgidxOff>n ){
|
||||
rc = FTS5_CORRUPT;
|
||||
goto decode_out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6386,14 +6421,22 @@ static void fts5DecodeFunction(
|
||||
}else{
|
||||
iOff = szLeaf;
|
||||
}
|
||||
if( iOff>n ){
|
||||
rc = FTS5_CORRUPT;
|
||||
goto decode_out;
|
||||
}
|
||||
fts5DecodePoslist(&rc, &s, &a[4], iOff-4);
|
||||
|
||||
/* Decode any more doclist data that appears on the page before the
|
||||
** first term. */
|
||||
nDoclist = (iTermOff ? iTermOff : szLeaf) - iOff;
|
||||
if( nDoclist+iOff>n ){
|
||||
rc = FTS5_CORRUPT;
|
||||
goto decode_out;
|
||||
}
|
||||
fts5DecodeDoclist(&rc, &s, &a[iOff], nDoclist);
|
||||
|
||||
while( iPgidxOff<n ){
|
||||
while( iPgidxOff<n && rc==SQLITE_OK ){
|
||||
int bFirst = (iPgidxOff==szLeaf); /* True for first term on page */
|
||||
int nByte; /* Bytes of data */
|
||||
int iEnd;
|
||||
@@ -6408,12 +6451,24 @@ static void fts5DecodeFunction(
|
||||
}else{
|
||||
iEnd = szLeaf;
|
||||
}
|
||||
if( iEnd>szLeaf ){
|
||||
rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
|
||||
if( bFirst==0 ){
|
||||
iOff += fts5GetVarint32(&a[iOff], nByte);
|
||||
if( nByte>term.n ){
|
||||
rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
term.n = nByte;
|
||||
}
|
||||
iOff += fts5GetVarint32(&a[iOff], nByte);
|
||||
if( iOff+nByte>n ){
|
||||
rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]);
|
||||
iOff += nByte;
|
||||
|
||||
|
||||
+156
-150
@@ -28,8 +28,8 @@ int sqlite3_fts5_may_be_corrupt = 1;
|
||||
typedef struct Fts5Auxdata Fts5Auxdata;
|
||||
typedef struct Fts5Auxiliary Fts5Auxiliary;
|
||||
typedef struct Fts5Cursor Fts5Cursor;
|
||||
typedef struct Fts5FullTable Fts5FullTable;
|
||||
typedef struct Fts5Sorter Fts5Sorter;
|
||||
typedef struct Fts5Table Fts5Table;
|
||||
typedef struct Fts5TokenizerModule Fts5TokenizerModule;
|
||||
|
||||
/*
|
||||
@@ -110,13 +110,8 @@ struct Fts5TokenizerModule {
|
||||
Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
|
||||
};
|
||||
|
||||
/*
|
||||
** Virtual-table object.
|
||||
*/
|
||||
struct Fts5Table {
|
||||
sqlite3_vtab base; /* Base class used by SQLite core */
|
||||
Fts5Config *pConfig; /* Virtual table configuration */
|
||||
Fts5Index *pIndex; /* Full-text index */
|
||||
struct Fts5FullTable {
|
||||
Fts5Table p; /* Public class members from fts5Int.h */
|
||||
Fts5Storage *pStorage; /* Document store */
|
||||
Fts5Global *pGlobal; /* Global (connection wide) data */
|
||||
Fts5Cursor *pSortCsr; /* Sort data from this cursor */
|
||||
@@ -254,7 +249,7 @@ struct Fts5Auxdata {
|
||||
#define FTS5_SAVEPOINT 5
|
||||
#define FTS5_RELEASE 6
|
||||
#define FTS5_ROLLBACKTO 7
|
||||
static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
|
||||
static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
|
||||
switch( op ){
|
||||
case FTS5_BEGIN:
|
||||
assert( p->ts.eState==0 );
|
||||
@@ -293,7 +288,7 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
|
||||
|
||||
case FTS5_ROLLBACKTO:
|
||||
assert( p->ts.eState==1 );
|
||||
assert( iSavepoint>=0 );
|
||||
assert( iSavepoint>=-1 );
|
||||
assert( iSavepoint<=p->ts.iSavepoint );
|
||||
p->ts.iSavepoint = iSavepoint;
|
||||
break;
|
||||
@@ -306,18 +301,18 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
|
||||
/*
|
||||
** Return true if pTab is a contentless table.
|
||||
*/
|
||||
static int fts5IsContentless(Fts5Table *pTab){
|
||||
return pTab->pConfig->eContent==FTS5_CONTENT_NONE;
|
||||
static int fts5IsContentless(Fts5FullTable *pTab){
|
||||
return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete a virtual table handle allocated by fts5InitVtab().
|
||||
*/
|
||||
static void fts5FreeVtab(Fts5Table *pTab){
|
||||
static void fts5FreeVtab(Fts5FullTable *pTab){
|
||||
if( pTab ){
|
||||
sqlite3Fts5IndexClose(pTab->pIndex);
|
||||
sqlite3Fts5IndexClose(pTab->p.pIndex);
|
||||
sqlite3Fts5StorageClose(pTab->pStorage);
|
||||
sqlite3Fts5ConfigFree(pTab->pConfig);
|
||||
sqlite3Fts5ConfigFree(pTab->p.pConfig);
|
||||
sqlite3_free(pTab);
|
||||
}
|
||||
}
|
||||
@@ -326,7 +321,7 @@ static void fts5FreeVtab(Fts5Table *pTab){
|
||||
** The xDisconnect() virtual table method.
|
||||
*/
|
||||
static int fts5DisconnectMethod(sqlite3_vtab *pVtab){
|
||||
fts5FreeVtab((Fts5Table*)pVtab);
|
||||
fts5FreeVtab((Fts5FullTable*)pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -337,7 +332,7 @@ static int fts5DestroyMethod(sqlite3_vtab *pVtab){
|
||||
Fts5Table *pTab = (Fts5Table*)pVtab;
|
||||
int rc = sqlite3Fts5DropAll(pTab->pConfig);
|
||||
if( rc==SQLITE_OK ){
|
||||
fts5FreeVtab((Fts5Table*)pVtab);
|
||||
fts5FreeVtab((Fts5FullTable*)pVtab);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -366,28 +361,28 @@ static int fts5InitVtab(
|
||||
const char **azConfig = (const char**)argv;
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
Fts5Config *pConfig = 0; /* Results of parsing argc/argv */
|
||||
Fts5Table *pTab = 0; /* New virtual table object */
|
||||
Fts5FullTable *pTab = 0; /* New virtual table object */
|
||||
|
||||
/* Allocate the new vtab object and parse the configuration */
|
||||
pTab = (Fts5Table*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Table));
|
||||
pTab = (Fts5FullTable*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5FullTable));
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr);
|
||||
assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pTab->pConfig = pConfig;
|
||||
pTab->p.pConfig = pConfig;
|
||||
pTab->pGlobal = pGlobal;
|
||||
}
|
||||
|
||||
/* Open the index sub-system */
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->pIndex, pzErr);
|
||||
rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->p.pIndex, pzErr);
|
||||
}
|
||||
|
||||
/* Open the storage sub-system */
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5StorageOpen(
|
||||
pConfig, pTab->pIndex, bCreate, &pTab->pStorage, pzErr
|
||||
pConfig, pTab->p.pIndex, bCreate, &pTab->pStorage, pzErr
|
||||
);
|
||||
}
|
||||
|
||||
@@ -400,8 +395,8 @@ static int fts5InitVtab(
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( pConfig->pzErrmsg==0 );
|
||||
pConfig->pzErrmsg = pzErr;
|
||||
rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
|
||||
sqlite3Fts5IndexRollback(pTab->pIndex);
|
||||
rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
|
||||
sqlite3Fts5IndexRollback(pTab->p.pIndex);
|
||||
pConfig->pzErrmsg = 0;
|
||||
}
|
||||
|
||||
@@ -614,7 +609,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int fts5NewTransaction(Fts5Table *pTab){
|
||||
static int fts5NewTransaction(Fts5FullTable *pTab){
|
||||
Fts5Cursor *pCsr;
|
||||
for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
|
||||
if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK;
|
||||
@@ -626,16 +621,16 @@ static int fts5NewTransaction(Fts5Table *pTab){
|
||||
** Implementation of xOpen method.
|
||||
*/
|
||||
static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
|
||||
Fts5Table *pTab = (Fts5Table*)pVTab;
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVTab;
|
||||
Fts5Config *pConfig = pTab->p.pConfig;
|
||||
Fts5Cursor *pCsr = 0; /* New cursor object */
|
||||
int nByte; /* Bytes of space to allocate */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate */
|
||||
int rc; /* Return code */
|
||||
|
||||
rc = fts5NewTransaction(pTab);
|
||||
if( rc==SQLITE_OK ){
|
||||
nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
|
||||
pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
|
||||
pCsr = (Fts5Cursor*)sqlite3_malloc64(nByte);
|
||||
if( pCsr ){
|
||||
Fts5Global *pGlobal = pTab->pGlobal;
|
||||
memset(pCsr, 0, nByte);
|
||||
@@ -673,7 +668,7 @@ static void fts5CsrNewrow(Fts5Cursor *pCsr){
|
||||
}
|
||||
|
||||
static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
|
||||
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
|
||||
Fts5Auxdata *pData;
|
||||
Fts5Auxdata *pNext;
|
||||
|
||||
@@ -717,7 +712,7 @@ static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
|
||||
*/
|
||||
static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){
|
||||
if( pCursor ){
|
||||
Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
|
||||
Fts5Cursor **pp;
|
||||
|
||||
@@ -774,7 +769,7 @@ static int fts5SorterNext(Fts5Cursor *pCsr){
|
||||
** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
|
||||
** open on table pTab.
|
||||
*/
|
||||
static void fts5TripCursors(Fts5Table *pTab){
|
||||
static void fts5TripCursors(Fts5FullTable *pTab){
|
||||
Fts5Cursor *pCsr;
|
||||
for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
|
||||
if( pCsr->ePlan==FTS5_PLAN_MATCH
|
||||
@@ -801,11 +796,11 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
|
||||
int rc = SQLITE_OK;
|
||||
assert( *pbSkip==0 );
|
||||
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){
|
||||
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
|
||||
int bDesc = pCsr->bDesc;
|
||||
i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
|
||||
|
||||
rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc);
|
||||
rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->p.pIndex, iRowid, bDesc);
|
||||
if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
|
||||
*pbSkip = 1;
|
||||
}
|
||||
@@ -902,18 +897,22 @@ static int fts5PrepareStatement(
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
static int fts5CursorFirstSorted(
|
||||
Fts5FullTable *pTab,
|
||||
Fts5Cursor *pCsr,
|
||||
int bDesc
|
||||
){
|
||||
Fts5Config *pConfig = pTab->p.pConfig;
|
||||
Fts5Sorter *pSorter;
|
||||
int nPhrase;
|
||||
int nByte;
|
||||
sqlite3_int64 nByte;
|
||||
int rc;
|
||||
const char *zRank = pCsr->zRank;
|
||||
const char *zRankArgs = pCsr->zRankArgs;
|
||||
|
||||
nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
|
||||
nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
|
||||
pSorter = (Fts5Sorter*)sqlite3_malloc(nByte);
|
||||
pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte);
|
||||
if( pSorter==0 ) return SQLITE_NOMEM;
|
||||
memset(pSorter, 0, nByte);
|
||||
pSorter->nIdx = nPhrase;
|
||||
@@ -950,10 +949,10 @@ static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
|
||||
static int fts5CursorFirst(Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc){
|
||||
int rc;
|
||||
Fts5Expr *pExpr = pCsr->pExpr;
|
||||
rc = sqlite3Fts5ExprFirst(pExpr, pTab->pIndex, pCsr->iFirstRowid, bDesc);
|
||||
rc = sqlite3Fts5ExprFirst(pExpr, pTab->p.pIndex, pCsr->iFirstRowid, bDesc);
|
||||
if( sqlite3Fts5ExprEof(pExpr) ){
|
||||
CsrFlagSet(pCsr, FTS5CSR_EOF);
|
||||
}
|
||||
@@ -968,7 +967,7 @@ static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
|
||||
** parameters.
|
||||
*/
|
||||
static int fts5SpecialMatch(
|
||||
Fts5Table *pTab,
|
||||
Fts5FullTable *pTab,
|
||||
Fts5Cursor *pCsr,
|
||||
const char *zQuery
|
||||
){
|
||||
@@ -979,18 +978,18 @@ static int fts5SpecialMatch(
|
||||
while( z[0]==' ' ) z++;
|
||||
for(n=0; z[n] && z[n]!=' '; n++);
|
||||
|
||||
assert( pTab->base.zErrMsg==0 );
|
||||
assert( pTab->p.base.zErrMsg==0 );
|
||||
pCsr->ePlan = FTS5_PLAN_SPECIAL;
|
||||
|
||||
if( 0==sqlite3_strnicmp("reads", z, n) ){
|
||||
pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->pIndex);
|
||||
pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->p.pIndex);
|
||||
}
|
||||
else if( 0==sqlite3_strnicmp("id", z, n) ){
|
||||
pCsr->iSpecial = pCsr->iCsrId;
|
||||
}
|
||||
else{
|
||||
/* An unrecognized directive. Return an error message. */
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z);
|
||||
pTab->p.base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
@@ -1002,7 +1001,7 @@ static int fts5SpecialMatch(
|
||||
** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary
|
||||
** structure. Otherwise, if no such function exists, return NULL.
|
||||
*/
|
||||
static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){
|
||||
static Fts5Auxiliary *fts5FindAuxiliary(Fts5FullTable *pTab, const char *zName){
|
||||
Fts5Auxiliary *pAux;
|
||||
|
||||
for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){
|
||||
@@ -1015,8 +1014,8 @@ static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){
|
||||
|
||||
|
||||
static int fts5FindRankFunction(Fts5Cursor *pCsr){
|
||||
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
|
||||
Fts5Config *pConfig = pTab->p.pConfig;
|
||||
int rc = SQLITE_OK;
|
||||
Fts5Auxiliary *pAux = 0;
|
||||
const char *zRank = pCsr->zRank;
|
||||
@@ -1032,7 +1031,7 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){
|
||||
assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 );
|
||||
if( rc==SQLITE_OK ){
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
int nByte;
|
||||
sqlite3_int64 nByte;
|
||||
pCsr->nRankArg = sqlite3_column_count(pStmt);
|
||||
nByte = sizeof(sqlite3_value*)*pCsr->nRankArg;
|
||||
pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte);
|
||||
@@ -1054,8 +1053,8 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){
|
||||
if( rc==SQLITE_OK ){
|
||||
pAux = fts5FindAuxiliary(pTab, zRank);
|
||||
if( pAux==0 ){
|
||||
assert( pTab->base.zErrMsg==0 );
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank);
|
||||
assert( pTab->p.base.zErrMsg==0 );
|
||||
pTab->p.base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -1130,8 +1129,8 @@ static int fts5FilterMethod(
|
||||
int nVal, /* Number of elements in apVal */
|
||||
sqlite3_value **apVal /* Arguments for the indexing scheme */
|
||||
){
|
||||
Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
|
||||
Fts5Config *pConfig = pTab->p.pConfig;
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
|
||||
int rc = SQLITE_OK; /* Error code */
|
||||
int iVal = 0; /* Counter for apVal[] */
|
||||
@@ -1160,8 +1159,8 @@ static int fts5FilterMethod(
|
||||
assert( pCsr->zRank==0 );
|
||||
assert( pCsr->zRankArgs==0 );
|
||||
|
||||
assert( pzErrmsg==0 || pzErrmsg==&pTab->base.zErrMsg );
|
||||
pConfig->pzErrmsg = &pTab->base.zErrMsg;
|
||||
assert( pzErrmsg==0 || pzErrmsg==&pTab->p.base.zErrMsg );
|
||||
pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
|
||||
|
||||
/* Decode the arguments passed through to this function.
|
||||
**
|
||||
@@ -1227,7 +1226,7 @@ static int fts5FilterMethod(
|
||||
** but a request for an internal parameter. */
|
||||
rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
|
||||
}else{
|
||||
char **pzErr = &pTab->base.zErrMsg;
|
||||
char **pzErr = &pTab->p.base.zErrMsg;
|
||||
rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( bOrderByRank ){
|
||||
@@ -1250,7 +1249,7 @@ static int fts5FilterMethod(
|
||||
** by rowid (ePlan==FTS5_PLAN_ROWID). */
|
||||
pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN);
|
||||
rc = sqlite3Fts5StorageStmt(
|
||||
pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->base.zErrMsg
|
||||
pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->p.base.zErrMsg
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pCsr->ePlan==FTS5_PLAN_ROWID ){
|
||||
@@ -1333,12 +1332,12 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
|
||||
|
||||
/* If the cursor does not yet have a statement handle, obtain one now. */
|
||||
if( pCsr->pStmt==0 ){
|
||||
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
|
||||
int eStmt = fts5StmtType(pCsr);
|
||||
rc = sqlite3Fts5StorageStmt(
|
||||
pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->base.zErrMsg:0)
|
||||
pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->p.base.zErrMsg:0)
|
||||
);
|
||||
assert( rc!=SQLITE_OK || pTab->base.zErrMsg==0 );
|
||||
assert( rc!=SQLITE_OK || pTab->p.base.zErrMsg==0 );
|
||||
assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) );
|
||||
}
|
||||
|
||||
@@ -1360,11 +1359,11 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){
|
||||
static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
|
||||
va_list ap; /* ... printf arguments */
|
||||
va_start(ap, zFormat);
|
||||
assert( p->base.zErrMsg==0 );
|
||||
p->base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
|
||||
assert( p->p.base.zErrMsg==0 );
|
||||
p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@@ -1384,11 +1383,11 @@ static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){
|
||||
** more commands are added to this function.
|
||||
*/
|
||||
static int fts5SpecialInsert(
|
||||
Fts5Table *pTab, /* Fts5 table object */
|
||||
Fts5FullTable *pTab, /* Fts5 table object */
|
||||
const char *zCmd, /* Text inserted into table-name column */
|
||||
sqlite3_value *pVal /* Value inserted into rank column */
|
||||
){
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
Fts5Config *pConfig = pTab->p.pConfig;
|
||||
int rc = SQLITE_OK;
|
||||
int bError = 0;
|
||||
|
||||
@@ -1423,9 +1422,9 @@ static int fts5SpecialInsert(
|
||||
pConfig->bPrefixIndex = sqlite3_value_int(pVal);
|
||||
#endif
|
||||
}else{
|
||||
rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
|
||||
rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError);
|
||||
rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
if( bError ){
|
||||
@@ -1439,7 +1438,7 @@ static int fts5SpecialInsert(
|
||||
}
|
||||
|
||||
static int fts5SpecialDelete(
|
||||
Fts5Table *pTab,
|
||||
Fts5FullTable *pTab,
|
||||
sqlite3_value **apVal
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
@@ -1453,7 +1452,7 @@ static int fts5SpecialDelete(
|
||||
|
||||
static void fts5StorageInsert(
|
||||
int *pRc,
|
||||
Fts5Table *pTab,
|
||||
Fts5FullTable *pTab,
|
||||
sqlite3_value **apVal,
|
||||
i64 *piRowid
|
||||
){
|
||||
@@ -1487,8 +1486,8 @@ static int fts5UpdateMethod(
|
||||
sqlite3_value **apVal, /* Array of arguments */
|
||||
sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */
|
||||
){
|
||||
Fts5Table *pTab = (Fts5Table*)pVtab;
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
Fts5Config *pConfig = pTab->p.pConfig;
|
||||
int eType0; /* value_type() of apVal[0] */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
|
||||
@@ -1497,12 +1496,11 @@ static int fts5UpdateMethod(
|
||||
|
||||
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( sqlite3_value_type(apVal[0])==SQLITE_INTEGER
|
||||
|| sqlite3_value_type(apVal[0])==SQLITE_NULL
|
||||
);
|
||||
assert( pTab->pConfig->pzErrmsg==0 );
|
||||
pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
|
||||
assert( pTab->p.pConfig->pzErrmsg==0 );
|
||||
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
|
||||
|
||||
/* Put any active cursors into REQUIRE_SEEK state. */
|
||||
fts5TripCursors(pTab);
|
||||
@@ -1543,7 +1541,7 @@ static int fts5UpdateMethod(
|
||||
/* 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(
|
||||
pTab->p.base.zErrMsg = sqlite3_mprintf(
|
||||
"cannot %s contentless fts5 table: %s",
|
||||
(nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
|
||||
);
|
||||
@@ -1556,46 +1554,52 @@ static int fts5UpdateMethod(
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
|
||||
}
|
||||
|
||||
/* 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
|
||||
){
|
||||
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
|
||||
}
|
||||
fts5StorageInsert(&rc, pTab, apVal, pRowid);
|
||||
}
|
||||
|
||||
/* UPDATE */
|
||||
/* INSERT or 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, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
|
||||
}
|
||||
fts5StorageInsert(&rc, pTab, apVal, pRowid);
|
||||
}else{
|
||||
rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
|
||||
}
|
||||
int eType1 = sqlite3_value_numeric_type(apVal[1]);
|
||||
|
||||
if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){
|
||||
rc = SQLITE_MISMATCH;
|
||||
}
|
||||
|
||||
else if( eType0!=SQLITE_INTEGER ){
|
||||
/* If this is a REPLACE, first remove the current entry (if any) */
|
||||
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
|
||||
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
|
||||
}
|
||||
}else{
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
|
||||
fts5StorageInsert(&rc, pTab, apVal, pRowid);
|
||||
}
|
||||
|
||||
/* UPDATE */
|
||||
else{
|
||||
i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
|
||||
i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
|
||||
if( eType1==SQLITE_INTEGER && iOld!=iNew ){
|
||||
if( eConflict==SQLITE_REPLACE ){
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
|
||||
}
|
||||
fts5StorageInsert(&rc, pTab, apVal, pRowid);
|
||||
}else{
|
||||
rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
|
||||
fts5StorageInsert(&rc, pTab, apVal, pRowid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pTab->pConfig->pzErrmsg = 0;
|
||||
pTab->p.pConfig->pzErrmsg = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1604,12 +1608,12 @@ static int fts5UpdateMethod(
|
||||
*/
|
||||
static int fts5SyncMethod(sqlite3_vtab *pVtab){
|
||||
int rc;
|
||||
Fts5Table *pTab = (Fts5Table*)pVtab;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
|
||||
pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
|
||||
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
|
||||
fts5TripCursors(pTab);
|
||||
rc = sqlite3Fts5StorageSync(pTab->pStorage);
|
||||
pTab->pConfig->pzErrmsg = 0;
|
||||
pTab->p.pConfig->pzErrmsg = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1617,8 +1621,8 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
|
||||
** Implementation of xBegin() method.
|
||||
*/
|
||||
static int fts5BeginMethod(sqlite3_vtab *pVtab){
|
||||
fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
|
||||
fts5NewTransaction((Fts5Table*)pVtab);
|
||||
fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
|
||||
fts5NewTransaction((Fts5FullTable*)pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -1629,7 +1633,7 @@ static int fts5BeginMethod(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int fts5CommitMethod(sqlite3_vtab *pVtab){
|
||||
UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */
|
||||
fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0);
|
||||
fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_COMMIT, 0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -1639,7 +1643,7 @@ static int fts5CommitMethod(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int fts5RollbackMethod(sqlite3_vtab *pVtab){
|
||||
int rc;
|
||||
Fts5Table *pTab = (Fts5Table*)pVtab;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
|
||||
rc = sqlite3Fts5StorageRollback(pTab->pStorage);
|
||||
return rc;
|
||||
@@ -1663,13 +1667,13 @@ static int fts5ApiColumnTotalSize(
|
||||
sqlite3_int64 *pnToken
|
||||
){
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
|
||||
return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken);
|
||||
}
|
||||
|
||||
static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
|
||||
return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
|
||||
}
|
||||
|
||||
@@ -1704,7 +1708,9 @@ static int fts5ApiColumnText(
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||
if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
|
||||
if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
|
||||
|| pCsr->ePlan==FTS5_PLAN_SPECIAL
|
||||
){
|
||||
*pz = 0;
|
||||
*pn = 0;
|
||||
}else{
|
||||
@@ -1773,10 +1779,11 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
|
||||
int rc = SQLITE_OK;
|
||||
Fts5PoslistReader *aIter; /* One iterator for each phrase */
|
||||
int nIter; /* Number of iterators/phrases */
|
||||
int nCol = ((Fts5Table*)pCsr->base.pVtab)->pConfig->nCol;
|
||||
|
||||
nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
|
||||
if( pCsr->aInstIter==0 ){
|
||||
int nByte = sizeof(Fts5PoslistReader) * nIter;
|
||||
sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nIter;
|
||||
pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte);
|
||||
}
|
||||
aIter = pCsr->aInstIter;
|
||||
@@ -1811,7 +1818,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
|
||||
nInst++;
|
||||
if( nInst>=pCsr->nInstAlloc ){
|
||||
pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
|
||||
aInst = (int*)sqlite3_realloc(
|
||||
aInst = (int*)sqlite3_realloc64(
|
||||
pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
|
||||
);
|
||||
if( aInst ){
|
||||
@@ -1826,6 +1833,10 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
|
||||
aInst[0] = iBest;
|
||||
aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
|
||||
aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
|
||||
if( aInst[1]<0 || aInst[1]>=nCol ){
|
||||
rc = FTS5_CORRUPT;
|
||||
break;
|
||||
}
|
||||
sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
|
||||
}
|
||||
}
|
||||
@@ -1898,8 +1909,8 @@ static int fts5ColumnSizeCb(
|
||||
|
||||
static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
|
||||
Fts5Config *pConfig = pTab->p.pConfig;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
|
||||
@@ -2155,7 +2166,7 @@ static int fts5ApiQueryPhrase(
|
||||
int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*)
|
||||
){
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
|
||||
int rc;
|
||||
Fts5Cursor *pNew = 0;
|
||||
|
||||
@@ -2232,25 +2243,19 @@ static void fts5ApiCallback(
|
||||
|
||||
|
||||
/*
|
||||
** Given cursor id iId, return a pointer to the corresponding Fts5Index
|
||||
** Given cursor id iId, return a pointer to the corresponding Fts5Table
|
||||
** object. Or NULL If the cursor id does not exist.
|
||||
**
|
||||
** If successful, set *ppConfig to point to the associated config object
|
||||
** before returning.
|
||||
*/
|
||||
Fts5Index *sqlite3Fts5IndexFromCsrid(
|
||||
Fts5Table *sqlite3Fts5TableFromCsrid(
|
||||
Fts5Global *pGlobal, /* FTS5 global context for db handle */
|
||||
i64 iCsrId, /* Id of cursor to find */
|
||||
Fts5Config **ppConfig /* OUT: Configuration object */
|
||||
i64 iCsrId /* Id of cursor to find */
|
||||
){
|
||||
Fts5Cursor *pCsr;
|
||||
Fts5Table *pTab;
|
||||
|
||||
pCsr = fts5CursorFromCsrid(pGlobal, iCsrId);
|
||||
pTab = (Fts5Table*)pCsr->base.pVtab;
|
||||
*ppConfig = pTab->pConfig;
|
||||
|
||||
return pTab->pIndex;
|
||||
if( pCsr ){
|
||||
return (Fts5Table*)pCsr->base.pVtab;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2330,8 +2335,8 @@ static int fts5ColumnMethod(
|
||||
sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
|
||||
int iCol /* Index of column to read value from */
|
||||
){
|
||||
Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
|
||||
Fts5Config *pConfig = pTab->p.pConfig;
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
@@ -2383,7 +2388,7 @@ static int fts5FindFunctionMethod(
|
||||
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
|
||||
void **ppArg /* OUT: User data for *pxFunc */
|
||||
){
|
||||
Fts5Table *pTab = (Fts5Table*)pVtab;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
Fts5Auxiliary *pAux;
|
||||
|
||||
UNUSED_PARAM(nUnused);
|
||||
@@ -2405,21 +2410,24 @@ static int fts5RenameMethod(
|
||||
sqlite3_vtab *pVtab, /* Virtual table handle */
|
||||
const char *zName /* New name of table */
|
||||
){
|
||||
Fts5Table *pTab = (Fts5Table*)pVtab;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
return sqlite3Fts5StorageRename(pTab->pStorage, zName);
|
||||
}
|
||||
|
||||
int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
|
||||
fts5TripCursors((Fts5FullTable*)pTab);
|
||||
return sqlite3Fts5StorageSync(((Fts5FullTable*)pTab)->pStorage);
|
||||
}
|
||||
|
||||
/*
|
||||
** The xSavepoint() method.
|
||||
**
|
||||
** Flush the contents of the pending-terms table to disk.
|
||||
*/
|
||||
static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Fts5Table *pTab = (Fts5Table*)pVtab;
|
||||
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
|
||||
fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
|
||||
fts5TripCursors(pTab);
|
||||
return sqlite3Fts5StorageSync(pTab->pStorage);
|
||||
fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint);
|
||||
return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2428,11 +2436,9 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
** This is a no-op.
|
||||
*/
|
||||
static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Fts5Table *pTab = (Fts5Table*)pVtab;
|
||||
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
|
||||
fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
|
||||
fts5TripCursors(pTab);
|
||||
return sqlite3Fts5StorageSync(pTab->pStorage);
|
||||
fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint);
|
||||
return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2441,7 +2447,7 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
** Discard the contents of the pending terms table.
|
||||
*/
|
||||
static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
Fts5Table *pTab = (Fts5Table*)pVtab;
|
||||
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
|
||||
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
|
||||
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
|
||||
fts5TripCursors(pTab);
|
||||
|
||||
+17
-8
@@ -115,7 +115,7 @@ static int fts5StorageGetStmt(
|
||||
char *zBind;
|
||||
int i;
|
||||
|
||||
zBind = sqlite3_malloc(1 + nCol*2);
|
||||
zBind = sqlite3_malloc64(1 + nCol*2);
|
||||
if( zBind ){
|
||||
for(i=0; i<nCol; i++){
|
||||
zBind[i*2] = '?';
|
||||
@@ -136,8 +136,9 @@ static int fts5StorageGetStmt(
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v3(pC->db, zSql, -1,
|
||||
SQLITE_PREPARE_PERSISTENT, &p->aStmt[eStmt], 0);
|
||||
int f = SQLITE_PREPARE_PERSISTENT;
|
||||
if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB;
|
||||
rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc!=SQLITE_OK && pzErrMsg ){
|
||||
*pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
|
||||
@@ -281,11 +282,11 @@ int sqlite3Fts5StorageOpen(
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
Fts5Storage *p; /* New object */
|
||||
int nByte; /* Bytes of space to allocate */
|
||||
sqlite3_int64 nByte; /* Bytes of space to allocate */
|
||||
|
||||
nByte = sizeof(Fts5Storage) /* Fts5Storage object */
|
||||
+ pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */
|
||||
*pp = p = (Fts5Storage*)sqlite3_malloc(nByte);
|
||||
*pp = p = (Fts5Storage*)sqlite3_malloc64(nByte);
|
||||
if( !p ) return SQLITE_NOMEM;
|
||||
|
||||
memset(p, 0, nByte);
|
||||
@@ -296,7 +297,7 @@ int sqlite3Fts5StorageOpen(
|
||||
if( bCreate ){
|
||||
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
|
||||
int nDefn = 32 + pConfig->nCol*10;
|
||||
char *zDefn = sqlite3_malloc(32 + pConfig->nCol * 10);
|
||||
char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10);
|
||||
if( zDefn==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -587,7 +588,7 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
sqlite3_stmt *pScan = 0;
|
||||
Fts5InsertCtx ctx;
|
||||
int rc;
|
||||
int rc, rc2;
|
||||
|
||||
memset(&ctx, 0, sizeof(Fts5InsertCtx));
|
||||
ctx.pStorage = p;
|
||||
@@ -626,6 +627,8 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
|
||||
}
|
||||
}
|
||||
sqlite3_free(buf.p);
|
||||
rc2 = sqlite3_reset(pScan);
|
||||
if( rc==SQLITE_OK ) rc = rc2;
|
||||
|
||||
/* Write the averages record */
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -875,7 +878,7 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
|
||||
|
||||
memset(&ctx, 0, sizeof(Fts5IntegrityCtx));
|
||||
ctx.pConfig = p->pConfig;
|
||||
aTotalSize = (i64*)sqlite3_malloc(pConfig->nCol * (sizeof(int)+sizeof(i64)));
|
||||
aTotalSize = (i64*)sqlite3_malloc64(pConfig->nCol*(sizeof(int)+sizeof(i64)));
|
||||
if( !aTotalSize ) return SQLITE_NOMEM;
|
||||
aColSize = (int*)&aTotalSize[pConfig->nCol];
|
||||
memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol);
|
||||
@@ -1075,7 +1078,13 @@ int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){
|
||||
int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
|
||||
int rc = fts5StorageLoadTotals(p, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
/* nTotalRow being zero does not necessarily indicate a corrupt
|
||||
** database - it might be that the FTS5 table really does contain zero
|
||||
** rows. However this function is only called from the xRowCount() API,
|
||||
** and there is no way for that API to be invoked if the table contains
|
||||
** no rows. Hence the FTS5_CORRUPT return. */
|
||||
*pnRow = p->nTotalRow;
|
||||
if( p->nTotalRow<=0 ) rc = FTS5_CORRUPT;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ static Fts5MatchinfoCtx *fts5MatchinfoNew(
|
||||
int nPhrase;
|
||||
int i;
|
||||
int nInt;
|
||||
int nByte;
|
||||
sqlite3_int64 nByte;
|
||||
int rc;
|
||||
|
||||
nCol = pApi->xColumnCount(pFts);
|
||||
@@ -330,7 +330,7 @@ static Fts5MatchinfoCtx *fts5MatchinfoNew(
|
||||
nByte = sizeof(Fts5MatchinfoCtx) /* The struct itself */
|
||||
+ sizeof(u32) * nInt /* The p->aRet[] array */
|
||||
+ (i+1); /* The p->zArg string */
|
||||
p = (Fts5MatchinfoCtx*)sqlite3_malloc(nByte);
|
||||
p = (Fts5MatchinfoCtx*)sqlite3_malloc64(nByte);
|
||||
if( p==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return 0;
|
||||
|
||||
@@ -137,7 +137,7 @@ static int fts5tokDequoteArray(
|
||||
nByte += (int)(strlen(argv[i]) + 1);
|
||||
}
|
||||
|
||||
*pazDequote = azDequote = sqlite3_malloc(sizeof(char *)*argc + nByte);
|
||||
*pazDequote = azDequote = sqlite3_malloc64(sizeof(char *)*argc + nByte);
|
||||
if( azDequote==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -335,7 +335,7 @@ static int fts5tokCb(
|
||||
if( (pCsr->nRow & (pCsr->nRow-1))==0 ){
|
||||
int nNew = pCsr->nRow ? pCsr->nRow*2 : 32;
|
||||
Fts5tokRow *aNew;
|
||||
aNew = (Fts5tokRow*)sqlite3_realloc(pCsr->aRow, nNew*sizeof(Fts5tokRow));
|
||||
aNew = (Fts5tokRow*)sqlite3_realloc64(pCsr->aRow, nNew*sizeof(Fts5tokRow));
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
memset(&aNew[pCsr->nRow], 0, sizeof(Fts5tokRow)*(nNew-pCsr->nRow));
|
||||
pCsr->aRow = aNew;
|
||||
@@ -378,7 +378,7 @@ static int fts5tokFilterMethod(
|
||||
if( pCsr->zInput==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memcpy(pCsr->zInput, zByte, nByte);
|
||||
if( nByte>0 ) memcpy(pCsr->zInput, zByte, nByte);
|
||||
pCsr->zInput[nByte] = 0;
|
||||
rc = pTab->tok.xTokenize(
|
||||
pTab->pTok, (void*)pCsr, 0, zByte, nByte, fts5tokCb
|
||||
|
||||
+23
-14
@@ -152,7 +152,7 @@ static int fts5AsciiTokenize(
|
||||
nByte = ie-is;
|
||||
if( nByte>nFold ){
|
||||
if( pFold!=aFold ) sqlite3_free(pFold);
|
||||
pFold = sqlite3_malloc(nByte*2);
|
||||
pFold = sqlite3_malloc64((sqlite3_int64)nByte*2);
|
||||
if( pFold==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
break;
|
||||
@@ -234,13 +234,18 @@ struct Unicode61Tokenizer {
|
||||
unsigned char aTokenChar[128]; /* ASCII range token characters */
|
||||
char *aFold; /* Buffer to fold text into */
|
||||
int nFold; /* Size of aFold[] in bytes */
|
||||
int bRemoveDiacritic; /* True if remove_diacritics=1 is set */
|
||||
int eRemoveDiacritic; /* True if remove_diacritics=1 is set */
|
||||
int nException;
|
||||
int *aiException;
|
||||
|
||||
unsigned char aCategory[32]; /* True for token char categories */
|
||||
};
|
||||
|
||||
/* Values for eRemoveDiacritic (must match internals of fts5_unicode2.c) */
|
||||
#define FTS5_REMOVE_DIACRITICS_NONE 0
|
||||
#define FTS5_REMOVE_DIACRITICS_SIMPLE 1
|
||||
#define FTS5_REMOVE_DIACRITICS_COMPLEX 2
|
||||
|
||||
static int fts5UnicodeAddExceptions(
|
||||
Unicode61Tokenizer *p, /* Tokenizer object */
|
||||
const char *z, /* Characters to treat as exceptions */
|
||||
@@ -251,13 +256,14 @@ static int fts5UnicodeAddExceptions(
|
||||
int *aNew;
|
||||
|
||||
if( n>0 ){
|
||||
aNew = (int*)sqlite3_realloc(p->aiException, (n+p->nException)*sizeof(int));
|
||||
aNew = (int*)sqlite3_realloc64(p->aiException,
|
||||
(n+p->nException)*sizeof(int));
|
||||
if( aNew ){
|
||||
int nNew = p->nException;
|
||||
const unsigned char *zCsr = (const unsigned char*)z;
|
||||
const unsigned char *zTerm = (const unsigned char*)&z[n];
|
||||
while( zCsr<zTerm ){
|
||||
int iCode;
|
||||
u32 iCode;
|
||||
int bToken;
|
||||
READ_UTF8(zCsr, zTerm, iCode);
|
||||
if( iCode<128 ){
|
||||
@@ -269,7 +275,7 @@ static int fts5UnicodeAddExceptions(
|
||||
if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){
|
||||
int i;
|
||||
for(i=0; i<nNew; i++){
|
||||
if( aNew[i]>iCode ) break;
|
||||
if( (u32)aNew[i]>iCode ) break;
|
||||
}
|
||||
memmove(&aNew[i+1], &aNew[i], (nNew-i)*sizeof(int));
|
||||
aNew[i] = iCode;
|
||||
@@ -361,7 +367,7 @@ static int fts5UnicodeCreate(
|
||||
int i;
|
||||
memset(p, 0, sizeof(Unicode61Tokenizer));
|
||||
|
||||
p->bRemoveDiacritic = 1;
|
||||
p->eRemoveDiacritic = FTS5_REMOVE_DIACRITICS_SIMPLE;
|
||||
p->nFold = 64;
|
||||
p->aFold = sqlite3_malloc(p->nFold * sizeof(char));
|
||||
if( p->aFold==0 ){
|
||||
@@ -382,10 +388,15 @@ static int fts5UnicodeCreate(
|
||||
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
|
||||
const char *zArg = azArg[i+1];
|
||||
if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
|
||||
if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
|
||||
if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
p->eRemoveDiacritic = (zArg[0] - '0');
|
||||
assert( p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_NONE
|
||||
|| p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_SIMPLE
|
||||
|| p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_COMPLEX
|
||||
);
|
||||
}
|
||||
p->bRemoveDiacritic = (zArg[0]=='1');
|
||||
}else
|
||||
if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
|
||||
rc = fts5UnicodeAddExceptions(p, zArg, 1);
|
||||
@@ -419,7 +430,7 @@ static int fts5UnicodeCreate(
|
||||
*/
|
||||
static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
|
||||
return (
|
||||
p->aCategory[sqlite3Fts5UnicodeCategory(iCode)]
|
||||
p->aCategory[sqlite3Fts5UnicodeCategory((u32)iCode)]
|
||||
^ fts5UnicodeIsException(p, iCode)
|
||||
);
|
||||
}
|
||||
@@ -448,7 +459,7 @@ static int fts5UnicodeTokenize(
|
||||
/* Each iteration of this loop gobbles up a contiguous run of separators,
|
||||
** then the next token. */
|
||||
while( rc==SQLITE_OK ){
|
||||
int iCode; /* non-ASCII codepoint read from input */
|
||||
u32 iCode; /* non-ASCII codepoint read from input */
|
||||
char *zOut = aFold;
|
||||
int is;
|
||||
int ie;
|
||||
@@ -480,7 +491,7 @@ static int fts5UnicodeTokenize(
|
||||
/* Grow the output buffer so that there is sufficient space to fit the
|
||||
** largest possible utf-8 character. */
|
||||
if( zOut>pEnd ){
|
||||
aFold = sqlite3_malloc(nFold*2);
|
||||
aFold = sqlite3_malloc64((sqlite3_int64)nFold*2);
|
||||
if( aFold==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto tokenize_done;
|
||||
@@ -499,7 +510,7 @@ static int fts5UnicodeTokenize(
|
||||
READ_UTF8(zCsr, zTerm, iCode);
|
||||
if( fts5UnicodeIsAlnum(p,iCode)||sqlite3Fts5UnicodeIsdiacritic(iCode) ){
|
||||
non_ascii_tokenchar:
|
||||
iCode = sqlite3Fts5UnicodeFold(iCode, p->bRemoveDiacritic);
|
||||
iCode = sqlite3Fts5UnicodeFold(iCode, p->eRemoveDiacritic);
|
||||
if( iCode ) WRITE_UTF8(zOut, iCode);
|
||||
}else{
|
||||
break;
|
||||
@@ -1274,5 +1285,3 @@ int sqlite3Fts5TokenizerInit(fts5_api *pApi){
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+47
-35
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** 2012 May 25
|
||||
** 2012-05-25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
@@ -28,32 +28,48 @@
|
||||
** E"). The resuls of passing a codepoint that corresponds to an
|
||||
** uppercase letter are undefined.
|
||||
*/
|
||||
static int fts5_remove_diacritic(int c){
|
||||
static int fts5_remove_diacritic(int c, int bComplex){
|
||||
unsigned short aDia[] = {
|
||||
0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
|
||||
2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
|
||||
2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
|
||||
2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
|
||||
3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928,
|
||||
3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234,
|
||||
4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504,
|
||||
6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529,
|
||||
61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726,
|
||||
61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122,
|
||||
62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536,
|
||||
62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730,
|
||||
62924, 63050, 63082, 63274, 63390,
|
||||
3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896,
|
||||
3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106,
|
||||
4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344,
|
||||
4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198,
|
||||
6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468,
|
||||
61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704,
|
||||
61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914,
|
||||
61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218,
|
||||
62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554,
|
||||
62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766,
|
||||
62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
|
||||
63182, 63242, 63274, 63310, 63368, 63390,
|
||||
};
|
||||
char aChar[] = {
|
||||
'\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c',
|
||||
'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r',
|
||||
's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o',
|
||||
'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r',
|
||||
'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h',
|
||||
'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a',
|
||||
'e', 'i', 'o', 'u', 'y',
|
||||
#define HIBIT ((unsigned char)0x80)
|
||||
unsigned char aChar[] = {
|
||||
'\0', 'a', 'c', 'e', 'i', 'n',
|
||||
'o', 'u', 'y', 'y', 'a', 'c',
|
||||
'd', 'e', 'e', 'g', 'h', 'i',
|
||||
'j', 'k', 'l', 'n', 'o', 'r',
|
||||
's', 't', 'u', 'u', 'w', 'y',
|
||||
'z', 'o', 'u', 'a', 'i', 'o',
|
||||
'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
|
||||
'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
|
||||
'e', 'i', 'o', 'r', 'u', 's',
|
||||
't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
|
||||
'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', 'a', 'b',
|
||||
'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
|
||||
'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
|
||||
'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
|
||||
'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
|
||||
's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
|
||||
'w', 'x', 'y', 'z', 'h', 't',
|
||||
'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
|
||||
'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
|
||||
'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
|
||||
};
|
||||
|
||||
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
|
||||
@@ -70,7 +86,8 @@ static int fts5_remove_diacritic(int c){
|
||||
}
|
||||
}
|
||||
assert( key>=aDia[iRes] );
|
||||
return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
|
||||
if( bComplex==0 && (aChar[iRes] & 0x80) ) return c;
|
||||
return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,8 +100,8 @@ int sqlite3Fts5UnicodeIsdiacritic(int c){
|
||||
unsigned int mask1 = 0x000361F8;
|
||||
if( c<768 || c>817 ) return 0;
|
||||
return (c < 768+32) ?
|
||||
(mask0 & (1 << (c-768))) :
|
||||
(mask1 & (1 << (c-768-32)));
|
||||
(mask0 & ((unsigned int)1 << (c-768))) :
|
||||
(mask1 & ((unsigned int)1 << (c-768-32)));
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +114,7 @@ int sqlite3Fts5UnicodeIsdiacritic(int c){
|
||||
** The results are undefined if the value passed to this function
|
||||
** is less than zero.
|
||||
*/
|
||||
int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
|
||||
int sqlite3Fts5UnicodeFold(int c, int eRemoveDiacritic){
|
||||
/* Each entry in the following array defines a rule for folding a range
|
||||
** of codepoints to lower case. The rule applies to a range of nRange
|
||||
** codepoints starting at codepoint iCode.
|
||||
@@ -220,7 +237,9 @@ int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
|
||||
assert( ret>0 );
|
||||
}
|
||||
|
||||
if( bRemoveDiacritic ) ret = fts5_remove_diacritic(ret);
|
||||
if( eRemoveDiacritic ){
|
||||
ret = fts5_remove_diacritic(ret, eRemoveDiacritic==2);
|
||||
}
|
||||
}
|
||||
|
||||
else if( c>=66560 && c<66600 ){
|
||||
@@ -231,12 +250,6 @@ int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int sqlite3Fts5UnicodeNCat(void) {
|
||||
return 32;
|
||||
}
|
||||
#endif
|
||||
|
||||
int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
||||
aArray[0] = 1;
|
||||
switch( zCat[0] ){
|
||||
@@ -718,7 +731,7 @@ static u16 aFts5UnicodeData[] = {
|
||||
34, 3074, 7692, 63, 63,
|
||||
};
|
||||
|
||||
int sqlite3Fts5UnicodeCategory(int iCode) {
|
||||
int sqlite3Fts5UnicodeCategory(u32 iCode) {
|
||||
int iRes = -1;
|
||||
int iHi;
|
||||
int iLo;
|
||||
@@ -756,9 +769,8 @@ void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
|
||||
int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ];
|
||||
int n = (aFts5UnicodeData[iTbl] >> 5) + i;
|
||||
for(; i<128 && i<n; i++){
|
||||
aAscii[i] = (u8)bToken;
|
||||
aAscii[i] = bToken;
|
||||
}
|
||||
iTbl++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v){
|
||||
u8 n;
|
||||
p -= 2;
|
||||
n = sqlite3Fts5GetVarint(p, &v64);
|
||||
*v = (u32)v64;
|
||||
*v = ((u32)v64) & 0x7FFFFFFF;
|
||||
assert( n>3 && n<=9 );
|
||||
return n;
|
||||
}
|
||||
@@ -342,4 +342,3 @@ int sqlite3Fts5GetVarintLen(u32 iVal){
|
||||
if( iVal<(1 << 28) ) return 4;
|
||||
return 5;
|
||||
}
|
||||
|
||||
|
||||
+38
-31
@@ -55,7 +55,7 @@ struct Fts5VocabTable {
|
||||
struct Fts5VocabCursor {
|
||||
sqlite3_vtab_cursor base;
|
||||
sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */
|
||||
Fts5Index *pIndex; /* Associated FTS5 index */
|
||||
Fts5Table *pFts5; /* Associated FTS5 table */
|
||||
|
||||
int bEof; /* True if this cursor is at EOF */
|
||||
Fts5IndexIter *pIter; /* Term/rowid iterator object */
|
||||
@@ -64,7 +64,6 @@ struct Fts5VocabCursor {
|
||||
char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
|
||||
|
||||
/* These are used by 'col' tables only */
|
||||
Fts5Config *pConfig; /* Fts5 table configuration */
|
||||
int iCol;
|
||||
i64 *aCnt;
|
||||
i64 *aDoc;
|
||||
@@ -327,8 +326,7 @@ static int fts5VocabOpenMethod(
|
||||
sqlite3_vtab_cursor **ppCsr
|
||||
){
|
||||
Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
|
||||
Fts5Index *pIndex = 0;
|
||||
Fts5Config *pConfig = 0;
|
||||
Fts5Table *pFts5 = 0;
|
||||
Fts5VocabCursor *pCsr = 0;
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
@@ -347,31 +345,34 @@ static int fts5VocabOpenMethod(
|
||||
|
||||
if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
i64 iId = sqlite3_column_int64(pStmt, 0);
|
||||
pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig);
|
||||
pFts5 = sqlite3Fts5TableFromCsrid(pTab->pGlobal, iId);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && pIndex==0 ){
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
if( rc==SQLITE_OK ){
|
||||
pVTab->zErrMsg = sqlite3_mprintf(
|
||||
"no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pFts5==0 ){
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
if( rc==SQLITE_OK ){
|
||||
pVTab->zErrMsg = sqlite3_mprintf(
|
||||
"no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}else{
|
||||
rc = sqlite3Fts5FlushToDisk(pFts5);
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor);
|
||||
int nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor);
|
||||
pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
|
||||
}
|
||||
|
||||
if( pCsr ){
|
||||
pCsr->pIndex = pIndex;
|
||||
pCsr->pFts5 = pFts5;
|
||||
pCsr->pStmt = pStmt;
|
||||
pCsr->pConfig = pConfig;
|
||||
pCsr->aCnt = (i64*)&pCsr[1];
|
||||
pCsr->aDoc = &pCsr->aCnt[pConfig->nCol];
|
||||
pCsr->aDoc = &pCsr->aCnt[pFts5->pConfig->nCol];
|
||||
}else{
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
@@ -387,6 +388,7 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
|
||||
sqlite3_free(pCsr->zLeTerm);
|
||||
pCsr->nLeTerm = -1;
|
||||
pCsr->zLeTerm = 0;
|
||||
pCsr->bEof = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -425,7 +427,7 @@ static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){
|
||||
}
|
||||
|
||||
static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
|
||||
int eDetail = pCsr->pConfig->eDetail;
|
||||
int eDetail = pCsr->pFts5->pConfig->eDetail;
|
||||
int rc = SQLITE_OK;
|
||||
Fts5IndexIter *pIter = pCsr->pIter;
|
||||
i64 *pp = &pCsr->iInstPos;
|
||||
@@ -460,7 +462,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
||||
Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
|
||||
int rc = SQLITE_OK;
|
||||
int nCol = pCsr->pConfig->nCol;
|
||||
int nCol = pCsr->pFts5->pConfig->nCol;
|
||||
|
||||
pCsr->rowid++;
|
||||
|
||||
@@ -482,6 +484,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
int nTerm;
|
||||
|
||||
zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
|
||||
assert( nTerm>=0 );
|
||||
if( pCsr->nLeTerm>=0 ){
|
||||
int nCmp = MIN(nTerm, pCsr->nLeTerm);
|
||||
int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
|
||||
@@ -498,7 +501,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
|
||||
assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
|
||||
while( rc==SQLITE_OK ){
|
||||
int eDetail = pCsr->pConfig->eDetail;
|
||||
int eDetail = pCsr->pFts5->pConfig->eDetail;
|
||||
const u8 *pPos; int nPos; /* Position list */
|
||||
i64 iPos = 0; /* 64-bit position read from poslist */
|
||||
int iOff = 0; /* Current offset within position list */
|
||||
@@ -521,7 +524,6 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
int iCol = -1;
|
||||
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
|
||||
int ii = FTS5_POS2COLUMN(iPos);
|
||||
pCsr->aCnt[ii]++;
|
||||
if( iCol!=ii ){
|
||||
if( ii>=nCol ){
|
||||
rc = FTS5_CORRUPT;
|
||||
@@ -530,6 +532,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
pCsr->aDoc[ii]++;
|
||||
iCol = ii;
|
||||
}
|
||||
pCsr->aCnt[ii]++;
|
||||
}
|
||||
}else if( eDetail==FTS5_DETAIL_COLUMNS ){
|
||||
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){
|
||||
@@ -558,7 +561,9 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
|
||||
if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){
|
||||
if( nTerm!=pCsr->term.n
|
||||
|| (nTerm>0 && memcmp(zTerm, pCsr->term.p, nTerm))
|
||||
){
|
||||
break;
|
||||
}
|
||||
if( sqlite3Fts5IterEof(pCsr->pIter) ) break;
|
||||
@@ -569,7 +574,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
|
||||
if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
|
||||
while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++;
|
||||
assert( pCsr->iCol<pCsr->pConfig->nCol );
|
||||
assert( pCsr->iCol<pCsr->pFts5->pConfig->nCol );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -616,6 +621,7 @@ static int fts5VocabFilterMethod(
|
||||
}
|
||||
if( pLe ){
|
||||
const char *zCopy = (const char *)sqlite3_value_text(pLe);
|
||||
if( zCopy==0 ) zCopy = "";
|
||||
pCsr->nLeTerm = sqlite3_value_bytes(pLe);
|
||||
pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1);
|
||||
if( pCsr->zLeTerm==0 ){
|
||||
@@ -627,14 +633,15 @@ static int fts5VocabFilterMethod(
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
|
||||
Fts5Index *pIndex = pCsr->pFts5->pIndex;
|
||||
rc = sqlite3Fts5IndexQuery(pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
|
||||
}
|
||||
if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){
|
||||
rc = fts5VocabInstanceNewTerm(pCsr);
|
||||
}
|
||||
if( rc==SQLITE_OK
|
||||
&& !pCsr->bEof
|
||||
&& (eType!=FTS5_VOCAB_INSTANCE || pCsr->pConfig->eDetail!=FTS5_DETAIL_NONE)
|
||||
if( rc==SQLITE_OK && !pCsr->bEof
|
||||
&& (eType!=FTS5_VOCAB_INSTANCE
|
||||
|| pCsr->pFts5->pConfig->eDetail!=FTS5_DETAIL_NONE)
|
||||
){
|
||||
rc = fts5VocabNextMethod(pCursor);
|
||||
}
|
||||
@@ -657,7 +664,7 @@ static int fts5VocabColumnMethod(
|
||||
int iCol /* Index of column to read value from */
|
||||
){
|
||||
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
||||
int eDetail = pCsr->pConfig->eDetail;
|
||||
int eDetail = pCsr->pFts5->pConfig->eDetail;
|
||||
int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType;
|
||||
i64 iVal = 0;
|
||||
|
||||
@@ -669,7 +676,7 @@ static int fts5VocabColumnMethod(
|
||||
assert( iCol==1 || iCol==2 || iCol==3 );
|
||||
if( iCol==1 ){
|
||||
if( eDetail!=FTS5_DETAIL_NONE ){
|
||||
const char *z = pCsr->pConfig->azCol[pCsr->iCol];
|
||||
const char *z = pCsr->pFts5->pConfig->azCol[pCsr->iCol];
|
||||
sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
|
||||
}
|
||||
}else if( iCol==2 ){
|
||||
@@ -697,8 +704,8 @@ static int fts5VocabColumnMethod(
|
||||
}else if( eDetail==FTS5_DETAIL_COLUMNS ){
|
||||
ii = (int)pCsr->iInstPos;
|
||||
}
|
||||
if( ii>=0 && ii<pCsr->pConfig->nCol ){
|
||||
const char *z = pCsr->pConfig->azCol[ii];
|
||||
if( ii>=0 && ii<pCsr->pFts5->pConfig->nCol ){
|
||||
const char *z = pCsr->pFts5->pConfig->azCol[ii];
|
||||
sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -38,8 +38,7 @@ do_execsql_test 1.0 {
|
||||
do_execsql_test 1.1 {
|
||||
DROP TABLE t1;
|
||||
SELECT name, sql FROM sqlite_master;
|
||||
} {
|
||||
}
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
@@ -51,6 +51,12 @@ do_execsql_test 1.1 {
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SAVEPOINT one;
|
||||
INSERT INTO t1 VALUES('v w x');
|
||||
ROLLBACK TO one;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -144,6 +144,14 @@ do_execsql_test 3.1 {
|
||||
{[a b c d e]}
|
||||
}
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
SELECT highlight(ft, 0, NULL, NULL) FROM ft WHERE ft MATCH 'a+b+c AND c+d+e';
|
||||
} {
|
||||
{a b c x c d e}
|
||||
{a b c c d e}
|
||||
{a b c d e}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# 2018 Dec 22
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5circref
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE tt USING fts5(a);
|
||||
SELECT name FROM sqlite_master ORDER BY 1;
|
||||
} {
|
||||
tt tt_config tt_content tt_data tt_docsize tt_idx
|
||||
}
|
||||
db_save_and_close
|
||||
|
||||
foreach {tn schema sql} {
|
||||
1 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON tt_config BEGIN
|
||||
SELECT * FROM tt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO tt(tt, rank) VALUES('usermerge', 4);
|
||||
}
|
||||
|
||||
2 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON tt_docsize BEGIN
|
||||
SELECT * FROM tt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO tt(a) VALUES('one two three');
|
||||
}
|
||||
|
||||
3 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON tt_content BEGIN
|
||||
SELECT * FROM tt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO tt(a) VALUES('one two three');
|
||||
}
|
||||
|
||||
4 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON tt_data BEGIN
|
||||
SELECT * FROM tt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO tt(a) VALUES('one two three');
|
||||
}
|
||||
|
||||
5 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON tt_idx BEGIN
|
||||
SELECT * FROM tt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO tt(a) VALUES('one two three');
|
||||
}
|
||||
} {
|
||||
db_restore_and_reopen
|
||||
do_execsql_test 1.1.$tn.1 $schema
|
||||
do_catchsql_test 1.1.$tn.2 $sql {1 {SQL logic error}}
|
||||
db close
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
+7370
-4
File diff suppressed because one or more lines are too long
@@ -0,0 +1,67 @@
|
||||
# 2019 Jan 4
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5interrupt
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 40);
|
||||
}
|
||||
db_save_and_close
|
||||
|
||||
proc progress_handler {args} {
|
||||
incr ::progress_handler_delay -1
|
||||
if {$::progress_handler_delay<=0} { return 1 }
|
||||
return 0
|
||||
}
|
||||
|
||||
foreach {tn sql} {
|
||||
1 { INSERT INTO t1(rowid, a) VALUES(0, 'z z z z') }
|
||||
2 { COMMIT }
|
||||
} {
|
||||
set bDone 0
|
||||
for {set i 1} {$bDone==0} {incr i} {
|
||||
do_test 1.$tn.$i {
|
||||
db_restore_and_reopen
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1(rowid, a) VALUES(1, 'a b c d');
|
||||
INSERT INTO t1(rowid, a) VALUES(2, 'd e f g');
|
||||
INSERT INTO t1(rowid, a) VALUES(3, 'h i j k');
|
||||
INSERT INTO t1(rowid, a) VALUES(4, 'l m n o');
|
||||
}
|
||||
|
||||
set ::progress_handler_delay $i
|
||||
db progress 1 progress_handler
|
||||
set res [catchsql $sql]
|
||||
db close
|
||||
if {$res=="0 {}"} {
|
||||
set bDone 1
|
||||
} else {
|
||||
if {$res!="1 interrupted"} { error "got: $res" }
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -189,7 +189,7 @@ do_catchsql_test 6.2 {
|
||||
} {1 {error in tokenizer constructor}}
|
||||
do_catchsql_test 6.3 {
|
||||
CREATE VIRTUAL TABLE a3 USING fts5(
|
||||
x, y, tokenize = 'unicode61 remove_diacritics 2'
|
||||
x, y, tokenize = 'unicode61 remove_diacritics 3'
|
||||
);
|
||||
} {1 {error in tokenizer constructor}}
|
||||
do_catchsql_test 6.4 {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# 2014 June 17
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5umlaut
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(
|
||||
x,
|
||||
tokenize="unicode61 remove_diacritics 2"
|
||||
);
|
||||
}
|
||||
|
||||
foreach {tn q res1 res2} {
|
||||
1 "Hà Nội" 0 1
|
||||
2 "Hà Noi" 1 1
|
||||
3 "Ha Noi" 1 1
|
||||
4 "Ha N\u1ed9i" 0 1
|
||||
5 "Ha N\u006fi" 1 1
|
||||
6 "Ha N\u006f\u0302i" 1 1
|
||||
7 "Ha N\u006f\u0323\u0302i" 1 1
|
||||
} {
|
||||
do_execsql_test 1.$tn.1 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(rowid, x) VALUES (1, 'Ha Noi');
|
||||
SELECT count(*) FROM t1($q)
|
||||
} $res1
|
||||
do_execsql_test 1.$tn.2 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(rowid, x) VALUES (1, $q);
|
||||
SELECT count(*) FROM t1('Ha Noi')
|
||||
} $res1
|
||||
|
||||
do_execsql_test 1.$tn.2 {
|
||||
DELETE FROM t2;
|
||||
INSERT INTO t2(rowid, x) VALUES (1, 'Ha Noi');
|
||||
SELECT count(*) FROM t2($q)
|
||||
} $res2
|
||||
do_execsql_test 1.$tn.2 {
|
||||
DELETE FROM t2;
|
||||
INSERT INTO t2(rowid, x) VALUES (1, $q);
|
||||
SELECT count(*) FROM t2('Ha Noi')
|
||||
} $res2
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -21,7 +21,7 @@ ifcapable !fts5 {
|
||||
}
|
||||
|
||||
proc fts3_unicode_path {file} {
|
||||
file join [file dirname [info script]] .. .. fts3 unicode $file
|
||||
file join .. [file dirname [info script]] .. .. fts3 unicode $file
|
||||
}
|
||||
|
||||
source [fts3_unicode_path parseunicode.tcl]
|
||||
@@ -36,24 +36,26 @@ foreach x [an_load_unicodedata_text $UD] {
|
||||
}
|
||||
|
||||
foreach {y} [rd_load_unicodedata_text $UD] {
|
||||
foreach {code ascii} $y {}
|
||||
foreach {code ascii f} $y {}
|
||||
if {$ascii==""} {
|
||||
set int 0
|
||||
} else {
|
||||
binary scan $ascii c int
|
||||
}
|
||||
set aDiacritic($code) $int
|
||||
set aDiacritic($code,$f) $int
|
||||
if {$f==0} { set aDiacritic($code,1) $int }
|
||||
}
|
||||
|
||||
proc tcl_fold {i {bRemoveDiacritic 0}} {
|
||||
global tl_lookup_table
|
||||
global aDiacritic
|
||||
set f [expr $bRemoveDiacritic==2]
|
||||
|
||||
if {[info exists tl_lookup_table($i)]} {
|
||||
set i $tl_lookup_table($i)
|
||||
}
|
||||
if {$bRemoveDiacritic && [info exists aDiacritic($i)]} {
|
||||
set i $aDiacritic($i)
|
||||
if {$bRemoveDiacritic && [info exists aDiacritic($i,$f)]} {
|
||||
set i $aDiacritic($i,$f)
|
||||
}
|
||||
expr $i
|
||||
}
|
||||
@@ -85,7 +87,7 @@ do_execsql_test 1.1 {
|
||||
SELECT count(*), min(i) FROM ii WHERE fts5_fold(i)!=CAST(tcl_fold(i) AS int);
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
do_execsql_test 1.2.1 {
|
||||
WITH ii(i) AS (
|
||||
SELECT -1
|
||||
UNION ALL
|
||||
@@ -95,6 +97,16 @@ do_execsql_test 1.2 {
|
||||
WHERE fts5_fold(i,1)!=CAST(tcl_fold(i,1) AS int);
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 1.2.2 {
|
||||
WITH ii(i) AS (
|
||||
SELECT -1
|
||||
UNION ALL
|
||||
SELECT i+1 FROM ii WHERE i<100000
|
||||
)
|
||||
SELECT count(*), min(i) FROM ii
|
||||
WHERE fts5_fold(i,2)!=CAST(tcl_fold(i,2) AS int);
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
WITH ii(i) AS (
|
||||
SELECT -1
|
||||
|
||||
@@ -115,5 +115,43 @@ do_execsql_test 2.2.integrity {
|
||||
INSERT INTO x2(x2) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE x3 USING fts5(x, detail=%DETAIL%);
|
||||
INSERT INTO x3 VALUES('one');
|
||||
INSERT INTO x3 VALUES('two');
|
||||
INSERT INTO x3 VALUES('one');
|
||||
INSERT INTO x3 VALUES('two');
|
||||
INSERT INTO x3 VALUES('one');
|
||||
}
|
||||
|
||||
do_test 3.1 {
|
||||
db eval { SELECT * FROM x3('one') } {
|
||||
db eval {
|
||||
INSERT INTO x3(x3) VALUES('optimize');
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE x4 USING fts5(a, detail=%DETAIL%);
|
||||
INSERT INTO x4 VALUES('one two three');
|
||||
INSERT INTO x4(rowid, a) VALUES('2', 'one two three');
|
||||
INSERT INTO x4(rowid, a) VALUES('3.0', 'one two three');
|
||||
}
|
||||
do_catchsql_test 4.1 {
|
||||
INSERT INTO x4(rowid, a) VALUES('four', 'one two three');
|
||||
} {1 {datatype mismatch}}
|
||||
|
||||
do_catchsql_test 4.2 {
|
||||
UPDATE x4 SET rowid = 'four' WHERE rowid=1;
|
||||
} {1 {datatype mismatch}}
|
||||
|
||||
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_catchsql_test 4.0 { CREATE VIRTUAL TABLE t1 USING fts5(a,b,c); } {0 {}}
|
||||
do_catchsql_test 4.1 { DELETE FROM t1 WHERE t1 MATCH 'f*'; } {0 {}}
|
||||
finish_test
|
||||
|
||||
@@ -79,8 +79,8 @@ do_execsql_test 1.1.2 {
|
||||
3 cnt {} 0 {} 0
|
||||
}
|
||||
|
||||
do_execsql_test 1.2.1 { SELECT * FROM v1 } { }
|
||||
do_execsql_test 1.2.2 { SELECT * FROM v2 } { }
|
||||
do_execsql_test 1.2.1 { SELECT * FROM v1 } {}
|
||||
do_execsql_test 1.2.2 { SELECT * FROM v2 } {}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO t1 VALUES('x y z');
|
||||
@@ -479,6 +479,68 @@ do_test 9.6 {
|
||||
expr [lsearch $e2 SorterSort]<0
|
||||
} 0
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 10.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(a, b, c);
|
||||
CREATE VIRTUAL TABLE t2 USING fts5vocab('ft','row');
|
||||
CREATE VIRTUAL TABLE t3 USING fts5vocab('ft','row');
|
||||
}
|
||||
|
||||
do_execsql_test 10.1 {
|
||||
BEGIN;
|
||||
INSERT INTO ft(b) VALUES('x y');
|
||||
}
|
||||
|
||||
do_execsql_test 10.2 {
|
||||
SELECT t2.term FROM t2;
|
||||
} {x y}
|
||||
|
||||
do_execsql_test 10.3 {
|
||||
SELECT t2.term, t3.term FROM t2, t3;
|
||||
} {x x x y y x y y}
|
||||
|
||||
do_execsql_test 10.4 {
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 10.5 {
|
||||
BEGIN;
|
||||
INSERT INTO ft(a) VALUES('1 2 3');
|
||||
INSERT INTO ft(a) VALUES('4 5 6');
|
||||
INSERT INTO ft(a) VALUES('1 2 3');
|
||||
INSERT INTO ft(a) VALUES('4 5 6');
|
||||
INSERT INTO ft(a) VALUES('1 2 3');
|
||||
INSERT INTO ft(a) VALUES('4 5 6');
|
||||
}
|
||||
|
||||
do_test 10.6 {
|
||||
set res [list]
|
||||
db eval { SELECT rowid FROM ft('4') } x {
|
||||
db eval { SELECT * FROM t2 }
|
||||
lappend res $x(rowid)
|
||||
}
|
||||
db eval COMMIT
|
||||
set res
|
||||
} {3 5 7}
|
||||
|
||||
do_execsql_test 10.6.1 {
|
||||
SELECT * FROM t2 WHERE term<NULL;
|
||||
}
|
||||
do_execsql_test 10.6.2 {
|
||||
SELECT * FROM t2 WHERE term>NULL;
|
||||
}
|
||||
do_execsql_test 10.6.3 {
|
||||
SELECT * FROM t2 WHERE term=NULL;
|
||||
}
|
||||
do_execsql_test 10.7.1 {
|
||||
SELECT * FROM t2 WHERE term<?;
|
||||
}
|
||||
do_execsql_test 10.7.2 {
|
||||
SELECT * FROM t2 WHERE term>?;
|
||||
}
|
||||
do_execsql_test 10.7.3 {
|
||||
SELECT * FROM t2 WHERE term=?;
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -80,8 +80,7 @@ do_execsql_test 1.4 {
|
||||
do_execsql_test 1.5 {
|
||||
DELETE FROM t1;
|
||||
SELECT * FROM v1;
|
||||
} {
|
||||
}
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -143,8 +142,7 @@ do_execsql_test 2.4 {
|
||||
do_execsql_test 2.5 {
|
||||
DELETE FROM t1;
|
||||
SELECT * FROM v1;
|
||||
} {
|
||||
}
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -202,7 +200,38 @@ do_execsql_test 3.4 {
|
||||
do_execsql_test 3.5 {
|
||||
DELETE FROM t1;
|
||||
SELECT * FROM v1;
|
||||
} {
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE v1 USING fts5vocab(nosuchtable, col);
|
||||
}
|
||||
|
||||
do_catchsql_test 4.1 {
|
||||
SELECT * FROM v1 WHERE term=='nosuchterm';
|
||||
} {1 {no such fts5 table: main.nosuchtable}}
|
||||
|
||||
do_execsql_test 4.2.1 {
|
||||
CREATE TABLE nosuchtable(nosuchtable, y, z);
|
||||
}
|
||||
do_catchsql_test 4.2.2 {
|
||||
SELECT * FROM v1 WHERE term=='nosuchterm';
|
||||
} {1 {no such fts5 table: main.nosuchtable}}
|
||||
|
||||
ifcapable fts3 {
|
||||
do_execsql_test 4.3.1 {
|
||||
DROP TABLE nosuchtable;
|
||||
CREATE VIRTUAL TABLE nosuchtable USING fts3(a, b);
|
||||
} {}
|
||||
do_catchsql_test 4.3.2 {
|
||||
SELECT * FROM v1 WHERE term=='nosuchterm';
|
||||
} {1 {no such fts5 table: main.nosuchtable}}
|
||||
do_catchsql_test 4.3.3 {
|
||||
INSERT INTO nosuchtable VALUES('id', '*id');
|
||||
SELECT * FROM v1 WHERE term=='nosuchterm';
|
||||
} {1 {no such fts5 table: main.nosuchtable}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+5
-5
@@ -619,7 +619,7 @@ static int amatchLoadOneRule(
|
||||
if( p->rDel==0 || p->rDel>rCost ) p->rDel = rCost;
|
||||
}else
|
||||
{
|
||||
pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo );
|
||||
pRule = sqlite3_malloc64( sizeof(*pRule) + nFrom + nTo );
|
||||
if( pRule==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -738,11 +738,11 @@ static int amatchLoadRules(
|
||||
** `mno` becomes mno
|
||||
*/
|
||||
static char *amatchDequote(const char *zIn){
|
||||
int nIn; /* Size of input string, in bytes */
|
||||
sqlite3_int64 nIn; /* Size of input string, in bytes */
|
||||
char *zOut; /* Output (dequoted) string */
|
||||
|
||||
nIn = (int)strlen(zIn);
|
||||
zOut = sqlite3_malloc(nIn+1);
|
||||
nIn = strlen(zIn);
|
||||
zOut = sqlite3_malloc64(nIn+1);
|
||||
if( zOut ){
|
||||
char q = zIn[0]; /* Quote character (if any ) */
|
||||
|
||||
@@ -1069,7 +1069,7 @@ static void amatchAddWord(
|
||||
}
|
||||
return;
|
||||
}
|
||||
pWord = sqlite3_malloc( sizeof(*pWord) + nBase + nTail - 1 );
|
||||
pWord = sqlite3_malloc64( sizeof(*pWord) + nBase + nTail - 1 );
|
||||
if( pWord==0 ) return;
|
||||
memset(pWord, 0, sizeof(*pWord));
|
||||
pWord->rCost = rCost;
|
||||
|
||||
+3
-3
@@ -422,11 +422,11 @@ static closure_avl *queuePull(closure_queue *pQueue){
|
||||
** `mno` becomes mno
|
||||
*/
|
||||
static char *closureDequote(const char *zIn){
|
||||
int nIn; /* Size of input string, in bytes */
|
||||
sqlite3_int64 nIn; /* Size of input string, in bytes */
|
||||
char *zOut; /* Output (dequoted) string */
|
||||
|
||||
nIn = (int)strlen(zIn);
|
||||
zOut = sqlite3_malloc(nIn+1);
|
||||
nIn = strlen(zIn);
|
||||
zOut = sqlite3_malloc64(nIn+1);
|
||||
if( zOut ){
|
||||
char q = zIn[0]; /* Quote character (if any ) */
|
||||
|
||||
|
||||
+1
-1
@@ -621,7 +621,7 @@ static int csvtabConnect(
|
||||
}else if( pNew->zData ){
|
||||
pNew->iStart = (int)sRdr.iIn;
|
||||
}else{
|
||||
pNew->iStart = ftell(sRdr.in);
|
||||
pNew->iStart = (int)(ftell(sRdr.in) - sRdr.nIn + sRdr.iIn);
|
||||
}
|
||||
csv_reader_reset(&sRdr);
|
||||
rc = sqlite3_declare_vtab(db, CSV_SCHEMA);
|
||||
|
||||
+1
-1
@@ -195,7 +195,7 @@ static char **tableColumnList(DState *p, const char *zTab){
|
||||
if( nCol>=nAlloc-2 ){
|
||||
char **azNew;
|
||||
nAlloc = nAlloc*2 + nCol + 10;
|
||||
azNew = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0]));
|
||||
azNew = sqlite3_realloc64(azCol, nAlloc*sizeof(azCol[0]));
|
||||
if( azNew==0 ) goto col_oom;
|
||||
azCol = azNew;
|
||||
azCol[0] = 0;
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ static int callback(void *pCtx, int argc, char **argv, char **colnames){
|
||||
/* Using sqlite3_realloc64() would be better, but it is a recent
|
||||
** addition and will cause a segfault if loaded by an older version
|
||||
** of SQLite. */
|
||||
zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0;
|
||||
zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc64(p->z, p->nAlloc) : 0;
|
||||
if( zNew==0 ){
|
||||
sqlite3_free(p->z);
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
+35
-10
@@ -121,22 +121,47 @@ SQLITE_EXTENSION_INIT1
|
||||
|
||||
/*
|
||||
** Set the result stored by context ctx to a blob containing the
|
||||
** contents of file zName.
|
||||
** contents of file zName. Or, leave the result unchanged (NULL)
|
||||
** if the file does not exist or is unreadable.
|
||||
**
|
||||
** If the file exceeds the SQLite blob size limit, through an
|
||||
** SQLITE_TOOBIG error.
|
||||
**
|
||||
** Throw an SQLITE_IOERR if there are difficulties pulling the file
|
||||
** off of disk.
|
||||
*/
|
||||
static void readFileContents(sqlite3_context *ctx, const char *zName){
|
||||
FILE *in;
|
||||
long nIn;
|
||||
sqlite3_int64 nIn;
|
||||
void *pBuf;
|
||||
sqlite3 *db;
|
||||
int mxBlob;
|
||||
|
||||
in = fopen(zName, "rb");
|
||||
if( in==0 ) return;
|
||||
if( in==0 ){
|
||||
/* File does not exist or is unreadable. Leave the result set to NULL. */
|
||||
return;
|
||||
}
|
||||
fseek(in, 0, SEEK_END);
|
||||
nIn = ftell(in);
|
||||
rewind(in);
|
||||
pBuf = sqlite3_malloc( nIn );
|
||||
if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
|
||||
sqlite3_result_blob(ctx, pBuf, nIn, sqlite3_free);
|
||||
db = sqlite3_context_db_handle(ctx);
|
||||
mxBlob = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1);
|
||||
if( nIn>mxBlob ){
|
||||
sqlite3_result_error_code(ctx, SQLITE_TOOBIG);
|
||||
fclose(in);
|
||||
return;
|
||||
}
|
||||
pBuf = sqlite3_malloc64( nIn );
|
||||
if( pBuf==0 ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
fclose(in);
|
||||
return;
|
||||
}
|
||||
if( 1==fread(pBuf, nIn, 1, in) ){
|
||||
sqlite3_result_blob64(ctx, pBuf, nIn, sqlite3_free);
|
||||
}else{
|
||||
sqlite3_result_error_code(ctx, SQLITE_IOERR);
|
||||
sqlite3_free(pBuf);
|
||||
}
|
||||
fclose(in);
|
||||
@@ -646,8 +671,8 @@ static int fsdirNext(sqlite3_vtab_cursor *cur){
|
||||
FsdirLevel *pLvl;
|
||||
if( iNew>=pCur->nLvl ){
|
||||
int nNew = iNew+1;
|
||||
int nByte = nNew*sizeof(FsdirLevel);
|
||||
FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc(pCur->aLvl, nByte);
|
||||
sqlite3_int64 nByte = nNew*sizeof(FsdirLevel);
|
||||
FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc64(pCur->aLvl, nByte);
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
|
||||
pCur->aLvl = aNew;
|
||||
@@ -727,7 +752,7 @@ static int fsdirColumn(
|
||||
}else if( S_ISLNK(m) ){
|
||||
char aStatic[64];
|
||||
char *aBuf = aStatic;
|
||||
int nBuf = 64;
|
||||
sqlite3_int64 nBuf = 64;
|
||||
int n;
|
||||
|
||||
while( 1 ){
|
||||
@@ -735,7 +760,7 @@ static int fsdirColumn(
|
||||
if( n<nBuf ) break;
|
||||
if( aBuf!=aStatic ) sqlite3_free(aBuf);
|
||||
nBuf = nBuf*2;
|
||||
aBuf = sqlite3_malloc(nBuf);
|
||||
aBuf = sqlite3_malloc64(nBuf);
|
||||
if( aBuf==0 ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
return SQLITE_NOMEM;
|
||||
|
||||
+8
-8
@@ -337,7 +337,7 @@ static int fuzzerLoadOneRule(
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
|
||||
pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo );
|
||||
pRule = sqlite3_malloc64( sizeof(*pRule) + nFrom + nTo );
|
||||
if( pRule==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -447,11 +447,11 @@ static int fuzzerLoadRules(
|
||||
** `mno` becomes mno
|
||||
*/
|
||||
static char *fuzzerDequote(const char *zIn){
|
||||
int nIn; /* Size of input string, in bytes */
|
||||
sqlite3_int64 nIn; /* Size of input string, in bytes */
|
||||
char *zOut; /* Output (dequoted) string */
|
||||
|
||||
nIn = (int)strlen(zIn);
|
||||
zOut = sqlite3_malloc(nIn+1);
|
||||
nIn = strlen(zIn);
|
||||
zOut = sqlite3_malloc64(nIn+1);
|
||||
if( zOut ){
|
||||
char q = zIn[0]; /* Quote character (if any ) */
|
||||
|
||||
@@ -513,10 +513,10 @@ static int fuzzerConnect(
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
int nModule; /* Length of zModule, in bytes */
|
||||
sqlite3_int64 nModule; /* Length of zModule, in bytes */
|
||||
|
||||
nModule = (int)strlen(zModule);
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) + nModule + 1);
|
||||
nModule = strlen(zModule);
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) + nModule + 1);
|
||||
if( pNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -872,7 +872,7 @@ static fuzzer_stem *fuzzerNewStem(
|
||||
fuzzer_rule *pRule;
|
||||
unsigned int h;
|
||||
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) + (int)strlen(zWord) + 1 );
|
||||
pNew = sqlite3_malloc64( sizeof(*pNew) + strlen(zWord) + 1 );
|
||||
if( pNew==0 ) return 0;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->zBasis = (char*)&pNew[1];
|
||||
|
||||
+3
-3
@@ -691,7 +691,7 @@ static JSON_NOINLINE int jsonParseAddNodeExpand(
|
||||
assert( pParse->nNode>=pParse->nAlloc );
|
||||
if( pParse->oom ) return -1;
|
||||
nNew = pParse->nAlloc*2 + 10;
|
||||
pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew);
|
||||
pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew);
|
||||
if( pNew==0 ){
|
||||
pParse->oom = 1;
|
||||
return -1;
|
||||
@@ -965,7 +965,7 @@ static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
|
||||
static int jsonParseFindParents(JsonParse *pParse){
|
||||
u32 *aUp;
|
||||
assert( pParse->aUp==0 );
|
||||
aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode );
|
||||
aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode );
|
||||
if( aUp==0 ){
|
||||
pParse->oom = 1;
|
||||
return SQLITE_NOMEM;
|
||||
@@ -1027,7 +1027,7 @@ static JsonParse *jsonParseCached(
|
||||
pMatch->iHold = iMaxHold+1;
|
||||
return pMatch;
|
||||
}
|
||||
p = sqlite3_malloc( sizeof(*p) + nJson + 1 );
|
||||
p = sqlite3_malloc64( sizeof(*p) + nJson + 1 );
|
||||
if( p==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -143,7 +143,7 @@ static int memstatFindSchemas(memstat_cursor *pCur){
|
||||
}
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
char **az, *z;
|
||||
az = sqlite3_realloc(pCur->azDb, sizeof(char*)*(pCur->nDb+1));
|
||||
az = sqlite3_realloc64(pCur->azDb, sizeof(char*)*(pCur->nDb+1));
|
||||
if( az==0 ){
|
||||
memstatClearSchema(pCur);
|
||||
return SQLITE_NOMEM;
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
** 2019-01-21
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file implements an extension that uses the SQLITE_CONFIG_MALLOC
|
||||
** mechanism to add a tracing layer on top of SQLite. If this extension
|
||||
** is registered prior to sqlite3_initialize(), it will cause all memory
|
||||
** allocation activities to be logged on standard output, or to some other
|
||||
** FILE specified by the initializer.
|
||||
**
|
||||
** This file needs to be compiled into the application that uses it.
|
||||
**
|
||||
** This extension is used to implement the --memtrace option of the
|
||||
** command-line shell.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* The original memory allocation routines */
|
||||
static sqlite3_mem_methods memtraceBase;
|
||||
static FILE *memtraceOut;
|
||||
|
||||
/* Methods that trace memory allocations */
|
||||
static void *memtraceMalloc(int n){
|
||||
if( memtraceOut ){
|
||||
fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n",
|
||||
memtraceBase.xRoundup(n));
|
||||
}
|
||||
return memtraceBase.xMalloc(n);
|
||||
}
|
||||
static void memtraceFree(void *p){
|
||||
if( p==0 ) return;
|
||||
if( memtraceOut ){
|
||||
fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p));
|
||||
}
|
||||
memtraceBase.xFree(p);
|
||||
}
|
||||
static void *memtraceRealloc(void *p, int n){
|
||||
if( p==0 ) return memtraceMalloc(n);
|
||||
if( n==0 ){
|
||||
memtraceFree(p);
|
||||
return 0;
|
||||
}
|
||||
if( memtraceOut ){
|
||||
fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n",
|
||||
memtraceBase.xSize(p), memtraceBase.xRoundup(n));
|
||||
}
|
||||
return memtraceBase.xRealloc(p, n);
|
||||
}
|
||||
static int memtraceSize(void *p){
|
||||
return memtraceBase.xSize(p);
|
||||
}
|
||||
static int memtraceRoundup(int n){
|
||||
return memtraceBase.xRoundup(n);
|
||||
}
|
||||
static int memtraceInit(void *p){
|
||||
return memtraceBase.xInit(p);
|
||||
}
|
||||
static void memtraceShutdown(void *p){
|
||||
memtraceBase.xShutdown(p);
|
||||
}
|
||||
|
||||
/* The substitute memory allocator */
|
||||
static sqlite3_mem_methods ersaztMethods = {
|
||||
memtraceMalloc,
|
||||
memtraceFree,
|
||||
memtraceRealloc,
|
||||
memtraceSize,
|
||||
memtraceRoundup,
|
||||
memtraceInit,
|
||||
memtraceShutdown,
|
||||
0
|
||||
};
|
||||
|
||||
/* Begin tracing memory allocations to out. */
|
||||
int sqlite3MemTraceActivate(FILE *out){
|
||||
int rc = SQLITE_OK;
|
||||
if( memtraceBase.xMalloc==0 ){
|
||||
rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods);
|
||||
}
|
||||
}
|
||||
memtraceOut = out;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Deactivate memory tracing */
|
||||
int sqlite3MemTraceDeactivate(void){
|
||||
int rc = SQLITE_OK;
|
||||
if( memtraceBase.xMalloc!=0 ){
|
||||
rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase);
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(&memtraceBase, 0, sizeof(memtraceBase));
|
||||
}
|
||||
}
|
||||
memtraceOut = 0;
|
||||
return rc;
|
||||
}
|
||||
@@ -105,4 +105,3 @@ int sqlite3_mmap_warm(sqlite3 *db, const char *zDb){
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -85,7 +85,7 @@ static void nextCharAppend(nextCharContext *p, unsigned c){
|
||||
if( p->nUsed+1 > p->nAlloc ){
|
||||
unsigned int *aNew;
|
||||
int n = p->nAlloc*2 + 30;
|
||||
aNew = sqlite3_realloc(p->aResult, n*sizeof(unsigned int));
|
||||
aNew = sqlite3_realloc64(p->aResult, n*sizeof(unsigned int));
|
||||
if( aNew==0 ){
|
||||
p->mallocFailed = 1;
|
||||
return;
|
||||
@@ -269,7 +269,7 @@ static void nextCharFunc(
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else{
|
||||
unsigned char *pRes;
|
||||
pRes = sqlite3_malloc( c.nUsed*4 + 1 );
|
||||
pRes = sqlite3_malloc64( c.nUsed*4 + 1 );
|
||||
if( pRes==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else{
|
||||
|
||||
@@ -151,7 +151,7 @@ static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){
|
||||
/* Allocate and store the Y */
|
||||
if( p->nUsed>=p->nAlloc ){
|
||||
unsigned n = p->nAlloc*2 + 250;
|
||||
double *a = sqlite3_realloc(p->a, sizeof(double)*n);
|
||||
double *a = sqlite3_realloc64(p->a, sizeof(double)*n);
|
||||
if( a==0 ){
|
||||
sqlite3_free(p->a);
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
** 2018-04-19
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file implements a table-valued function:
|
||||
**
|
||||
** prefixes('abcdefg')
|
||||
**
|
||||
** The function has a single (non-HIDDEN) column named prefix that takes
|
||||
** on all prefixes of the string in its argument, including an empty string
|
||||
** and the input string itself. The order of prefixes is from longest
|
||||
** to shortest.
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) || !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
#if !defined(SQLITEINT_H)
|
||||
#include "sqlite3ext.h"
|
||||
#endif
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* prefixes_vtab is a subclass of sqlite3_vtab which is
|
||||
** underlying representation of the virtual table
|
||||
*/
|
||||
typedef struct prefixes_vtab prefixes_vtab;
|
||||
struct prefixes_vtab {
|
||||
sqlite3_vtab base; /* Base class - must be first */
|
||||
/* No additional fields are necessary */
|
||||
};
|
||||
|
||||
/* prefixes_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
** serve as the underlying representation of a cursor that scans
|
||||
** over rows of the result
|
||||
*/
|
||||
typedef struct prefixes_cursor prefixes_cursor;
|
||||
struct prefixes_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3_int64 iRowid; /* The rowid */
|
||||
char *zStr; /* Original string to be prefixed */
|
||||
int nStr; /* Length of the string in bytes */
|
||||
};
|
||||
|
||||
/*
|
||||
** The prefixesConnect() method is invoked to create a new
|
||||
** template virtual table.
|
||||
**
|
||||
** Think of this routine as the constructor for prefixes_vtab objects.
|
||||
**
|
||||
** All this routine needs to do is:
|
||||
**
|
||||
** (1) Allocate the prefixes_vtab object and initialize all fields.
|
||||
**
|
||||
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
|
||||
** result set of queries against the virtual table will look like.
|
||||
*/
|
||||
static int prefixesConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
prefixes_vtab *pNew;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE prefixes(prefix TEXT, original_string TEXT HIDDEN)"
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for prefixes_vtab objects.
|
||||
*/
|
||||
static int prefixesDisconnect(sqlite3_vtab *pVtab){
|
||||
prefixes_vtab *p = (prefixes_vtab*)pVtab;
|
||||
sqlite3_free(p);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new prefixes_cursor object.
|
||||
*/
|
||||
static int prefixesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
prefixes_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for a prefixes_cursor.
|
||||
*/
|
||||
static int prefixesClose(sqlite3_vtab_cursor *cur){
|
||||
prefixes_cursor *pCur = (prefixes_cursor*)cur;
|
||||
sqlite3_free(pCur->zStr);
|
||||
sqlite3_free(pCur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance a prefixes_cursor to its next row of output.
|
||||
*/
|
||||
static int prefixesNext(sqlite3_vtab_cursor *cur){
|
||||
prefixes_cursor *pCur = (prefixes_cursor*)cur;
|
||||
pCur->iRowid++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the prefixes_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int prefixesColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
prefixes_cursor *pCur = (prefixes_cursor*)cur;
|
||||
switch( i ){
|
||||
case 0:
|
||||
sqlite3_result_text(ctx, pCur->zStr, pCur->nStr - (int)pCur->iRowid,
|
||||
0);
|
||||
break;
|
||||
default:
|
||||
sqlite3_result_text(ctx, pCur->zStr, pCur->nStr, 0);
|
||||
break;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** rowid is the same as the output value.
|
||||
*/
|
||||
static int prefixesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
prefixes_cursor *pCur = (prefixes_cursor*)cur;
|
||||
*pRowid = pCur->iRowid;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int prefixesEof(sqlite3_vtab_cursor *cur){
|
||||
prefixes_cursor *pCur = (prefixes_cursor*)cur;
|
||||
return pCur->iRowid>pCur->nStr;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the prefixes_cursor object back
|
||||
** to the first row of output. This method is always called at least
|
||||
** once prior to any call to prefixesColumn() or prefixesRowid() or
|
||||
** prefixesEof().
|
||||
*/
|
||||
static int prefixesFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
prefixes_cursor *pCur = (prefixes_cursor *)pVtabCursor;
|
||||
sqlite3_free(pCur->zStr);
|
||||
if( argc>0 ){
|
||||
pCur->zStr = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
|
||||
pCur->nStr = pCur->zStr ? (int)strlen(pCur->zStr) : 0;
|
||||
}else{
|
||||
pCur->zStr = 0;
|
||||
pCur->nStr = 0;
|
||||
}
|
||||
pCur->iRowid = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** SQLite will invoke this method one or more times while planning a query
|
||||
** that uses the virtual table. This routine needs to create
|
||||
** a query plan for each invocation and compute an estimated cost for that
|
||||
** plan.
|
||||
*/
|
||||
static int prefixesBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
/* Search for a usable equality constraint against column 1
|
||||
** (original_string) and use it if at all possible */
|
||||
int i;
|
||||
const struct sqlite3_index_constraint *p;
|
||||
|
||||
for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
|
||||
if( p->iColumn!=1 ) continue;
|
||||
if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
if( !p->usable ) continue;
|
||||
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
pIdxInfo->estimatedCost = (double)10;
|
||||
pIdxInfo->estimatedRows = 10;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pIdxInfo->estimatedCost = (double)1000000000;
|
||||
pIdxInfo->estimatedRows = 1000000000;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** virtual table.
|
||||
*/
|
||||
static sqlite3_module prefixesModule = {
|
||||
/* iVersion */ 0,
|
||||
/* xCreate */ 0,
|
||||
/* xConnect */ prefixesConnect,
|
||||
/* xBestIndex */ prefixesBestIndex,
|
||||
/* xDisconnect */ prefixesDisconnect,
|
||||
/* xDestroy */ 0,
|
||||
/* xOpen */ prefixesOpen,
|
||||
/* xClose */ prefixesClose,
|
||||
/* xFilter */ prefixesFilter,
|
||||
/* xNext */ prefixesNext,
|
||||
/* xEof */ prefixesEof,
|
||||
/* xColumn */ prefixesColumn,
|
||||
/* xRowid */ prefixesRowid,
|
||||
/* xUpdate */ 0,
|
||||
/* xBegin */ 0,
|
||||
/* xSync */ 0,
|
||||
/* xCommit */ 0,
|
||||
/* xRollback */ 0,
|
||||
/* xFindMethod */ 0,
|
||||
/* xRename */ 0,
|
||||
/* xSavepoint */ 0,
|
||||
/* xRelease */ 0,
|
||||
/* xRollbackTo */ 0,
|
||||
/* xShadowName */ 0
|
||||
};
|
||||
|
||||
/*
|
||||
** This is a copy of the SQLITE_SKIP_UTF8(zIn) macro in sqliteInt.h.
|
||||
**
|
||||
** Assuming zIn points to the first byte of a UTF-8 character,
|
||||
** advance zIn to point to the first byte of the next UTF-8 character.
|
||||
*/
|
||||
#define PREFIX_SKIP_UTF8(zIn) { \
|
||||
if( (*(zIn++))>=0xc0 ){ \
|
||||
while( (*zIn & 0xc0)==0x80 ){ zIn++; } \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of function prefix_length(). This function accepts two
|
||||
** strings as arguments and returns the length in characters (not bytes),
|
||||
** of the longest prefix shared by the two strings. For example:
|
||||
**
|
||||
** prefix_length('abcdxxx', 'abcyy') == 3
|
||||
** prefix_length('abcdxxx', 'bcyyy') == 0
|
||||
** prefix_length('abcdxxx', 'ab') == 2
|
||||
** prefix_length('ab', 'abcd') == 2
|
||||
**
|
||||
** This function assumes the input is well-formed utf-8. If it is not,
|
||||
** it is possible for this function to return -1.
|
||||
*/
|
||||
static void prefixLengthFunc(
|
||||
sqlite3_context *ctx,
|
||||
int nVal,
|
||||
sqlite3_value **apVal
|
||||
){
|
||||
int nByte; /* Number of bytes to compare */
|
||||
int nRet = 0; /* Return value */
|
||||
const unsigned char *zL = sqlite3_value_text(apVal[0]);
|
||||
const unsigned char *zR = sqlite3_value_text(apVal[1]);
|
||||
int nL = sqlite3_value_bytes(apVal[0]);
|
||||
int nR = sqlite3_value_bytes(apVal[1]);
|
||||
int i;
|
||||
|
||||
nByte = (nL > nR ? nL : nR);
|
||||
for(i=0; i<nByte; i++){
|
||||
if( zL[i]!=zR[i] ) break;
|
||||
if( (zL[i] & 0xC0)!=0x80 ) nRet++;
|
||||
}
|
||||
|
||||
if( (zL[i] & 0xC0)==0x80 ) nRet--;
|
||||
sqlite3_result_int(ctx, nRet);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_prefixes_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
rc = sqlite3_create_module(db, "prefixes", &prefixesModule, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(
|
||||
db, "prefix_length", 2, SQLITE_UTF8, 0, prefixLengthFunc, 0, 0
|
||||
);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif /* !defined(SQLITE_CORE) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
|
||||
+3
-3
@@ -225,7 +225,7 @@ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
|
||||
pToFree = 0;
|
||||
aStateSet[0].aState = aSpace;
|
||||
}else{
|
||||
pToFree = sqlite3_malloc( sizeof(ReStateNumber)*2*pRe->nState );
|
||||
pToFree = sqlite3_malloc64( sizeof(ReStateNumber)*2*pRe->nState );
|
||||
if( pToFree==0 ) return -1;
|
||||
aStateSet[0].aState = pToFree;
|
||||
}
|
||||
@@ -337,10 +337,10 @@ re_match_end:
|
||||
static int re_resize(ReCompiled *p, int N){
|
||||
char *aOp;
|
||||
int *aArg;
|
||||
aOp = sqlite3_realloc(p->aOp, N*sizeof(p->aOp[0]));
|
||||
aOp = sqlite3_realloc64(p->aOp, N*sizeof(p->aOp[0]));
|
||||
if( aOp==0 ) return 1;
|
||||
p->aOp = aOp;
|
||||
aArg = sqlite3_realloc(p->aArg, N*sizeof(p->aArg[0]));
|
||||
aArg = sqlite3_realloc64(p->aArg, N*sizeof(p->aArg[0]));
|
||||
if( aArg==0 ) return 1;
|
||||
p->aArg = aArg;
|
||||
p->nAlloc = N;
|
||||
|
||||
@@ -250,11 +250,11 @@ struct UnionCsr {
|
||||
** is attempted but fails, NULL is returned and *pRc is set to
|
||||
** SQLITE_NOMEM.
|
||||
*/
|
||||
static void *unionMalloc(int *pRc, int nByte){
|
||||
static void *unionMalloc(int *pRc, sqlite3_int64 nByte){
|
||||
void *pRet;
|
||||
assert( nByte>0 );
|
||||
if( *pRc==SQLITE_OK ){
|
||||
pRet = sqlite3_malloc(nByte);
|
||||
pRet = sqlite3_malloc64(nByte);
|
||||
if( pRet ){
|
||||
memset(pRet, 0, nByte);
|
||||
}else{
|
||||
@@ -276,7 +276,7 @@ static void *unionMalloc(int *pRc, int nByte){
|
||||
static char *unionStrdup(int *pRc, const char *zIn){
|
||||
char *zRet = 0;
|
||||
if( zIn ){
|
||||
int nByte = (int)strlen(zIn) + 1;
|
||||
sqlite3_int64 nByte = strlen(zIn) + 1;
|
||||
zRet = unionMalloc(pRc, nByte);
|
||||
if( zRet ){
|
||||
memcpy(zRet, zIn, nByte);
|
||||
@@ -939,7 +939,7 @@ static int unionConnect(
|
||||
/* Grow the pTab->aSrc[] array if required. */
|
||||
if( nAlloc<=pTab->nSrc ){
|
||||
int nNew = nAlloc ? nAlloc*2 : 8;
|
||||
UnionSrc *aNew = (UnionSrc*)sqlite3_realloc(
|
||||
UnionSrc *aNew = (UnionSrc*)sqlite3_realloc64(
|
||||
pTab->aSrc, nNew*sizeof(UnionSrc)
|
||||
);
|
||||
if( aNew==0 ){
|
||||
|
||||
+1
-1
@@ -276,7 +276,7 @@ static VLogLog *vlogLogOpen(const char *zFilename){
|
||||
&& sqlite3_strglob("-mj??????9??", zFilename+nName-12)==0 ){
|
||||
return 0; /* Do not log master journal files */
|
||||
}
|
||||
pTemp = sqlite3_malloc( sizeof(*pLog)*2 + nName + 60 );
|
||||
pTemp = sqlite3_malloc64( sizeof(*pLog)*2 + nName + 60 );
|
||||
if( pTemp==0 ) return 0;
|
||||
pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
sqlite3_mutex_enter(pMutex);
|
||||
|
||||
+12
-12
@@ -358,7 +358,7 @@ static int zipfileConnect(
|
||||
|
||||
rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA);
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = (ZipfileTab*)sqlite3_malloc(nByte+nFile);
|
||||
pNew = (ZipfileTab*)sqlite3_malloc64((sqlite3_int64)nByte+nFile);
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, nByte+nFile);
|
||||
pNew->db = db;
|
||||
@@ -806,7 +806,7 @@ static int zipfileGetEntry(
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
int nAlloc;
|
||||
sqlite3_int64 nAlloc;
|
||||
ZipfileEntry *pNew;
|
||||
|
||||
int nFile = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF]);
|
||||
@@ -818,7 +818,7 @@ static int zipfileGetEntry(
|
||||
nAlloc += zipfileGetU32(&aRead[ZIPFILE_CDS_SZCOMPRESSED_OFF]);
|
||||
}
|
||||
|
||||
pNew = (ZipfileEntry*)sqlite3_malloc(nAlloc);
|
||||
pNew = (ZipfileEntry*)sqlite3_malloc64(nAlloc);
|
||||
if( pNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -981,11 +981,11 @@ static int zipfileDeflate(
|
||||
u8 **ppOut, int *pnOut, /* Output */
|
||||
char **pzErr /* OUT: Error message */
|
||||
){
|
||||
int nAlloc = (int)compressBound(nIn);
|
||||
sqlite3_int64 nAlloc = compressBound(nIn);
|
||||
u8 *aOut;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
aOut = (u8*)sqlite3_malloc(nAlloc);
|
||||
aOut = (u8*)sqlite3_malloc64(nAlloc);
|
||||
if( aOut==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1058,7 +1058,7 @@ static int zipfileColumn(
|
||||
if( pCsr->pCurrent->aData ){
|
||||
aBuf = pCsr->pCurrent->aData;
|
||||
}else{
|
||||
aBuf = aFree = sqlite3_malloc(sz);
|
||||
aBuf = aFree = sqlite3_malloc64(sz);
|
||||
if( aBuf==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1897,14 +1897,14 @@ struct ZipfileCtx {
|
||||
static int zipfileBufferGrow(ZipfileBuffer *pBuf, int nByte){
|
||||
if( pBuf->n+nByte>pBuf->nAlloc ){
|
||||
u8 *aNew;
|
||||
int nNew = pBuf->n ? pBuf->n*2 : 512;
|
||||
sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512;
|
||||
int nReq = pBuf->n + nByte;
|
||||
|
||||
while( nNew<nReq ) nNew = nNew*2;
|
||||
aNew = sqlite3_realloc(pBuf->a, nNew);
|
||||
aNew = sqlite3_realloc64(pBuf->a, nNew);
|
||||
if( aNew==0 ) return SQLITE_NOMEM;
|
||||
pBuf->a = aNew;
|
||||
pBuf->nAlloc = nNew;
|
||||
pBuf->nAlloc = (int)nNew;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -2095,7 +2095,7 @@ void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
|
||||
void zipfileFinal(sqlite3_context *pCtx){
|
||||
ZipfileCtx *p;
|
||||
ZipfileEOCD eocd;
|
||||
int nZip;
|
||||
sqlite3_int64 nZip;
|
||||
u8 *aZip;
|
||||
|
||||
p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx));
|
||||
@@ -2108,14 +2108,14 @@ void zipfileFinal(sqlite3_context *pCtx){
|
||||
eocd.iOffset = p->body.n;
|
||||
|
||||
nZip = p->body.n + p->cds.n + ZIPFILE_EOCD_FIXED_SZ;
|
||||
aZip = (u8*)sqlite3_malloc(nZip);
|
||||
aZip = (u8*)sqlite3_malloc64(nZip);
|
||||
if( aZip==0 ){
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
}else{
|
||||
memcpy(aZip, p->body.a, p->body.n);
|
||||
memcpy(&aZip[p->body.n], p->cds.a, p->cds.n);
|
||||
zipfileSerializeEOCD(&eocd, &aZip[p->body.n + p->cds.n]);
|
||||
sqlite3_result_blob(pCtx, aZip, nZip, zipfileFree);
|
||||
sqlite3_result_blob(pCtx, aZip, (int)nZip, zipfileFree);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,12 +86,13 @@ proc step_rbu_legacy {target rbu} {
|
||||
set rc
|
||||
}
|
||||
|
||||
proc do_rbu_vacuum_test {tn step} {
|
||||
forcedelete state.db
|
||||
uplevel [list do_test $tn.1 {
|
||||
if {$step==0} { sqlite3rbu_vacuum rbu test.db state.db }
|
||||
proc do_rbu_vacuum_test {tn step {statedb state.db}} {
|
||||
forcedelete $statedb
|
||||
if {$statedb=="" && $step==1} breakpoint
|
||||
uplevel [list do_test $tn.1 [string map [list %state% $statedb] {
|
||||
if {$step==0} { sqlite3rbu_vacuum rbu test.db {%state%}}
|
||||
while 1 {
|
||||
if {$step==1} { sqlite3rbu_vacuum rbu test.db state.db }
|
||||
if {$step==1} { sqlite3rbu_vacuum rbu test.db {%state%}}
|
||||
set state [rbu state]
|
||||
check_prestep_state test.db $state
|
||||
set rc [rbu step]
|
||||
@@ -100,7 +101,7 @@ proc do_rbu_vacuum_test {tn step} {
|
||||
if {$step==1} { rbu close }
|
||||
}
|
||||
rbu close
|
||||
} {SQLITE_DONE}]
|
||||
}] {SQLITE_DONE}]
|
||||
|
||||
uplevel [list do_execsql_test $tn.2 {
|
||||
PRAGMA integrity_check
|
||||
|
||||
+18
-9
@@ -16,8 +16,11 @@
|
||||
|
||||
source [file join [file dirname [info script]] rbu_common.tcl]
|
||||
|
||||
foreach step {0 1} {
|
||||
set ::testprefix rbuvacuum2-$step
|
||||
foreach {step} {0 1} {
|
||||
foreach {ttt state} {
|
||||
s state.db t test.db-vacuum n {}
|
||||
} {
|
||||
set ::testprefix rbuvacuum2-$step$ttt
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that a database that contains fts3 tables can be vacuumed.
|
||||
@@ -29,7 +32,7 @@ foreach step {0 1} {
|
||||
INSERT INTO t1 VALUES('fix this issue', 'at some point');
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 1.2 $step
|
||||
do_rbu_vacuum_test 1.2 $step $state
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SELECT * FROM t1;
|
||||
@@ -46,7 +49,7 @@ foreach step {0 1} {
|
||||
INSERT INTO t1 VALUES('a b c', 'x y z');
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 1.6 $step
|
||||
do_rbu_vacuum_test 1.6 $step $state
|
||||
do_execsql_test 1.7 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
SELECT * FROM t1;
|
||||
@@ -67,7 +70,7 @@ foreach step {0 1} {
|
||||
INSERT INTO t1 VALUES('fix this issue', 'at some point');
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 2.2 $step
|
||||
do_rbu_vacuum_test 2.2 $step $state
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
SELECT * FROM t1;
|
||||
@@ -84,7 +87,7 @@ foreach step {0 1} {
|
||||
INSERT INTO t1 VALUES('a b c', 'x y z');
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 2.6 $step
|
||||
do_rbu_vacuum_test 2.6 $step $state
|
||||
do_execsql_test 2.7 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
SELECT * FROM t1;
|
||||
@@ -107,7 +110,7 @@ foreach step {0 1} {
|
||||
INSERT INTO rt VALUES(3, 55, 65);
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 3.2 $step
|
||||
do_rbu_vacuum_test 3.2 $step $state
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
SELECT * FROM rt;
|
||||
@@ -120,7 +123,7 @@ foreach step {0 1} {
|
||||
SELECT rowid FROM rt WHERE x2>59 AND x1 < 59
|
||||
} {2 3}
|
||||
|
||||
do_rbu_vacuum_test 3.5 $step
|
||||
do_rbu_vacuum_test 3.5 $step $state
|
||||
|
||||
do_execsql_test 3.6.1 {
|
||||
SELECT rowid FROM rt WHERE x2>51 AND x1 < 51
|
||||
@@ -147,7 +150,7 @@ foreach step {0 1} {
|
||||
trigger tr1 t1 0 {CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END}
|
||||
}
|
||||
|
||||
do_rbu_vacuum_test 4.3 $step
|
||||
do_rbu_vacuum_test 4.3 $step $state
|
||||
do_execsql_test 4.4 {
|
||||
SELECT * FROM sqlite_master;
|
||||
} {
|
||||
@@ -157,6 +160,7 @@ foreach step {0 1} {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that passing a NULL value as the second argument to
|
||||
@@ -231,4 +235,9 @@ do_test 6.3 {
|
||||
execsql { PRAGMA integrity_check }
|
||||
} {ok}
|
||||
|
||||
do_test 6.4 {
|
||||
sqlite3rbu_vacuum rbu test.db test.db-vactmp
|
||||
list [catch { rbu close } msg] $msg
|
||||
} {1 SQLITE_MISUSE}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# 2019 Jan 3
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains tests for the RBU module. More specifically, it
|
||||
# contains tests to ensure that the sqlite3rbu_vacuum() API works as
|
||||
# expected.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] rbu_common.tcl]
|
||||
set testprefix rbuvacuum3
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b, c);
|
||||
CREATE INDEX i1b ON t1(b);
|
||||
CREATE INDEX i1c ON t1(c);
|
||||
|
||||
WITH s(i) AS (
|
||||
VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100
|
||||
)
|
||||
INSERT INTO t1 SELECT i, randomblob(100), randomblob(100) FROM s;
|
||||
}
|
||||
|
||||
forcedelete state.db
|
||||
do_test 1.1 {
|
||||
sqlite3rbu_vacuum rbu test.db state.db
|
||||
while {1} {
|
||||
set rc [rbu step]
|
||||
if {$rc!="SQLITE_OK"} break
|
||||
rbu savestate
|
||||
}
|
||||
rbu close
|
||||
} {SQLITE_DONE}
|
||||
|
||||
do_test 1.2 {
|
||||
sqlite3rbu_vacuum rbu test.db state.db
|
||||
while {1} {
|
||||
set rc [rbu step]
|
||||
if {$rc!="SQLITE_OK"} break
|
||||
rbu savestate
|
||||
}
|
||||
rbu close
|
||||
} {SQLITE_DONE}
|
||||
|
||||
do_test 1.3 {
|
||||
while {1} {
|
||||
sqlite3rbu_vacuum rbu test.db state.db
|
||||
set rc [rbu step]
|
||||
if {$rc!="SQLITE_OK"} break
|
||||
rbu savestate
|
||||
rbu close
|
||||
}
|
||||
rbu close
|
||||
} {SQLITE_DONE}
|
||||
|
||||
finish_test
|
||||
+11
-2
@@ -2477,7 +2477,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
|
||||
if( *zExtra=='\0' ) zExtra = 0;
|
||||
}
|
||||
|
||||
zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s",
|
||||
zTarget = sqlite3_mprintf("file:%s-vactmp?rbu_memory=1%s%s",
|
||||
sqlite3_db_filename(p->dbRbu, "main"),
|
||||
(zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
|
||||
);
|
||||
@@ -3743,6 +3743,12 @@ sqlite3rbu *sqlite3rbu_vacuum(
|
||||
const char *zState
|
||||
){
|
||||
if( zTarget==0 ){ return rbuMisuseError(); }
|
||||
if( zState ){
|
||||
int n = strlen(zState);
|
||||
if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){
|
||||
return rbuMisuseError();
|
||||
}
|
||||
}
|
||||
/* TODO: Check that both arguments are non-NULL */
|
||||
return openRbuHandle(0, zTarget, zState);
|
||||
}
|
||||
@@ -3939,7 +3945,10 @@ int sqlite3rbu_savestate(sqlite3rbu *p){
|
||||
if( p->eStage==RBU_STAGE_OAL ){
|
||||
assert( rc!=SQLITE_DONE );
|
||||
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
|
||||
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
const char *zBegin = rbuIsVacuum(p) ? "BEGIN" : "BEGIN IMMEDIATE";
|
||||
rc = sqlite3_exec(p->dbRbu, zBegin, 0, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0);
|
||||
}
|
||||
|
||||
|
||||
@@ -333,7 +333,11 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open(
|
||||
** name of the state database is "<database>-vacuum", where <database>
|
||||
** is the name of the target database file. In this case, on UNIX, if the
|
||||
** state database is not already present in the file-system, it is created
|
||||
** with the same permissions as the target db is made.
|
||||
** with the same permissions as the target db is made.
|
||||
**
|
||||
** With an RBU vacuum, it is an SQLITE_MISUSE error if the name of the
|
||||
** state database ends with "-vactmp". This name is reserved for internal
|
||||
** use.
|
||||
**
|
||||
** This function does not delete the state database after an RBU vacuum
|
||||
** is completed, even if it created it. However, if the call to
|
||||
|
||||
@@ -273,6 +273,7 @@ static int SQLITE_TCLAPI test_sqlite3rbu_vacuum(
|
||||
zCmd = Tcl_GetString(objv[1]);
|
||||
zTarget = Tcl_GetString(objv[2]);
|
||||
if( objc==4 ) zStateDb = Tcl_GetString(objv[3]);
|
||||
if( zStateDb && zStateDb[0]=='\0' ) zStateDb = 0;
|
||||
|
||||
pRbu = sqlite3rbu_vacuum(zTarget, zStateDb);
|
||||
Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0);
|
||||
|
||||
+53
-42
@@ -124,6 +124,14 @@ struct GeoPoly {
|
||||
*/
|
||||
#define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4))
|
||||
|
||||
/* Macros to access coordinates of a GeoPoly.
|
||||
** We have to use these macros, rather than just say p->a[i] in order
|
||||
** to silence (incorrect) UBSAN warnings if the array index is too large.
|
||||
*/
|
||||
#define GeoX(P,I) (((GeoCoord*)(P)->a)[(I)*2])
|
||||
#define GeoY(P,I) (((GeoCoord*)(P)->a)[(I)*2+1])
|
||||
|
||||
|
||||
/*
|
||||
** State of a parse of a GeoJSON input.
|
||||
*/
|
||||
@@ -316,8 +324,9 @@ static GeoPoly *geopolyFuncParam(
|
||||
memcpy(p->hdr, a, nByte);
|
||||
if( a[0] != *(unsigned char*)&x ){
|
||||
int ii;
|
||||
for(ii=0; ii<nVertex*2; ii++){
|
||||
geopolySwab32((unsigned char*)&p->a[ii]);
|
||||
for(ii=0; ii<nVertex; ii++){
|
||||
geopolySwab32((unsigned char*)&GeoX(p,ii));
|
||||
geopolySwab32((unsigned char*)&GeoY(p,ii));
|
||||
}
|
||||
p->hdr[0] ^= 1;
|
||||
}
|
||||
@@ -376,9 +385,9 @@ static void geopolyJsonFunc(
|
||||
int i;
|
||||
sqlite3_str_append(x, "[", 1);
|
||||
for(i=0; i<p->nVertex; i++){
|
||||
sqlite3_str_appendf(x, "[%!g,%!g],", p->a[i*2], p->a[i*2+1]);
|
||||
sqlite3_str_appendf(x, "[%!g,%!g],", GeoX(p,i), GeoY(p,i));
|
||||
}
|
||||
sqlite3_str_appendf(x, "[%!g,%!g]]", p->a[0], p->a[1]);
|
||||
sqlite3_str_appendf(x, "[%!g,%!g]]", GeoX(p,0), GeoY(p,0));
|
||||
sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
@@ -395,7 +404,9 @@ static void geopolySvgFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
|
||||
GeoPoly *p;
|
||||
if( argc<1 ) return;
|
||||
p = geopolyFuncParam(context, argv[0], 0);
|
||||
if( p ){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
sqlite3_str *x = sqlite3_str_new(db);
|
||||
@@ -403,10 +414,10 @@ static void geopolySvgFunc(
|
||||
char cSep = '\'';
|
||||
sqlite3_str_appendf(x, "<polyline points=");
|
||||
for(i=0; i<p->nVertex; i++){
|
||||
sqlite3_str_appendf(x, "%c%g,%g", cSep, p->a[i*2], p->a[i*2+1]);
|
||||
sqlite3_str_appendf(x, "%c%g,%g", cSep, GeoX(p,i), GeoY(p,i));
|
||||
cSep = ' ';
|
||||
}
|
||||
sqlite3_str_appendf(x, " %g,%g'", p->a[0], p->a[1]);
|
||||
sqlite3_str_appendf(x, " %g,%g'", GeoX(p,0), GeoY(p,0));
|
||||
for(i=1; i<argc; i++){
|
||||
const char *z = (const char*)sqlite3_value_text(argv[i]);
|
||||
if( z && z[0] ){
|
||||
@@ -451,12 +462,12 @@ static void geopolyXformFunc(
|
||||
int ii;
|
||||
if( p ){
|
||||
for(ii=0; ii<p->nVertex; ii++){
|
||||
x0 = p->a[ii*2];
|
||||
y0 = p->a[ii*2+1];
|
||||
x0 = GeoX(p,ii);
|
||||
y0 = GeoY(p,ii);
|
||||
x1 = (GeoCoord)(A*x0 + B*y0 + E);
|
||||
y1 = (GeoCoord)(C*x0 + D*y0 + F);
|
||||
p->a[ii*2] = x1;
|
||||
p->a[ii*2+1] = y1;
|
||||
GeoX(p,ii) = x1;
|
||||
GeoY(p,ii) = y1;
|
||||
}
|
||||
sqlite3_result_blob(context, p->hdr,
|
||||
4+8*p->nVertex, SQLITE_TRANSIENT);
|
||||
@@ -475,12 +486,12 @@ static double geopolyArea(GeoPoly *p){
|
||||
double rArea = 0.0;
|
||||
int ii;
|
||||
for(ii=0; ii<p->nVertex-1; ii++){
|
||||
rArea += (p->a[ii*2] - p->a[ii*2+2]) /* (x0 - x1) */
|
||||
* (p->a[ii*2+1] + p->a[ii*2+3]) /* (y0 + y1) */
|
||||
rArea += (GeoX(p,ii) - GeoX(p,ii+1)) /* (x0 - x1) */
|
||||
* (GeoY(p,ii) + GeoY(p,ii+1)) /* (y0 + y1) */
|
||||
* 0.5;
|
||||
}
|
||||
rArea += (p->a[ii*2] - p->a[0]) /* (xN - x0) */
|
||||
* (p->a[ii*2+1] + p->a[1]) /* (yN + y0) */
|
||||
rArea += (GeoX(p,ii) - GeoX(p,0)) /* (xN - x0) */
|
||||
* (GeoY(p,ii) + GeoY(p,0)) /* (yN + y0) */
|
||||
* 0.5;
|
||||
return rArea;
|
||||
}
|
||||
@@ -527,13 +538,13 @@ static void geopolyCcwFunc(
|
||||
if( p ){
|
||||
if( geopolyArea(p)<0.0 ){
|
||||
int ii, jj;
|
||||
for(ii=2, jj=p->nVertex*2 - 2; ii<jj; ii+=2, jj-=2){
|
||||
GeoCoord t = p->a[ii];
|
||||
p->a[ii] = p->a[jj];
|
||||
p->a[jj] = t;
|
||||
t = p->a[ii+1];
|
||||
p->a[ii+1] = p->a[jj+1];
|
||||
p->a[jj+1] = t;
|
||||
for(ii=1, jj=p->nVertex-1; ii<jj; ii++, jj--){
|
||||
GeoCoord t = GeoX(p,ii);
|
||||
GeoX(p,ii) = GeoX(p,jj);
|
||||
GeoX(p,jj) = t;
|
||||
t = GeoY(p,ii);
|
||||
GeoY(p,ii) = GeoY(p,jj);
|
||||
GeoY(p,jj) = t;
|
||||
}
|
||||
}
|
||||
sqlite3_result_blob(context, p->hdr,
|
||||
@@ -593,8 +604,8 @@ static void geopolyRegularFunc(
|
||||
p->hdr[3] = n&0xff;
|
||||
for(i=0; i<n; i++){
|
||||
double rAngle = 2.0*GEOPOLY_PI*i/n;
|
||||
p->a[i*2] = x - r*geopolySine(rAngle-0.5*GEOPOLY_PI);
|
||||
p->a[i*2+1] = y + r*geopolySine(rAngle);
|
||||
GeoX(p,i) = x - r*geopolySine(rAngle-0.5*GEOPOLY_PI);
|
||||
GeoY(p,i) = y + r*geopolySine(rAngle);
|
||||
}
|
||||
sqlite3_result_blob(context, p->hdr, 4+8*n, SQLITE_TRANSIENT);
|
||||
sqlite3_free(p);
|
||||
@@ -631,13 +642,13 @@ static GeoPoly *geopolyBBox(
|
||||
}
|
||||
if( p ){
|
||||
int ii;
|
||||
mnX = mxX = p->a[0];
|
||||
mnY = mxY = p->a[1];
|
||||
mnX = mxX = GeoX(p,0);
|
||||
mnY = mxY = GeoY(p,0);
|
||||
for(ii=1; ii<p->nVertex; ii++){
|
||||
double r = p->a[ii*2];
|
||||
double r = GeoX(p,ii);
|
||||
if( r<mnX ) mnX = (float)r;
|
||||
else if( r>mxX ) mxX = (float)r;
|
||||
r = p->a[ii*2+1];
|
||||
r = GeoY(p,ii);
|
||||
if( r<mnY ) mnY = (float)r;
|
||||
else if( r>mxY ) mxY = (float)r;
|
||||
}
|
||||
@@ -657,14 +668,14 @@ static GeoPoly *geopolyBBox(
|
||||
pOut->hdr[1] = 0;
|
||||
pOut->hdr[2] = 0;
|
||||
pOut->hdr[3] = 4;
|
||||
pOut->a[0] = mnX;
|
||||
pOut->a[1] = mnY;
|
||||
pOut->a[2] = mxX;
|
||||
pOut->a[3] = mnY;
|
||||
pOut->a[4] = mxX;
|
||||
pOut->a[5] = mxY;
|
||||
pOut->a[6] = mnX;
|
||||
pOut->a[7] = mxY;
|
||||
GeoX(pOut,0) = mnX;
|
||||
GeoY(pOut,0) = mnY;
|
||||
GeoX(pOut,1) = mxX;
|
||||
GeoY(pOut,1) = mnY;
|
||||
GeoX(pOut,2) = mxX;
|
||||
GeoY(pOut,2) = mxY;
|
||||
GeoX(pOut,3) = mnX;
|
||||
GeoY(pOut,3) = mxY;
|
||||
}else{
|
||||
sqlite3_free(p);
|
||||
aCoord[0].f = mnX;
|
||||
@@ -802,14 +813,14 @@ static void geopolyContainsPointFunc(
|
||||
int ii;
|
||||
if( p1==0 ) return;
|
||||
for(ii=0; ii<p1->nVertex-1; ii++){
|
||||
v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
|
||||
p1->a[ii*2+2],p1->a[ii*2+3]);
|
||||
v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii),
|
||||
GeoX(p1,ii+1),GeoY(p1,ii+1));
|
||||
if( v==2 ) break;
|
||||
cnt += v;
|
||||
}
|
||||
if( v!=2 ){
|
||||
v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
|
||||
p1->a[0],p1->a[1]);
|
||||
v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii),
|
||||
GeoX(p1,0), GeoY(p1,0));
|
||||
}
|
||||
if( v==2 ){
|
||||
sqlite3_result_int(context, 1);
|
||||
@@ -931,10 +942,10 @@ static void geopolyAddSegments(
|
||||
unsigned int i;
|
||||
GeoCoord *x;
|
||||
for(i=0; i<(unsigned)pPoly->nVertex-1; i++){
|
||||
x = pPoly->a + (i*2);
|
||||
x = &GeoX(pPoly,i);
|
||||
geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i);
|
||||
}
|
||||
x = pPoly->a + (i*2);
|
||||
x = &GeoX(pPoly,i);
|
||||
geopolyAddOneSegment(p, x[0], x[1], pPoly->a[0], pPoly->a[1], side, i);
|
||||
}
|
||||
|
||||
|
||||
+89
-46
@@ -128,6 +128,9 @@ struct Rtree {
|
||||
u8 inWrTrans; /* True if inside write transaction */
|
||||
u8 nAux; /* # of auxiliary columns in %_rowid */
|
||||
u8 nAuxNotNull; /* Number of initial not-null aux columns */
|
||||
#ifdef SQLITE_DEBUG
|
||||
u8 bCorrupt; /* Shadow table corruption detected */
|
||||
#endif
|
||||
int iDepth; /* Current depth of the r-tree structure */
|
||||
char *zDb; /* Name of database containing r-tree table */
|
||||
char *zName; /* Name of r-tree table */
|
||||
@@ -187,6 +190,15 @@ struct Rtree {
|
||||
# define RTREE_ZERO 0.0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Set the Rtree.bCorrupt flag
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
# define RTREE_IS_CORRUPT(X) ((X)->bCorrupt = 1)
|
||||
#else
|
||||
# define RTREE_IS_CORRUPT(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** When doing a search of an r-tree, instances of the following structure
|
||||
** record intermediate results from the tree walk.
|
||||
@@ -553,8 +565,8 @@ static void nodeZero(Rtree *pRtree, RtreeNode *p){
|
||||
** Given a node number iNode, return the corresponding key to use
|
||||
** in the Rtree.aHash table.
|
||||
*/
|
||||
static int nodeHash(i64 iNode){
|
||||
return iNode % HASHSIZE;
|
||||
static unsigned int nodeHash(i64 iNode){
|
||||
return ((unsigned)iNode) % HASHSIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -599,7 +611,7 @@ static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){
|
||||
*/
|
||||
static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
|
||||
RtreeNode *pNode;
|
||||
pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize);
|
||||
pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode) + pRtree->iNodeSize);
|
||||
if( pNode ){
|
||||
memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize);
|
||||
pNode->zData = (u8 *)&pNode[1];
|
||||
@@ -623,6 +635,18 @@ static void nodeBlobReset(Rtree *pRtree){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if pNode is the same as pParent or any of the parents
|
||||
** of pParent.
|
||||
*/
|
||||
static int nodeInParentChain(const RtreeNode *pNode, const RtreeNode *pParent){
|
||||
do{
|
||||
if( pNode==pParent ) return 1;
|
||||
pParent = pParent->pParent;
|
||||
}while( pParent );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Obtain a reference to an r-tree node.
|
||||
*/
|
||||
@@ -641,6 +665,10 @@ static int nodeAcquire(
|
||||
if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
|
||||
assert( !pParent || !pNode->pParent || pNode->pParent==pParent );
|
||||
if( pParent && !pNode->pParent ){
|
||||
if( nodeInParentChain(pNode, pParent) ){
|
||||
RTREE_IS_CORRUPT(pRtree);
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
pParent->nRef++;
|
||||
pNode->pParent = pParent;
|
||||
}
|
||||
@@ -671,9 +699,12 @@ static int nodeAcquire(
|
||||
*ppNode = 0;
|
||||
/* If unable to open an sqlite3_blob on the desired row, that can only
|
||||
** be because the shadow tables hold erroneous data. */
|
||||
if( rc==SQLITE_ERROR ) rc = SQLITE_CORRUPT_VTAB;
|
||||
if( rc==SQLITE_ERROR ){
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
RTREE_IS_CORRUPT(pRtree);
|
||||
}
|
||||
}else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){
|
||||
pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
|
||||
pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode)+pRtree->iNodeSize);
|
||||
if( !pNode ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -686,7 +717,6 @@ static int nodeAcquire(
|
||||
pNode->pNext = 0;
|
||||
rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData,
|
||||
pRtree->iNodeSize, 0);
|
||||
nodeReference(pParent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,6 +730,7 @@ static int nodeAcquire(
|
||||
pRtree->iDepth = readInt16(pNode->zData);
|
||||
if( pRtree->iDepth>RTREE_MAX_DEPTH ){
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
RTREE_IS_CORRUPT(pRtree);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -710,14 +741,17 @@ static int nodeAcquire(
|
||||
if( pNode && rc==SQLITE_OK ){
|
||||
if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
RTREE_IS_CORRUPT(pRtree);
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pNode!=0 ){
|
||||
nodeReference(pParent);
|
||||
nodeHashInsert(pRtree, pNode);
|
||||
}else{
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
RTREE_IS_CORRUPT(pRtree);
|
||||
}
|
||||
*ppNode = pNode;
|
||||
}else{
|
||||
@@ -943,7 +977,7 @@ static void rtreeRelease(Rtree *pRtree){
|
||||
pRtree->inWrTrans = 0;
|
||||
assert( pRtree->nCursor==0 );
|
||||
nodeBlobReset(pRtree);
|
||||
assert( pRtree->nNodeRef==0 );
|
||||
assert( pRtree->nNodeRef==0 || pRtree->bCorrupt );
|
||||
sqlite3_finalize(pRtree->pWriteNode);
|
||||
sqlite3_finalize(pRtree->pDeleteNode);
|
||||
sqlite3_finalize(pRtree->pReadRowid);
|
||||
@@ -1002,7 +1036,7 @@ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
Rtree *pRtree = (Rtree *)pVTab;
|
||||
RtreeCursor *pCsr;
|
||||
|
||||
pCsr = (RtreeCursor *)sqlite3_malloc(sizeof(RtreeCursor));
|
||||
pCsr = (RtreeCursor *)sqlite3_malloc64(sizeof(RtreeCursor));
|
||||
if( pCsr ){
|
||||
memset(pCsr, 0, sizeof(RtreeCursor));
|
||||
pCsr->base.pVtab = pVTab;
|
||||
@@ -1275,6 +1309,7 @@ static int nodeRowidIndex(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
RTREE_IS_CORRUPT(pRtree);
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
@@ -1368,7 +1403,7 @@ static RtreeSearchPoint *rtreeEnqueue(
|
||||
RtreeSearchPoint *pNew;
|
||||
if( pCur->nPoint>=pCur->nPointAlloc ){
|
||||
int nNew = pCur->nPointAlloc*2 + 8;
|
||||
pNew = sqlite3_realloc(pCur->aPoint, nNew*sizeof(pCur->aPoint[0]));
|
||||
pNew = sqlite3_realloc64(pCur->aPoint, nNew*sizeof(pCur->aPoint[0]));
|
||||
if( pNew==0 ) return 0;
|
||||
pCur->aPoint = pNew;
|
||||
pCur->nPointAlloc = nNew;
|
||||
@@ -1770,7 +1805,7 @@ static int rtreeFilter(
|
||||
*/
|
||||
rc = nodeAcquire(pRtree, 1, 0, &pRoot);
|
||||
if( rc==SQLITE_OK && argc>0 ){
|
||||
pCsr->aConstraint = sqlite3_malloc(sizeof(RtreeConstraint)*argc);
|
||||
pCsr->aConstraint = sqlite3_malloc64(sizeof(RtreeConstraint)*argc);
|
||||
pCsr->nConstraint = argc;
|
||||
if( !pCsr->aConstraint ){
|
||||
rc = SQLITE_NOMEM;
|
||||
@@ -1915,20 +1950,20 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
){
|
||||
u8 op;
|
||||
switch( p->op ){
|
||||
case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break;
|
||||
default:
|
||||
assert( p->op==SQLITE_INDEX_CONSTRAINT_MATCH );
|
||||
op = RTREE_MATCH;
|
||||
break;
|
||||
case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_MATCH: op = RTREE_MATCH; break;
|
||||
default: op = 0; break;
|
||||
}
|
||||
if( op ){
|
||||
zIdxStr[iIdx++] = op;
|
||||
zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0');
|
||||
pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
|
||||
pIdxInfo->aConstraintUsage[ii].omit = 1;
|
||||
}
|
||||
zIdxStr[iIdx++] = op;
|
||||
zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0');
|
||||
pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
|
||||
pIdxInfo->aConstraintUsage[ii].omit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1964,11 +1999,11 @@ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
|
||||
#endif
|
||||
{
|
||||
switch( pRtree->nDim ){
|
||||
case 5: area = p->aCoord[9].i - p->aCoord[8].i;
|
||||
case 4: area *= p->aCoord[7].i - p->aCoord[6].i;
|
||||
case 3: area *= p->aCoord[5].i - p->aCoord[4].i;
|
||||
case 2: area *= p->aCoord[3].i - p->aCoord[2].i;
|
||||
default: area *= p->aCoord[1].i - p->aCoord[0].i;
|
||||
case 5: area = (i64)p->aCoord[9].i - (i64)p->aCoord[8].i;
|
||||
case 4: area *= (i64)p->aCoord[7].i - (i64)p->aCoord[6].i;
|
||||
case 3: area *= (i64)p->aCoord[5].i - (i64)p->aCoord[4].i;
|
||||
case 2: area *= (i64)p->aCoord[3].i - (i64)p->aCoord[2].i;
|
||||
default: area *= (i64)p->aCoord[1].i - (i64)p->aCoord[0].i;
|
||||
}
|
||||
}
|
||||
return area;
|
||||
@@ -2137,12 +2172,14 @@ static int AdjustTree(
|
||||
RtreeCell *pCell /* This cell was just inserted */
|
||||
){
|
||||
RtreeNode *p = pNode;
|
||||
int cnt = 0;
|
||||
while( p->pParent ){
|
||||
RtreeNode *pParent = p->pParent;
|
||||
RtreeCell cell;
|
||||
int iCell;
|
||||
|
||||
if( nodeParentIndex(pRtree, p, &iCell) ){
|
||||
if( (++cnt)>1000 || nodeParentIndex(pRtree, p, &iCell) ){
|
||||
RTREE_IS_CORRUPT(pRtree);
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
@@ -2339,9 +2376,9 @@ static int splitNodeStartree(
|
||||
int iBestSplit = 0;
|
||||
RtreeDValue fBestMargin = RTREE_ZERO;
|
||||
|
||||
int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
|
||||
sqlite3_int64 nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
|
||||
|
||||
aaSorted = (int **)sqlite3_malloc(nByte);
|
||||
aaSorted = (int **)sqlite3_malloc64(nByte);
|
||||
if( !aaSorted ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -2462,7 +2499,7 @@ static int SplitNode(
|
||||
/* Allocate an array and populate it with a copy of pCell and
|
||||
** all cells from node pLeft. Then zero the original node.
|
||||
*/
|
||||
aCell = sqlite3_malloc((sizeof(RtreeCell)+sizeof(int))*(nCell+1));
|
||||
aCell = sqlite3_malloc64((sizeof(RtreeCell)+sizeof(int))*(nCell+1));
|
||||
if( !aCell ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto splitnode_out;
|
||||
@@ -2610,7 +2647,10 @@ static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){
|
||||
}
|
||||
rc = sqlite3_reset(pRtree->pReadParent);
|
||||
if( rc==SQLITE_OK ) rc = rc2;
|
||||
if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT_VTAB;
|
||||
if( rc==SQLITE_OK && !pChild->pParent ){
|
||||
RTREE_IS_CORRUPT(pRtree);
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
pChild = pChild->pParent;
|
||||
}
|
||||
return rc;
|
||||
@@ -2750,7 +2790,7 @@ static int Reinsert(
|
||||
/* Allocate the buffers used by this operation. The allocation is
|
||||
** relinquished before this function returns.
|
||||
*/
|
||||
aCell = (RtreeCell *)sqlite3_malloc(n * (
|
||||
aCell = (RtreeCell *)sqlite3_malloc64(n * (
|
||||
sizeof(RtreeCell) + /* aCell array */
|
||||
sizeof(int) + /* aOrder array */
|
||||
sizeof(int) + /* aSpare array */
|
||||
@@ -2924,8 +2964,12 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
|
||||
rc = findLeafNode(pRtree, iDelete, &pLeaf, 0);
|
||||
}
|
||||
|
||||
#ifdef CORRUPT_DB
|
||||
assert( pLeaf!=0 || rc!=SQLITE_OK || CORRUPT_DB );
|
||||
#endif
|
||||
|
||||
/* Delete the cell in question from the leaf node. */
|
||||
if( rc==SQLITE_OK ){
|
||||
if( rc==SQLITE_OK && pLeaf ){
|
||||
int rc2;
|
||||
rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -3197,7 +3241,7 @@ static int rtreeUpdate(
|
||||
rc = rc2;
|
||||
}
|
||||
}
|
||||
if( pRtree->nAux ){
|
||||
if( rc==SQLITE_OK && pRtree->nAux ){
|
||||
sqlite3_stmt *pUp = pRtree->pWriteAux;
|
||||
int jj;
|
||||
sqlite3_bind_int64(pUp, 1, *pRowid);
|
||||
@@ -3395,6 +3439,7 @@ static int rtreeSqlInit(
|
||||
};
|
||||
sqlite3_stmt **appStmt[N_STATEMENT];
|
||||
int i;
|
||||
const int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB;
|
||||
|
||||
pRtree->db = db;
|
||||
|
||||
@@ -3451,8 +3496,7 @@ static int rtreeSqlInit(
|
||||
}
|
||||
zSql = sqlite3_mprintf(zFormat, zDb, zPrefix);
|
||||
if( zSql ){
|
||||
rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
|
||||
appStmt[i], 0);
|
||||
rc = sqlite3_prepare_v3(db, zSql, -1, f, appStmt[i], 0);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -3482,8 +3526,7 @@ static int rtreeSqlInit(
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
|
||||
&pRtree->pWriteAux, 0);
|
||||
rc = sqlite3_prepare_v3(db, zSql, -1, f, &pRtree->pWriteAux, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
}
|
||||
@@ -3559,6 +3602,7 @@ static int getNodeSize(
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
|
||||
}else if( pRtree->iNodeSize<(512-64) ){
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
RTREE_IS_CORRUPT(pRtree);
|
||||
*pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"",
|
||||
pRtree->zName);
|
||||
}
|
||||
@@ -3614,7 +3658,7 @@ static int rtreeInit(
|
||||
/* Allocate the sqlite3_vtab structure */
|
||||
nDb = (int)strlen(argv[1]);
|
||||
nName = (int)strlen(argv[2]);
|
||||
pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2);
|
||||
pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
|
||||
if( !pRtree ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -3882,8 +3926,7 @@ static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){
|
||||
static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){
|
||||
u8 *pRet = 0; /* Return value */
|
||||
|
||||
assert( pCheck->rc==SQLITE_OK );
|
||||
if( pCheck->pGetNode==0 ){
|
||||
if( pCheck->rc==SQLITE_OK && pCheck->pGetNode==0 ){
|
||||
pCheck->pGetNode = rtreeCheckPrepare(pCheck,
|
||||
"SELECT data FROM %Q.'%q_node' WHERE nodeno=?",
|
||||
pCheck->zDb, pCheck->zTab
|
||||
@@ -3895,7 +3938,7 @@ static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){
|
||||
if( sqlite3_step(pCheck->pGetNode)==SQLITE_ROW ){
|
||||
int nNode = sqlite3_column_bytes(pCheck->pGetNode, 0);
|
||||
const u8 *pNode = (const u8*)sqlite3_column_blob(pCheck->pGetNode, 0);
|
||||
pRet = sqlite3_malloc(nNode);
|
||||
pRet = sqlite3_malloc64(nNode);
|
||||
if( pRet==0 ){
|
||||
pCheck->rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -4328,12 +4371,12 @@ static void rtreeMatchArgFree(void *pArg){
|
||||
static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
|
||||
RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx);
|
||||
RtreeMatchArg *pBlob;
|
||||
int nBlob;
|
||||
sqlite3_int64 nBlob;
|
||||
int memErr = 0;
|
||||
|
||||
nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue)
|
||||
+ nArg*sizeof(sqlite3_value*);
|
||||
pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob);
|
||||
pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob);
|
||||
if( !pBlob ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
}else{
|
||||
|
||||
@@ -647,5 +647,19 @@ do_execsql_test 16.130 {
|
||||
SELECT * FROM rt1 WHERE id IN (1, 2, 3, 4);
|
||||
} {1 1.0 2.0 aux1 2 2.0 3.0 aux2 3 3.0 4.0 aux3 4 4.0 5.0 aux4}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 17.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(id, x1 PRIMARY KEY, x2, y1, y2);
|
||||
CREATE VIRTUAL TABLE t2 USING rtree(id, x1, x2, y1, y2 UNIQUE);
|
||||
}
|
||||
do_execsql_test 17.1 {
|
||||
REINDEX t1;
|
||||
REINDEX t2;
|
||||
} {}
|
||||
|
||||
do_execsql_test 17.2 {
|
||||
REINDEX;
|
||||
} {}
|
||||
|
||||
expand_all_sql db
|
||||
finish_test
|
||||
|
||||
@@ -15,6 +15,7 @@ if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
set testprefix rtree6
|
||||
|
||||
ifcapable {!rtree || rtree_int_only} {
|
||||
finish_test
|
||||
@@ -58,6 +59,9 @@ do_test rtree6-1.1 {
|
||||
do_test rtree6-1.2 {
|
||||
rtree_strategy {SELECT * FROM t1 WHERE x1>10}
|
||||
} {E0}
|
||||
do_test rtree6-1.2.1 {
|
||||
rtree_strategy {SELECT * FROM t1 WHERE x1>10 AND x2 LIKE '%x%'}
|
||||
} {E0}
|
||||
|
||||
do_test rtree6-1.3 {
|
||||
rtree_strategy {SELECT * FROM t1 WHERE x1<10}
|
||||
@@ -164,5 +168,14 @@ do_execsql_test rtree6-3.5 {
|
||||
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>1.1
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(id,x0,x1,y0,y1);
|
||||
}
|
||||
do_execsql_test 4.1 {
|
||||
DELETE FROM t1 WHERE x0>1 AND x1<2 OR y0<92;
|
||||
}
|
||||
|
||||
expand_all_sql db
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# 2018 Dec 22
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source [file join [file dirname [info script]] rtree_util.tcl]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix rtreecirc
|
||||
|
||||
ifcapable !rtree {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2, y1, y2);
|
||||
SELECT name FROM sqlite_master ORDER BY 1;
|
||||
} {
|
||||
rt rt_node rt_parent rt_rowid
|
||||
}
|
||||
db_save_and_close
|
||||
|
||||
foreach {tn schema sql} {
|
||||
1 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON rt_node BEGIN
|
||||
SELECT * FROM rt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO rt VALUES(1, 2, 3, 4, 5);
|
||||
}
|
||||
2 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON rt_parent BEGIN
|
||||
SELECT * FROM rt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO rt VALUES(1, 2, 3, 4, 5);
|
||||
}
|
||||
3 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON rt_rowid BEGIN
|
||||
SELECT * FROM rt;
|
||||
END;
|
||||
} {
|
||||
INSERT INTO rt VALUES(1, 2, 3, 4, 5);
|
||||
}
|
||||
} {
|
||||
db_restore_and_reopen
|
||||
do_execsql_test 1.1.$tn.1 $schema
|
||||
do_catchsql_test 1.1.$tn.2 $sql {1 {no such table: main.rt}}
|
||||
db close
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,777 @@
|
||||
# 2012-12-21
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for corrupt database files.
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !deserialize||!rtree {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
database_may_be_corrupt
|
||||
|
||||
do_test rtreefuzz001-100 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
| size 24576 pagesize 4096 filename c1b.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 03 00 00 00 06 .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 04 ................
|
||||
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
|
||||
| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................
|
||||
| 96: 00 2e 30 38 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f ..08...........O
|
||||
| 112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17 ............^...
|
||||
| 3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72 .....tablet1_par
|
||||
| 3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45 entt1_parent.CRE
|
||||
| 3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61 ATE TABLE .t1_pa
|
||||
| 3792: 72 66 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 rfnt.(nodeno INT
|
||||
| 3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
|
||||
| 3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17 ,parentnode)Q...
|
||||
| 3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65 ....tablet1_node
|
||||
| 3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54 t1_node.CREATE T
|
||||
| 3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e ABLE .t1_node.(n
|
||||
| 3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52 odeno INTEGER PR
|
||||
| 3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c IMARY KEY,data).
|
||||
| 3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f ........tablet1_
|
||||
| 3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52 rowidt1_rowid.CR
|
||||
| 3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72 EATE TABLE .t1_r
|
||||
| 3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE
|
||||
| 3984: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY,
|
||||
| 4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07 nodeno,a0,a1)Q..
|
||||
| 4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43 ......tablet1t1C
|
||||
| 4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA
|
||||
| 4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 BLE t1 USING rtr
|
||||
| 4064: 65 65 28 69 64 2c 78 30 2c 78 31 2c 79 30 2c 79 ee(id,x0,x1,y0,y
|
||||
| 4080: 31 2c 2b 6c 61 62 65 6c 2c 2b 6f 74 68 65 72 29 1,+label,+other)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 0c cd 00 74 08 75 01 0f e8 0c b3 0f d0 0f b7 ....t.u.........
|
||||
| 16: 0f 9e 0f 91 0f 81 0f 70 0f 5e 0f 4f 0f 39 0f 29 .......p.^.O.9.)
|
||||
| 32: 0f 18 0f 06 0e f7 0c 65 0e 58 0d c2 0d 2c 0c 25 .......e.X...,.%
|
||||
| 48: 0b 85 0a e5 0a 45 09 a5 09 05 0c 83 0c 93 0c a3 .....E..........
|
||||
| 64: 0f f0 0c 15 0b 75 0a d5 0a 35 09 95 08 f5 0e d8 .....u...5......
|
||||
| 80: 0e 42 0d ac 0d 16 0c 05 0b 65 0a c5 0a 25 09 85 .B.......e...%..
|
||||
| 96: 08 e5 0e c8 0e 32 0d 9c 0d 06 0b f5 0b 55 0a b5 .....2.......U..
|
||||
| 112: 0a 15 09 75 08 d5 0e b8 0e 22 0d 8c 0c f6 0b e5 ...u............
|
||||
| 128: 0b 45 0a a5 0a 05 09 65 08 c5 0e a8 0e 12 0d 7c .E.....e.......|
|
||||
| 144: 0c e6 0b d5 0b 35 0a 95 09 f5 09 55 08 b5 0e 98 .....5.....U....
|
||||
| 160: 0e 02 0d 6c 0c d6 0b c5 0b 25 0a 85 09 e5 09 45 ...l.....%.....E
|
||||
| 176: 08 a5 0e 88 0d f2 0d 5c 0c 55 0b b5 0b 15 0a 75 .........U.....u
|
||||
| 192: 09 d5 09 35 08 95 0e 78 0d e2 0d 4c 0c 45 0b a5 ...5...x...L.E..
|
||||
| 208: 0b 05 0a 65 09 c5 09 25 08 85 0e 68 0d d2 0d 3c ...e...%...h...<
|
||||
| 224: 0c 35 0b 95 0a f5 0a 55 09 b5 09 15 08 75 0c 75 .5.....U.....u.u
|
||||
| 2160: 00 00 00 00 00 0d 8e 75 05 00 01 1b 00 04 62 6f .......u......bo
|
||||
| 2176: 78 2d 39 2c 39 0d 8e 11 05 00 01 1b 00 02 62 6f x-9,9.........bo
|
||||
| 2192: 78 2d 39 2c 38 0d 8d 2d 05 00 01 1b 00 02 62 6f x-9,8..-......bo
|
||||
| 2208: 78 2d 39 2c 37 0d 8c 49 05 00 01 1b 00 02 62 6f x-9,7..I......bo
|
||||
| 2224: 78 2d 39 2c 36 0d 8b 65 05 00 01 1b 00 02 62 6f x-9,6..e......bo
|
||||
| 2240: 78 2d 39 2c 35 0d 8b 01 05 00 01 1b 00 02 62 6f x-9,5.........bo
|
||||
| 2256: 78 2d 39 2c 34 0d 8a 1d 05 00 01 1b 00 02 62 6f x-9,4.........bo
|
||||
| 2272: 78 2d 39 2c 33 0d 89 39 05 00 01 1b 00 02 62 6f x-9,3..9......bo
|
||||
| 2288: 78 2d 39 2c 32 0d 88 55 05 00 01 1b 00 02 62 6f x-9,2..U......bo
|
||||
| 2304: 78 2d 39 2c 31 0d 87 71 05 00 01 1b 00 02 62 6f x-9,1..q......bo
|
||||
| 2320: 78 2d 39 2c 30 0d 8e 74 05 00 01 1b 00 04 62 6f x-9,0..t......bo
|
||||
| 2336: 78 2d 38 2c 39 0d 8e 10 05 00 01 1b 00 02 62 6f x-8,9.........bo
|
||||
| 2352: 78 2d 38 2c 38 0d 8d 2c 05 00 01 1b 00 02 62 6f x-8,8..,......bo
|
||||
| 2368: 78 2d 38 2c 37 0d 8c 48 05 00 01 1b 00 02 62 6f x-8,7..H......bo
|
||||
| 2384: 78 2d 38 2c 36 0d 8b 64 05 00 01 1b 00 02 62 6f x-8,6..d......bo
|
||||
| 2400: 78 2d 38 2c 35 0d 8b 00 05 00 01 1b 00 02 62 6f x-8,5.........bo
|
||||
| 2416: 78 2d 38 2c 34 0d 8a 1c 05 00 01 1b 00 02 62 6f x-8,4.........bo
|
||||
| 2432: 78 2d 38 2c 33 0d 89 38 05 00 01 1b 00 02 62 6f x-8,3..8......bo
|
||||
| 2448: 78 2d 38 2c 32 0d 88 54 05 00 01 1b 00 02 62 6f x-8,2..T......bo
|
||||
| 2464: 78 2d 38 2c 31 0d 87 70 05 00 01 1b 00 02 62 6f x-8,1..p......bo
|
||||
| 2480: 78 2d 38 2c 30 0d 8e 73 05 00 01 1b 00 05 62 6f x-8,0..s......bo
|
||||
| 2496: 78 2d 37 2c 39 0d 8e 0f 05 00 01 1b 00 05 62 6f x-7,9.........bo
|
||||
| 2512: 78 2d 37 2c 38 0d 8d 2b 05 00 01 1b 00 05 62 6f x-7,8..+......bo
|
||||
| 2528: 78 2d 37 2c 37 0d 8c 47 05 00 01 1b 00 05 62 6f x-7,7..G......bo
|
||||
| 2544: 78 2d 37 2c 36 0d 8b 63 05 00 01 1b 00 05 62 6f x-7,6..c......bo
|
||||
| 2560: 78 2d 37 2c 35 0d 8a 7f 05 00 01 1b 00 05 62 6f x-7,5.........bo
|
||||
| 2576: 78 2d 37 2c 34 0d 8a 1b 05 00 01 1b 00 05 62 6f x-7,4.........bo
|
||||
| 2592: 78 2d 37 2c 33 0d 89 37 05 00 01 1b 00 05 62 6f x-7,3..7......bo
|
||||
| 2608: 78 2d 37 2c 32 0d 88 53 05 00 01 1b 00 05 62 6f x-7,2..S......bo
|
||||
| 2624: 78 2d 37 2c 31 0d 87 6f 05 00 01 1b 00 05 62 6f x-7,1..o......bo
|
||||
| 2640: 78 2d 37 2c 30 0d 8e 72 05 00 01 1b 00 04 62 6f x-7,0..r......bo
|
||||
| 2656: 78 2d 36 2c 39 0d 8e 0e 05 00 01 1b 00 05 62 6f x-6,9.........bo
|
||||
| 2672: 78 2d 36 2c 38 0d 8d 2a 05 00 01 1b 00 05 62 6f x-6,8..*......bo
|
||||
| 2688: 78 2d 36 2c 37 0d 8c 46 05 00 01 1b 00 05 62 6f x-6,7..F......bo
|
||||
| 2704: 78 2d 36 2c 36 0d 8b 62 05 00 01 1b 00 05 62 6f x-6,6..b......bo
|
||||
| 2720: 78 2d 36 2c 35 0d 8a 7e 05 00 01 1b 00 05 62 6f x-6,5..~......bo
|
||||
| 2736: 78 2d 36 2c 34 0d 8a 1a 05 00 01 1b 00 05 62 6f x-6,4.........bo
|
||||
| 2752: 78 2d 36 2c 33 0d 89 36 05 00 01 1b 00 05 62 6f x-6,3..6......bo
|
||||
| 2768: 78 2d 36 2c 32 0d 88 52 05 00 01 1b 00 05 62 6f x-6,2..R......bo
|
||||
| 2784: 78 2d 36 2c 31 0d 87 6e 05 00 01 1b 00 05 62 6f x-6,1..n......bo
|
||||
| 2800: 78 2d 36 2c 30 0d 8e 71 05 00 01 1b 00 04 62 6f x-6,0..q......bo
|
||||
| 2816: 78 2d 35 2c 39 0d 8e 0d 05 00 01 1b 00 05 62 6f x-5,9.........bo
|
||||
| 2832: 78 2d 35 2c 38 0d 8d 29 05 00 01 1b 00 05 62 6f x-5,8..)......bo
|
||||
| 2848: 78 2d 35 2c 37 0d 8c 45 05 00 01 1b 00 05 62 6f x-5,7..E......bo
|
||||
| 2864: 78 2d 35 2c 36 0d 8b 61 05 00 01 1b 00 05 62 6f x-5,6..a......bo
|
||||
| 2880: 78 2d 35 2c 35 0d 8a 7d 05 00 01 1b 00 05 62 6f x-5,5.........bo
|
||||
| 2896: 78 2d 35 2c 34 0d 8a 19 05 00 01 1b 00 05 62 6f x-5,4.........bo
|
||||
| 2912: 78 2d 35 2c 33 0d 89 35 05 00 01 1b 00 05 62 6f x-5,3..5......bo
|
||||
| 2928: 78 2d 35 2c 32 0d 88 51 05 00 01 1b 00 05 62 6f x-5,2..Q......bo
|
||||
| 2944: 78 2d 35 2c 31 0d 87 6d 05 00 01 1b 00 05 62 6f x-5,1..m......bo
|
||||
| 2960: 78 2d 35 2c 30 0d 8e 70 05 00 01 1b 00 04 62 6f x-5,0..p......bo
|
||||
| 2976: 78 2d 34 2c 39 0d 8e 0c 05 00 01 1b 00 04 62 6f x-4,9.........bo
|
||||
| 2992: 78 2d 34 2c 38 0d 8d 28 05 00 01 1b 00 04 62 6f x-4,8..(......bo
|
||||
| 3008: 78 2d 34 2c 37 0d 8c 44 05 00 01 1b 00 04 62 6f x-4,7..D......bo
|
||||
| 3024: 78 2d 34 2c 36 0d 8b 60 05 00 01 1b 00 02 62 6f x-4,6..`......bo
|
||||
| 3040: 78 2d 34 2c 35 0d 8a 7c 05 00 01 1b 00 02 62 6f x-4,5..|......bo
|
||||
| 3056: 78 2d 34 2c 34 0d 8a 18 05 00 01 1b 00 02 62 6f x-4,4.........bo
|
||||
| 3072: 78 2d 34 2c 33 0d 89 34 05 00 01 1b 00 02 62 6f x-4,3..4......bo
|
||||
| 3088: 78 2d 34 2c 32 0d 88 50 05 00 01 1b 00 02 62 6f x-4,2..P......bo
|
||||
| 3104: 78 2d 34 2c 31 0d 87 6c 05 00 01 1b 00 02 62 6f x-4,1..l......bo
|
||||
| 3120: 78 2d 34 2c 30 0d 8e 6f 05 00 01 1b 00 04 62 6f x-4,0..o......bo
|
||||
| 3136: 78 2d 33 2c 39 0d 8e 0b 05 00 01 1b 00 04 62 6f x-3,9.........bo
|
||||
| 3152: 78 2d 33 2c 38 0d 8d 27 05 00 01 1b 00 04 62 6f x-3,8..'......bo
|
||||
| 3168: 78 2d 33 2c 37 0d 87 68 05 00 01 1b 00 03 62 6f x-3,7..h......bo
|
||||
| 3184: 78 2d 30 2c 30 06 90 d9 80 80 81 84 4c 05 00 01 x-0,0.......L...
|
||||
| 3200: 00 00 03 0d 88 4c 05 00 01 1b 00 02 62 6f 78 2d .....L......box-
|
||||
| 3216: 30 2c 31 0d 88 4d 05 00 01 1b 00 02 62 6f 78 2d 0,1..M......box-
|
||||
| 3232: 31 2c 31 0d 88 4e 05 00 01 1b 00 02 62 6f 78 2d 1,1..N......box-
|
||||
| 3248: 32 2c 31 17 01 05 00 01 2f 00 02 6c 6f 77 65 72 2,1...../..lower
|
||||
| 3264: 2d 6c 65 66 74 20 63 6f 72 6e 65 72 0d 0d 26 00 -left corner..&.
|
||||
| 3280: 09 00 01 00 00 04 0d 8c 43 05 00 01 1b 00 04 62 ........C......b
|
||||
| 3296: 6f 78 2d 33 2c 36 0d 8b 5f 05 00 01 1b 00 02 62 ox-3,6.._......b
|
||||
| 3312: 6f 78 2d 33 2c 35 0d 8a 7b 05 00 01 1b 00 02 62 ox-3,5.........b
|
||||
| 3328: 6f 78 2d 33 2c 34 0d 8a 17 05 00 01 1b 00 02 62 ox-3,4.........b
|
||||
| 3344: 6f 78 2d 33 2c 33 0d 89 33 05 00 01 1b 00 02 62 ox-3,3..3......b
|
||||
| 3360: 6f 78 2d 33 2c 32 0d bc 00 06 00 09 0d 87 6b 05 ox-3,2........k.
|
||||
| 3376: 00 01 1b 00 03 62 6f 78 2d 33 2c 30 0d 8e 6e 05 .....box-3,0..n.
|
||||
| 3392: 00 01 1b 00 04 62 6f 78 2d 32 2c 39 0d 8e 0a 05 .....box-2,9....
|
||||
| 3408: 00 01 1b 00 04 62 6f 78 2d 32 2c 38 0d 8d 26 05 .....box-2,8..&.
|
||||
| 3424: 00 01 1b 00 04 62 6f 78 2d 32 2c 37 0d 8c 42 05 .....box-2,7..B.
|
||||
| 3440: 00 01 1b 00 04 62 6f 78 2d 32 2c 36 0d 8b 5e 05 .....box-2,6..^.
|
||||
| 3456: 00 01 1b 00 02 62 6f 78 2d 32 2c 35 0d 8a 7a 05 .....box-2,5..z.
|
||||
| 3472: 00 01 1b 00 02 62 6f 78 2d 32 2c 34 0d 8a 16 05 .....box-2,4....
|
||||
| 3488: 00 01 1b 00 02 62 6f 78 2d 32 2c 33 0d 89 32 05 .....box-2,3..2.
|
||||
| 3504: 00 01 1b 00 02 62 6f 78 2d 32 2c 32 0e 52 00 06 .....box-2,2.R..
|
||||
| 3520: 00 09 0d 87 6a 05 00 01 1b 00 03 62 6f 78 2d 32 ....j......box-2
|
||||
| 3536: 2c 30 0d 8e 6d 05 00 01 1b 00 04 62 6f 78 2d 31 ,0..m......box-1
|
||||
| 3552: 2c 39 0d 8e 09 05 00 01 1b 00 04 62 6f 78 2d 31 ,9.........box-1
|
||||
| 3568: 2c 38 0d 8d 25 05 00 01 1b 00 04 62 6f 78 2d 31 ,8..%......box-1
|
||||
| 3584: 2c 37 0d 8c 41 05 00 01 1b 00 04 62 6f 78 2d 31 ,7..A......box-1
|
||||
| 3600: 2c 36 0d 8b 5d 05 00 01 1b 00 02 62 6f 78 2d 31 ,6..]......box-1
|
||||
| 3616: 2c 35 0d 8a 79 05 00 01 1b 00 02 62 6f 78 2d 31 ,5..y......box-1
|
||||
| 3632: 2c 34 0d 8a 15 05 00 01 1b 00 02 62 6f 78 2d 31 ,4.........box-1
|
||||
| 3648: 2c 33 0d 89 31 05 00 01 1b 00 02 62 6f 78 2d 31 ,3..1......box-1
|
||||
| 3664: 2c 32 0e e8 00 06 00 09 0d 87 69 05 00 01 1b 00 ,2........i.....
|
||||
| 3680: 03 62 6f 78 2d 31 2c 30 0d 8e 6c 05 00 01 1b 00 .box-1,0..l.....
|
||||
| 3696: 04 62 6f 78 2d 30 2c 39 0d 8e 08 05 00 01 1b 00 .box-0,9........
|
||||
| 3712: 04 62 6f 78 2d 30 2c 38 0d 8d 24 05 00 01 1b 00 .box-0,8..$.....
|
||||
| 3728: 04 62 6f 78 2d 30 2c 37 0d 8c 40 05 00 01 1b 00 .box-0,7..@.....
|
||||
| 3744: 04 62 6f 78 2d 30 2c 36 0d 8b 5c 05 00 01 1b 00 .box-0,6........
|
||||
| 3760: 02 62 6f 78 2d 30 2c 35 0d 8a 78 05 00 01 1b 00 .box-0,5..x.....
|
||||
| 3776: 02 62 6f 78 2d 30 2c 34 0d 8a 14 05 00 01 1b 00 .box-0,4........
|
||||
| 3792: 02 62 6f 78 2d 30 2c 33 0d 89 30 05 00 01 1b 00 .box-0,3..0.....
|
||||
| 3808: 02 62 6f 78 2d 30 2c 32 00 00 00 0f 00 09 1b 00 .box-0,2........
|
||||
| 3824: 62 6f 78 2d 30 2c 30 0d 0e 05 00 09 1d 00 74 6f box-0,0.......to
|
||||
| 3840: 70 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74 p half.....#.bot
|
||||
| 3856: 74 6f 6d 20 68 61 6c 66 0f 0c 02 05 09 01 00 72 tom half.......r
|
||||
| 3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00 ight half.......
|
||||
| 3888: 6c 65 66 74 20 68 61 6c 66 14 0a 05 00 09 2b 00 left half.....+.
|
||||
| 3904: 74 68 65 20 77 68 6f 6c 65 20 74 68 69 6e 67 0d the whole thing.
|
||||
| 3920: 09 05 00 09 1d 00 74 6f 70 20 65 64 67 65 10 08 ......top edge..
|
||||
| 3936: 05 00 09 23 00 62 6f 74 74 6f 6d 20 65 64 67 65 ...#.bottom edge
|
||||
| 3952: 0f 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 .....!.right edg
|
||||
| 3968: 65 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 e.......left edg
|
||||
| 3984: 65 0b 05 05 00 09 19 00 63 65 6e 74 65 72 17 04 e.......center..
|
||||
| 4000: 05 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 ...1.upper-right
|
||||
| 4016: 20 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f corner.....1.lo
|
||||
| 4032: 77 65 72 2d 72 69 67 68 74 20 63 6f 72 6e 65 72 wer-right corner
|
||||
| 4048: 16 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 ...../.upper-lef
|
||||
| 4064: 74 20 63 6f 72 6e 65 72 06 00 05 00 01 00 00 03 t corner........
|
||||
| 4080: 0d 88 4f 05 00 01 1b 00 02 62 6f 78 2d 33 2c 31 ..O......box-3,1
|
||||
| page 3 offset 8192
|
||||
| 0: 05 00 00 00 01 0f fb 00 00 00 00 06 0f fb 00 00 ................
|
||||
| 384: 00 00 00 00 00 00 00 89 50 03 04 00 93 24 00 00 ........P....$..
|
||||
| 400: 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 688: 00 00 00 00 42 c8 00 00 42 4c 00 00 42 00 00 00 ....B...BL..B...
|
||||
| 720: 03 eb 40 40 00 00 40 80 00 00 00 00 00 00 3f 80 ..@@..@.......?.
|
||||
| 736: 00 00 00 00 00 00 00 00 03 ea 40 00 00 00 40 40 ..........@...@@
|
||||
| 752: 00 00 00 00 00 00 3f 80 00 00 00 00 00 00 00 00 ......?.........
|
||||
| 768: 03 e9 3f 80 00 00 40 00 00 00 00 00 00 00 3f 80 ..?...@.......?.
|
||||
| 784: 00 00 00 00 00 00 00 00 03 e8 00 00 00 00 3f 80 ..............?.
|
||||
| 800: 00 00 00 00 00 00 3f 80 00 00 00 00 00 00 00 00 ......?.........
|
||||
| 1616: 00 00 00 00 00 00 00 00 00 00 89 50 02 04 00 93 ...........P....
|
||||
| 1632: 24 00 00 00 33 00 00 00 00 00 00 00 01 00 00 00 $...3...........
|
||||
| 1648: 00 41 20 00 00 00 00 00 00 41 0e 00 00 00 00 00 .A ......A......
|
||||
| 1664: 00 00 00 04 4f 40 40 00 00 40 80 00 00 3f 80 00 ....O@@..@...?..
|
||||
| 1680: 00 40 00 00 00 00 00 00 00 00 00 04 4e 40 00 00 .@..........N@..
|
||||
| 1696: 00 40 40 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@@..?...@......
|
||||
| 1712: 00 00 00 04 4d 3f 80 00 00 40 00 00 00 3f 80 00 ....M?...@...?..
|
||||
| 1728: 00 40 00 00 00 00 00 00 00 00 00 04 4c 00 00 00 .@..........L...
|
||||
| 1744: 00 3f 80 00 00 3f 80 00 00 40 00 00 00 00 00 00 .?...?...@......
|
||||
| 1760: 00 00 00 04 b3 40 40 00 00 40 80 00 00 40 00 00 .....@@..@...@..
|
||||
| 1776: 00 40 40 00 00 00 00 00 00 00 00 04 b2 40 00 00 .@@..........@..
|
||||
| 1792: 00 40 40 00 00 40 00 00 00 40 40 00 00 00 00 00 .@@..@...@@.....
|
||||
| 1808: 00 00 00 04 b1 3f 80 00 00 40 00 00 00 40 00 00 .....?...@...@..
|
||||
| 1824: 00 40 40 00 00 00 00 00 00 00 00 04 b0 00 00 00 .@@.............
|
||||
| 1840: 00 3f 80 00 00 40 00 00 00 40 40 00 00 00 00 00 .?...@...@@.....
|
||||
| 1856: 00 00 00 05 17 40 40 00 00 40 80 00 00 40 40 00 .....@@..@...@@.
|
||||
| 1872: 00 40 80 00 00 00 00 00 00 00 00 05 16 40 00 00 .@...........@..
|
||||
| 1888: 00 40 40 00 00 40 40 00 00 40 80 00 00 00 00 00 .@@..@@..@......
|
||||
| 1904: 00 00 00 05 15 3f 80 00 00 40 00 00 00 40 40 00 .....?...@...@@.
|
||||
| 1920: 00 40 80 00 00 00 00 00 00 00 00 05 14 00 00 00 .@..............
|
||||
| 1936: 00 3f 80 00 00 40 40 00 00 40 80 00 00 00 00 00 .?...@@..@......
|
||||
| 1952: 00 00 00 05 7b 40 40 00 00 40 80 00 00 40 80 00 .....@@..@...@..
|
||||
| 1968: 00 40 a0 00 00 00 00 00 00 00 00 05 7a 40 00 00 .@..........z@..
|
||||
| 1984: 00 40 40 00 00 40 80 00 00 40 a0 00 00 00 00 00 .@@..@...@......
|
||||
| 2000: 00 00 00 05 79 3f 80 00 00 40 00 00 00 40 80 00 ....y?...@...@..
|
||||
| 2016: 00 40 a0 00 00 00 00 00 00 00 00 05 78 00 00 00 .@..........x...
|
||||
| 2032: 00 3f 80 00 00 40 80 00 00 40 a0 00 00 00 00 00 .?...@...@......
|
||||
| 2048: 00 00 00 05 df 40 40 00 00 40 80 00 00 40 a0 00 .....@@..@...@..
|
||||
| 2064: 00 40 c0 00 00 00 00 00 00 00 00 05 de 40 00 00 .@...........@..
|
||||
| 2080: 00 40 40 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@@..@...@......
|
||||
| 2096: 00 00 00 05 dd 3f 80 00 00 40 00 00 00 40 a0 00 .....?...@...@..
|
||||
| 2112: 00 40 c0 00 00 00 00 00 00 00 00 05 dc 00 00 00 .@..............
|
||||
| 2128: 00 3f 80 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .?...@...@......
|
||||
| 2144: 00 00 00 06 43 40 40 00 00 40 80 00 00 40 c0 00 ....C@@..@...@..
|
||||
| 2160: 00 40 e0 00 00 00 00 00 00 00 00 06 42 40 00 00 .@..........B@..
|
||||
| 2176: 00 40 40 00 00 40 c0 00 00 40 e0 00 00 00 00 00 .@@..@...@......
|
||||
| 2192: 00 00 00 06 41 3f 80 00 00 40 00 00 00 40 c0 00 ....A?...@...@..
|
||||
| 2208: 00 40 e0 00 00 00 00 00 00 00 00 06 40 00 00 00 .@..........@...
|
||||
| 2224: 00 3f 80 00 00 40 c0 00 00 40 e0 00 00 00 00 00 .?...@...@......
|
||||
| 2240: 00 00 00 06 a7 40 40 00 00 40 80 00 00 40 e0 00 .....@@..@...@..
|
||||
| 2256: 00 41 00 00 00 00 00 00 00 00 00 06 a6 40 00 00 .A...........@..
|
||||
| 2272: 00 40 40 00 00 40 e0 00 00 41 00 00 00 00 00 00 .@@..@...A......
|
||||
| 2288: 00 00 00 06 a5 3f 80 00 00 40 00 00 00 40 e0 00 .....?...@...@..
|
||||
| 2304: 00 41 00 00 00 00 00 00 00 00 00 06 a4 00 00 00 .A..............
|
||||
| 2320: 00 3f 80 00 00 40 e0 00 00 41 00 00 00 00 00 00 .?...@...A......
|
||||
| 2336: 00 00 00 07 0a 40 00 00 00 40 40 00 00 41 00 00 .....@...@@..A..
|
||||
| 2352: 00 41 10 00 00 00 00 00 00 00 00 07 09 3f 80 00 .A...........?..
|
||||
| 2368: 00 40 00 00 00 41 00 00 00 41 10 00 00 00 00 00 .@...A...A......
|
||||
| 2384: 00 00 00 07 08 00 00 00 00 3f 80 00 00 41 00 00 .........?...A..
|
||||
| 2400: 00 41 10 00 00 00 00 00 00 00 00 07 6e 40 00 00 .A..........n@..
|
||||
| 2416: 00 40 40 00 00 41 10 00 00 41 20 00 00 00 00 00 .@@..A...A .....
|
||||
| 2432: 00 00 00 07 6d 3f 80 00 00 40 00 00 00 41 10 00 ....m?...@...A..
|
||||
| 2448: 00 41 20 00 00 00 00 00 00 00 00 07 6c 00 00 00 .A .........l...
|
||||
| 2464: 00 3f 80 00 00 41 10 00 00 41 20 00 00 00 00 00 .?...A...A .....
|
||||
| 2480: 00 00 00 07 0b 40 40 00 00 40 80 00 00 41 00 00 .....@@..@...A..
|
||||
| 2496: 00 41 10 00 00 00 00 00 00 00 00 07 6f 40 40 00 .A..........o@@.
|
||||
| 2512: 00 40 80 00 00 41 10 00 00 41 20 00 00 00 00 00 .@...A...A .....
|
||||
| 2528: 00 00 00 03 ec 40 80 00 00 40 a0 00 00 00 00 00 .....@...@......
|
||||
| 2544: 00 3f 80 00 00 00 00 00 00 00 00 04 50 40 80 00 .?..........P@..
|
||||
| 2560: 00 40 a0 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@......
|
||||
| 2576: 00 00 00 04 b4 40 80 00 00 40 a0 00 00 40 00 00 .....@...@...@..
|
||||
| 2592: 00 40 40 00 00 00 00 00 00 00 00 05 18 40 80 00 .@@..........@..
|
||||
| 2608: 00 40 a0 00 00 40 40 00 00 40 80 00 00 00 00 00 .@...@@..@......
|
||||
| 2624: 00 00 00 05 7c 40 80 00 00 40 a0 00 00 40 80 00 ....|@...@...@..
|
||||
| 2640: 00 40 a0 00 00 00 00 00 00 00 00 05 e0 40 80 00 .@...........@..
|
||||
| 2656: 00 40 a0 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@...@...@......
|
||||
| 2672: 00 00 00 06 44 40 80 00 00 40 a0 00 00 40 c0 00 ....D@...@...@..
|
||||
| 2688: 00 40 e0 00 00 00 00 00 00 00 00 06 a8 40 80 00 .@...........@..
|
||||
| 2704: 00 40 a0 00 00 40 e0 00 00 41 00 00 00 00 00 00 .@...@...A......
|
||||
| 2720: 00 00 00 07 0c 40 80 00 00 40 a0 00 00 41 00 00 .....@...@...A..
|
||||
| 2736: 00 41 10 00 00 00 00 00 00 00 00 07 70 40 80 00 .A..........p@..
|
||||
| 2752: 00 40 a0 00 00 41 10 00 00 41 20 00 00 00 00 00 .@...A...A .....
|
||||
| 2768: 00 00 00 03 ed 40 a0 00 00 40 c0 00 00 00 00 00 .....@...@......
|
||||
| 2784: 00 3f 80 00 00 00 00 00 00 00 00 04 51 40 a0 00 .?..........Q@..
|
||||
| 2800: 00 40 c0 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@......
|
||||
| 2816: 00 00 00 04 b5 40 a0 00 00 40 c0 00 00 40 00 00 .....@...@...@..
|
||||
| 2832: 00 40 40 00 00 00 00 00 00 00 00 05 19 40 a0 00 .@@..........@..
|
||||
| 2848: 00 40 c0 00 00 40 40 00 00 40 80 00 00 89 50 01 .@...@@..@....P.
|
||||
| 2864: 04 00 93 24 00 01 00 02 00 00 00 00 00 00 00 03 ...$............
|
||||
| 2880: 00 00 00 00 40 80 00 00 00 00 00 00 3f 80 00 00 ....@.......?...
|
||||
| 2896: 00 00 00 00 00 00 00 02 00 00 00 00 41 20 00 00 ............A ..
|
||||
| 2912: 00 00 00 00 41 20 00 00 00 00 00 00 00 00 00 00 ....A ..........
|
||||
| 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 03 ................
|
||||
| page 4 offset 12288
|
||||
| 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| page 5 offset 16384
|
||||
| 0: 0d 00 00 00 03 01 87 00 0b 2d 06 5a 01 87 00 00 .........-.Z....
|
||||
| 384: 00 00 00 00 00 00 00 89 50 03 04 00 93 24 00 00 ........P....$..
|
||||
| 400: 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 688: 00 00 00 00 42 c8 00 00 42 4c 00 00 42 00 00 00 ....B...BL..B...
|
||||
| 720: 03 eb 40 40 00 00 40 80 00 00 00 00 00 00 3f 80 ..@@..@.......?.
|
||||
| 736: 00 00 00 00 00 00 00 00 03 ea 40 00 00 00 40 40 ..........@...@@
|
||||
| 752: 00 00 00 00 00 00 3f 80 00 00 00 00 00 00 00 00 ......?.........
|
||||
| 768: 03 e9 3f 80 00 00 40 00 00 00 00 00 00 00 3f 80 ..?...@.......?.
|
||||
| 784: 00 00 00 00 00 00 00 00 03 e8 00 00 00 00 3f 80 ..............?.
|
||||
| 800: 00 00 00 00 00 00 3f 80 00 00 00 00 00 00 00 00 ......?.........
|
||||
| 1616: 00 00 00 00 00 00 00 00 00 00 89 50 02 04 00 93 ...........P....
|
||||
| 1632: 24 00 00 00 2d 00 00 00 00 00 00 04 4c 00 00 00 $...-.......L...
|
||||
| 1648: 00 3f 80 00 00 3f 80 00 00 40 00 00 00 00 00 00 .?...?...@......
|
||||
| 1664: 00 00 00 04 b0 00 00 00 00 3f 80 00 00 40 00 00 .........?...@..
|
||||
| 1680: 00 40 40 00 00 00 00 00 00 00 00 05 14 00 00 00 .@@.............
|
||||
| 1696: 00 3f 80 00 00 40 40 00 00 40 80 00 00 00 00 00 .?...@@..@......
|
||||
| 1712: 00 00 00 05 78 00 00 00 00 3f 80 00 00 40 80 00 ....x....?...@..
|
||||
| 1728: 00 40 a0 00 00 00 00 00 00 00 00 05 dc 00 00 00 .@..............
|
||||
| 1744: 00 3f 80 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .?...@...@......
|
||||
| 1760: 00 00 00 00 01 00 00 00 00 41 20 00 00 00 00 00 .........A .....
|
||||
| 1776: 00 41 0e 00 00 00 00 00 00 00 00 04 4d 3f 80 00 .A..........M?..
|
||||
| 1792: 00 40 00 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@......
|
||||
| 1808: 00 00 00 04 b1 3f 80 00 00 40 00 00 00 40 00 00 .....?...@...@..
|
||||
| 1824: 00 40 40 00 00 00 00 00 00 00 00 05 15 3f 80 00 .@@..........?..
|
||||
| 1840: 00 40 00 00 00 40 40 00 00 40 80 00 00 00 00 00 .@...@@..@......
|
||||
| 1856: 00 00 00 05 79 3f 80 00 00 40 00 00 00 40 80 00 ....y?...@...@..
|
||||
| 1872: 00 40 a0 00 00 00 00 00 00 00 00 05 dd 3f 80 00 .@...........?..
|
||||
| 1888: 00 40 00 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@...@...@......
|
||||
| 1904: 00 00 00 04 4e 40 00 00 00 40 40 00 00 3f 80 00 ....N@...@@..?..
|
||||
| 1920: 00 40 00 00 00 00 00 00 00 00 00 04 b2 40 00 00 .@...........@..
|
||||
| 1936: 00 40 40 00 00 40 00 00 00 40 40 00 00 00 00 00 .@@..@...@@.....
|
||||
| 1952: 00 00 00 05 16 40 00 00 00 40 40 00 00 40 40 00 .....@...@@..@@.
|
||||
| 1968: 00 40 80 00 00 00 00 00 00 00 00 05 7a 40 00 00 .@..........z@..
|
||||
| 1984: 00 40 40 00 00 40 80 00 00 40 a0 00 00 00 00 00 .@@..@...@......
|
||||
| 2000: 00 00 00 05 de 40 00 00 00 40 40 00 00 40 a0 00 .....@...@@..@..
|
||||
| 2016: 00 40 c0 00 00 00 00 00 00 00 00 04 4f 40 40 00 .@..........O@@.
|
||||
| 2032: 00 40 80 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@......
|
||||
| 2048: 00 00 00 04 b3 40 40 00 00 40 80 00 00 40 00 00 .....@@..@...@..
|
||||
| 2064: 00 40 40 00 00 00 00 00 00 00 00 05 17 40 40 00 .@@..........@@.
|
||||
| 2080: 00 40 80 00 00 40 40 00 00 40 80 00 00 00 00 00 .@...@@..@......
|
||||
| 2096: 00 00 00 05 7b 40 40 00 00 40 80 00 00 40 80 00 .....@@..@...@..
|
||||
| 2112: 00 40 a0 00 00 00 00 00 00 00 00 05 df 40 40 00 .@...........@@.
|
||||
| 2128: 00 40 80 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@...@...@......
|
||||
| 2144: 00 00 00 03 ec 40 80 00 00 40 a0 00 00 00 00 00 .....@...@......
|
||||
| 2160: 00 3f 80 00 00 00 00 00 00 00 00 04 50 40 80 00 .?..........P@..
|
||||
| 2176: 00 40 a0 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@......
|
||||
| 2192: 00 00 00 04 b4 40 80 00 00 40 a0 00 00 40 00 00 .....@...@...@..
|
||||
| 2208: 00 40 40 00 00 00 00 00 00 00 00 05 18 40 80 00 .@@..........@..
|
||||
| 2224: 00 40 a0 00 00 40 40 00 00 40 80 00 00 00 00 00 .@...@@..@......
|
||||
| 2240: 00 00 00 05 7c 40 80 00 00 40 a0 00 00 40 80 00 ....|@...@...@..
|
||||
| 2256: 00 40 a0 00 00 00 00 00 00 00 00 05 e0 40 80 00 .@...........@..
|
||||
| 2272: 00 40 a0 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@...@...@......
|
||||
| 2288: 00 00 00 03 f0 41 00 00 00 41 10 00 00 00 00 00 .....A...A......
|
||||
| 2304: 00 3f 80 00 00 00 00 00 00 00 00 04 54 41 00 00 .?..........TA..
|
||||
| 2320: 00 41 10 00 00 3f 80 00 00 40 00 00 00 00 00 00 .A...?...@......
|
||||
| 2336: 00 00 00 04 b8 41 00 00 00 41 10 00 00 40 00 00 .....A...A...@..
|
||||
| 2352: 00 40 40 00 00 00 00 00 00 00 00 05 1c 41 00 00 .@@..........A..
|
||||
| 2368: 00 41 10 00 00 40 40 00 00 40 80 00 00 00 00 00 .A...@@..@......
|
||||
| 2384: 00 00 00 05 80 41 00 00 00 41 10 00 00 40 80 00 .....A...A...@..
|
||||
| 2400: 00 40 a0 00 00 00 00 00 00 00 00 05 e4 41 00 00 .@...........A..
|
||||
| 2416: 00 41 10 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .A...@...@......
|
||||
| 2432: 00 00 00 06 48 41 00 00 00 41 10 00 00 40 c0 00 ....HA...A...@..
|
||||
| 2448: 00 40 e0 00 00 00 00 00 00 00 00 06 ac 41 00 00 .@...........A..
|
||||
| 2464: 00 41 10 00 00 40 e0 00 00 41 00 00 00 00 00 00 .A...@...A......
|
||||
| 2480: 00 00 00 07 10 41 00 00 00 41 10 00 00 41 00 00 .....A...A...A..
|
||||
| 2496: 00 41 10 00 00 00 00 00 00 00 00 03 f1 41 10 00 .A...........A..
|
||||
| 2512: 00 41 20 00 00 00 00 00 00 3f 80 00 00 00 00 00 .A ......?......
|
||||
| 2528: 00 00 00 04 55 41 10 00 00 41 20 00 00 3f 80 00 ....UA...A ..?..
|
||||
| 2544: 00 40 00 00 00 00 00 00 00 00 00 04 b9 41 10 00 .@...........A..
|
||||
| 2560: 00 41 20 00 00 40 00 00 00 40 40 00 00 00 00 00 .A ..@...@@.....
|
||||
| 2576: 00 00 00 05 1d 41 10 00 00 41 20 00 00 40 40 00 .....A...A ..@@.
|
||||
| 2592: 00 40 80 00 00 00 00 00 00 00 00 05 81 41 10 00 .@...........A..
|
||||
| 2608: 00 41 20 00 00 40 80 00 00 40 a0 00 00 00 00 00 .A ..@...@......
|
||||
| 2624: 00 00 00 05 e5 41 10 00 00 41 20 00 00 40 a0 00 .....A...A ..@..
|
||||
| 2640: 00 40 c0 00 00 00 00 00 00 00 00 06 49 41 10 00 .@..........IA..
|
||||
| 2656: 00 41 20 00 00 40 c0 00 00 40 e0 00 00 00 00 00 .A ..@...@......
|
||||
| 2672: 00 00 00 06 ad 41 10 00 00 41 20 00 00 40 e0 00 .....A...A ..@..
|
||||
| 2688: 00 41 00 00 00 00 00 00 00 00 00 07 11 41 10 00 .A...........A..
|
||||
| 2704: 00 41 20 00 00 41 00 00 00 41 10 00 00 00 00 00 .A ..A...A......
|
||||
| 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 01 ..............P.
|
||||
| 2864: 04 00 93 24 00 01 00 04 00 00 00 00 00 00 00 03 ...$............
|
||||
| 2880: 00 00 00 00 40 80 00 00 00 00 00 00 3f 80 00 00 ....@.......?...
|
||||
| 2896: 00 00 00 00 00 00 00 02 00 00 00 00 41 20 00 00 ............A ..
|
||||
| 2912: 00 00 00 00 41 10 00 00 00 00 00 00 00 00 00 04 ....A...........
|
||||
| 2928: 00 00 00 00 41 20 00 00 40 c0 00 00 41 20 00 00 ....A ..@...A ..
|
||||
| 2944: 00 00 00 00 00 00 00 05 40 a0 00 00 41 00 00 00 ........@...A...
|
||||
| 2960: 00 00 00 00 41 20 00 00 00 00 00 00 00 00 00 00 ....A ..........
|
||||
| page 6 offset 20480
|
||||
| 0: 0d 00 00 00 02 06 5a 00 0b 2d 06 5a 00 00 00 00 ......Z..-.Z....
|
||||
| 1616: 00 00 00 00 00 00 00 00 00 00 89 50 05 04 00 93 ...........P....
|
||||
| 1632: 24 00 00 00 1c 00 00 00 00 00 00 03 ed 40 a0 00 $............@..
|
||||
| 1648: 00 40 c0 00 00 00 00 00 00 3f 80 00 00 00 00 00 .@.......?......
|
||||
| 1664: 00 00 00 04 51 40 a0 00 00 40 c0 00 00 3f 80 00 ....Q@...@...?..
|
||||
| 1680: 00 40 00 00 00 00 00 00 00 00 00 04 b5 40 a0 00 .@...........@..
|
||||
| 1696: 00 40 c0 00 00 40 00 00 00 40 40 00 00 00 00 00 .@...@...@@.....
|
||||
| 1712: 00 00 00 05 19 40 a0 00 00 40 c0 00 00 40 40 00 .....@...@...@@.
|
||||
| 1728: 00 40 80 00 00 00 00 00 00 00 00 05 7d 40 a0 00 .@...........@..
|
||||
| 1744: 00 40 c0 00 00 40 80 00 00 40 a0 00 00 00 00 00 .@...@...@......
|
||||
| 1760: 00 00 00 05 e1 40 a0 00 00 40 c0 00 00 40 a0 00 .....@...@...@..
|
||||
| 1776: 00 40 c0 00 00 00 00 00 00 00 00 06 45 40 a0 00 .@..........E@..
|
||||
| 1792: 00 40 c0 00 00 40 c0 00 00 40 e0 00 00 00 00 00 .@...@...@......
|
||||
| 1808: 00 00 00 06 a9 40 a0 00 00 40 c0 00 00 40 e0 00 .....@...@...@..
|
||||
| 1824: 00 41 00 00 00 00 00 00 00 00 00 07 0d 40 a0 00 .A...........@..
|
||||
| 1840: 00 40 c0 00 00 41 00 00 00 41 10 00 00 00 00 00 .@...A...A......
|
||||
| 1856: 00 00 00 03 ee 40 c0 00 00 40 e0 00 00 00 00 00 .....@...@......
|
||||
| 1872: 00 3f 80 00 00 00 00 00 00 00 00 04 52 40 c0 00 .?..........R@..
|
||||
| 1888: 00 40 e0 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@......
|
||||
| 1904: 00 00 00 04 b6 40 c0 00 00 40 e0 00 00 40 00 00 .....@...@...@..
|
||||
| 1920: 00 40 40 00 00 00 00 00 00 00 00 05 1a 40 c0 00 .@@..........@..
|
||||
| 1936: 00 40 e0 00 00 40 40 00 00 40 80 00 00 00 00 00 .@...@@..@......
|
||||
| 1952: 00 00 00 05 7e 40 c0 00 00 40 e0 00 00 40 80 00 ....~@...@...@..
|
||||
| 1968: 00 40 a0 00 00 00 00 00 00 00 00 05 e2 40 c0 00 .@...........@..
|
||||
| 1984: 00 40 e0 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@...@...@......
|
||||
| 2000: 00 00 00 06 46 40 c0 00 00 40 e0 00 00 40 c0 00 ....F@...@...@..
|
||||
| 2016: 00 40 e0 00 00 00 00 00 00 00 00 06 aa 40 c0 00 .@...........@..
|
||||
| 2032: 00 40 e0 00 00 40 e0 00 00 41 00 00 00 00 00 00 .@...@...A......
|
||||
| 2048: 00 00 00 07 0e 40 c0 00 00 40 e0 00 00 41 00 00 .....@...@...A..
|
||||
| 2064: 00 41 10 00 00 00 00 00 00 00 00 03 ef 40 e0 00 .A...........@..
|
||||
| 2080: 00 41 00 00 00 00 00 00 00 3f 80 00 00 00 00 00 .A.......?......
|
||||
| 2096: 00 00 00 04 53 40 e0 00 00 41 00 00 00 3f 80 00 ....S@...A...?..
|
||||
| 2112: 00 40 00 00 00 00 00 00 00 00 00 04 b7 40 e0 00 .@...........@..
|
||||
| 2128: 00 41 00 00 00 40 00 00 00 40 40 00 00 00 00 00 .A...@...@@.....
|
||||
| 2144: 00 00 00 05 1b 40 e0 00 00 41 00 00 00 40 40 00 .....@...A...@@.
|
||||
| 2160: 00 40 80 00 00 00 00 00 00 00 00 05 7f 40 e0 00 .@...........@..
|
||||
| 2176: 00 41 00 00 00 40 80 00 00 40 a0 00 00 00 00 00 .A...@...@......
|
||||
| 2192: 00 00 00 05 e3 40 e0 00 00 41 00 00 00 40 a0 00 .....@...A...@..
|
||||
| 2208: 00 40 c0 00 00 00 00 00 00 00 00 06 47 40 e0 00 .@..........G@..
|
||||
| 2224: 00 41 00 00 00 40 c0 00 00 40 e0 00 00 00 00 00 .A...@...@......
|
||||
| 2240: 00 00 00 06 ab 40 e0 00 00 41 00 00 00 40 e0 00 .....@...A...@..
|
||||
| 2256: 00 41 00 00 00 00 00 00 00 00 00 07 0f 40 e0 00 .A...........@..
|
||||
| 2272: 00 41 00 00 00 41 00 00 00 41 10 00 00 00 00 00 .A...A...A......
|
||||
| 2288: 00 00 00 07 73 40 e0 00 00 41 00 00 00 41 10 00 ....s@...A...A..
|
||||
| 2304: 00 41 20 00 00 00 00 00 00 00 00 00 00 00 00 00 .A .............
|
||||
| 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 04 ..............P.
|
||||
| 2864: 04 00 93 24 00 00 00 18 00 00 00 00 00 00 06 43 ...$...........C
|
||||
| 2880: 40 40 00 00 40 80 00 00 40 c0 00 00 40 e0 00 00 @@..@...@...@...
|
||||
| 2896: 00 00 00 00 00 00 06 42 40 00 00 00 40 40 00 00 .......B@...@@..
|
||||
| 2912: 40 c0 00 00 40 e0 00 00 00 00 00 00 00 00 06 41 @...@..........A
|
||||
| 2928: 3f 80 00 00 40 00 00 00 40 c0 00 00 40 e0 00 00 ?...@...@...@...
|
||||
| 2944: 00 00 00 00 00 00 06 40 00 00 00 00 3f 80 00 00 .......@....?...
|
||||
| 2960: 40 c0 00 00 40 e0 00 00 00 00 00 00 00 00 06 44 @...@..........D
|
||||
| 2976: 40 80 00 00 40 a0 00 00 40 c0 00 00 40 e0 00 00 @...@...@...@...
|
||||
| 2992: 00 00 00 00 00 00 06 a7 40 40 00 00 40 80 00 00 ........@@..@...
|
||||
| 3008: 40 e0 00 00 41 00 00 00 00 00 00 00 00 00 06 a6 @...A...........
|
||||
| 3024: 40 00 00 00 40 40 00 00 40 e0 00 00 41 00 00 00 @...@@..@...A...
|
||||
| 3040: 00 00 00 00 00 00 06 a5 3f 80 00 00 40 00 00 00 ........?...@...
|
||||
| 3056: 40 e0 00 00 41 00 00 00 00 00 00 00 00 00 06 a4 @...A...........
|
||||
| 3072: 00 00 00 00 3f 80 00 00 40 e0 00 00 41 00 00 00 ....?...@...A...
|
||||
| 3088: 00 00 00 00 00 00 06 a8 40 80 00 00 40 a0 00 00 ........@...@...
|
||||
| 3104: 40 e0 00 00 41 00 00 00 00 00 00 00 00 00 07 0a @...A...........
|
||||
| 3120: 40 00 00 00 40 40 00 00 41 00 00 00 41 10 00 00 @...@@..A...A...
|
||||
| 3136: 00 00 00 00 00 00 07 09 3f 80 00 00 40 00 00 00 ........?...@...
|
||||
| 3152: 41 00 00 00 41 10 00 00 00 00 00 00 00 00 07 08 A...A...........
|
||||
| 3168: 00 00 00 00 3f 80 00 00 41 00 00 00 41 10 00 00 ....?...A...A...
|
||||
| 3184: 00 00 00 00 00 00 07 0b 40 40 00 00 40 80 00 00 ........@@..@...
|
||||
| 3200: 41 00 00 00 41 10 00 00 00 00 00 00 00 00 07 0c A...A...........
|
||||
| 3216: 40 80 00 00 40 a0 00 00 41 00 00 00 41 10 00 00 @...@...A...A...
|
||||
| 3232: 00 00 00 00 00 00 07 6e 40 00 00 00 40 40 00 00 .......n@...@@..
|
||||
| 3248: 41 10 00 00 41 20 00 00 00 00 00 00 00 00 07 6d A...A .........m
|
||||
| 3264: 3f 80 00 00 40 00 00 00 41 10 00 00 41 20 00 00 ?...@...A...A ..
|
||||
| 3280: 00 00 00 00 00 00 07 6c 00 00 00 00 3f 80 00 00 .......l....?...
|
||||
| 3296: 41 10 00 00 41 20 00 00 00 00 00 00 00 00 07 6f A...A .........o
|
||||
| 3312: 40 40 00 00 40 80 00 00 41 10 00 00 41 20 00 00 @@..@...A...A ..
|
||||
| 3328: 00 00 00 00 00 00 07 70 40 80 00 00 40 a0 00 00 .......p@...@...
|
||||
| 3344: 41 10 00 00 41 20 00 00 00 00 00 00 00 00 07 71 A...A .........q
|
||||
| 3360: 40 a0 00 00 40 c0 00 00 41 10 00 00 41 20 00 00 @...@...A...A ..
|
||||
| 3376: 00 00 00 00 00 00 07 72 40 c0 00 00 40 e0 00 00 .......r@...@...
|
||||
| 3392: 41 10 00 00 41 20 00 00 00 00 00 00 00 00 07 74 A...A .........t
|
||||
| 3408: 41 00 00 00 41 10 00 00 41 10 00 00 41 20 00 00 A...A...A...A ..
|
||||
| 3424: 00 00 00 00 00 00 07 75 41 10 00 00 41 20 00 00 .......uA...A ..
|
||||
| 3440: 41 10 00 00 41 20 00 00 00 00 00 00 00 00 00 00 A...A ..........
|
||||
| end c1b.db
|
||||
}]
|
||||
catchsql {
|
||||
SELECT rtreecheck('t1');
|
||||
}
|
||||
} {1 {SQL logic error}}
|
||||
|
||||
do_test rtreefuzz001-200 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
| size 16384 pagesize 4096 filename c3.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 04 .....@ ........
|
||||
| 32: 00 00 00 00 01 00 00 00 00 00 00 04 00 00 00 04 ................
|
||||
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f ...............O
|
||||
| 112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17 ............^...
|
||||
| 3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72 .....tablet1_par
|
||||
| 3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45 entt1_parent.CRE
|
||||
| 3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61 ATE TABLE .t1_pa
|
||||
| 3792: 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 rent.(nodeno INT
|
||||
| 3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
|
||||
| 3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17 ,parentnode)Q...
|
||||
| 3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65 ....tablet1_node
|
||||
| 3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54 t1_node.CREATE T
|
||||
| 3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e ABLE .t1_node.(n
|
||||
| 3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52 odeno INTEGER PR
|
||||
| 3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c IMARY KEY,data).
|
||||
| 3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f ........tablet1_
|
||||
| 3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52 rowidt1_rowid.CR
|
||||
| 3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72 EATE TABLE .t1_r
|
||||
| 3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE
|
||||
| 3984: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY,
|
||||
| 4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07 nodeno,a0,a1)Q..
|
||||
| 4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43 ......tablet1t1C
|
||||
| 4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA
|
||||
| 4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 BLE t1 USING rtr
|
||||
| 4064: 65 65 28 69 64 2c 78 30 2c 78 31 2c 79 30 2c 79 ee(id,x0,x1,y0,y
|
||||
| 4080: 31 2c 2b 6c 61 62 65 6c 2c 2b 6f 74 68 65 72 29 1,+label,+other)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 00 00 00 0e 0e f7 00 0f e8 0f d0 0f b7 0f 9e ................
|
||||
| 16: 0f 91 0f 81 0f 70 0f 5e 0f 4f 0f 39 0f 29 0f 18 .....p.^.O.9.)..
|
||||
| 32: 0f 06 0e f7 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3824: 00 00 00 00 00 00 00 0d 0e 05 00 09 1d 00 74 6f ..............to
|
||||
| 3840: 70 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74 p half.....#.bot
|
||||
| 3856: 74 6f 6d 20 68 61 6c 66 0f 0c 05 00 09 21 00 72 tom half.....!.r
|
||||
| 3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00 ight half.......
|
||||
| 3888: 6c 65 66 74 20 68 61 6c 66 14 0a 05 00 09 2b 00 left half.....+.
|
||||
| 3904: 74 68 65 20 77 68 6f 6c 65 20 74 68 69 6e 67 0d the whole thing.
|
||||
| 3920: 09 05 00 09 1d 00 74 6f 70 20 65 64 67 65 10 08 ......top edge..
|
||||
| 3936: 05 00 09 23 00 62 6f 74 74 6f 6d 20 65 64 67 65 ...#.bottom edge
|
||||
| 3952: 0f 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 .....!.right edg
|
||||
| 3968: 65 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 e.......left edg
|
||||
| 3984: 65 0b 05 05 00 09 19 00 63 65 6e 74 65 72 17 04 e.......center..
|
||||
| 4000: 05 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 ...1.upper-right
|
||||
| 4016: 20 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f corner.....1.lo
|
||||
| 4032: 77 65 72 2d 72 69 67 68 74 27 60 f6 32 6e 65 72 wer-right'`.2ner
|
||||
| 4048: 16 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 ...../.upper-lef
|
||||
| 4064: 74 20 63 6f 72 6e 65 72 16 01 05 00 09 2f 00 6c t corner...../.l
|
||||
| 4080: 6f 77 65 72 2d 6c 65 66 74 20 63 6f 72 6e 65 72 ower-left corner
|
||||
| page 3 offset 8192
|
||||
| 0: 0d 00 00 00 02 0b 2d 00 0b 2d 00 00 00 00 00 00 ......-..-......
|
||||
| 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 01 ..............P.
|
||||
| 2864: 04 00 93 24 00 00 00 0e 00 00 00 00 00 00 00 01 ...$............
|
||||
| 2880: 00 00 00 00 41 20 00 00 00 00 00 00 41 20 01 00 ....A ......A ..
|
||||
| 2896: 00 00 00 00 00 00 00 02 00 00 00 00 41 00 00 04 ............A...
|
||||
| 2912: 2b 40 00 0c 42 c8 00 00 00 00 00 00 00 00 00 03 +@..B...........
|
||||
| 2928: 42 b4 00 00 42 c8 00 00 00 00 00 00 41 20 00 00 B...B.......A ..
|
||||
| 2944: 00 00 00 00 00 00 00 04 42 b4 00 00 42 c8 00 00 ........B...B...
|
||||
| 2960: 42 b4 00 00 42 c8 00 00 00 00 00 00 00 00 00 05 B...B...........
|
||||
| 2976: 42 20 00 00 42 70 00 00 42 20 00 00 42 70 00 00 B ..Bp..B ..Bp..
|
||||
| 2992: 00 00 00 00 00 00 00 60 00 00 00 04 0a 00 00 00 .......`........
|
||||
| 3008: 00 00 00 42 c8 00 00 00 00 00 00 00 00 00 07 42 ...B...........B
|
||||
| 3024: be 00 00 42 c8 00 00 00 00 00 00 42 c8 00 00 00 ...B.......B....
|
||||
| 3040: 00 00 00 00 00 00 08 00 00 00 00 42 c8 00 00 00 ...........B....
|
||||
| 3056: 00 00 00 40 a0 00 00 00 00 00 00 00 00 00 09 00 ...@............
|
||||
| 3072: 00 00 00 42 c8 00 00 42 be 00 00 42 c8 00 00 00 ...B...B...B....
|
||||
| 3088: 00 00 00 00 00 00 0a 00 00 00 00 42 c8 00 00 00 ...........B....
|
||||
| 3104: 00 00 00 42 c8 00 00 00 00 00 00 00 00 00 0b 00 ...B............
|
||||
| 3120: 00 00 00 42 48 00 00 00 00 00 04 2c 80 00 00 00 ...BH......,....
|
||||
| 3136: 00 00 00 00 00 00 c4 24 c0 00 04 2c 80 00 00 00 .......$...,....
|
||||
| 3152: 00 00 04 2c 80 00 00 00 00 00 00 00 00 00 d0 00 ...,............
|
||||
| 3168: 00 00 04 2c 80 00 00 00 00 00 04 24 80 00 00 00 ...,.......$....
|
||||
| 3184: 00 00 00 00 00 00 e0 00 00 00 04 2c 80 00 04 24 ...........,...$
|
||||
| 3200: c0 00 04 2c 00 00 00 00 00 00 00 00 00 00 00 00 ...,............
|
||||
| page 4 offset 12288
|
||||
| 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| end c3.db
|
||||
}]
|
||||
catchsql {
|
||||
WITH RECURSIVE
|
||||
c1(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c1 WHERE x<99),
|
||||
c2(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM c2 WHERE y<99)
|
||||
INSERT INTO t1(id, x0,x1,y0,y1,label)
|
||||
SELECT 1000+x+y*100, x, x+1, y, y+1, printf('box-%d,%d',x,y) FROM c1, c2;
|
||||
}
|
||||
} {1 {database disk image is malformed}}
|
||||
do_test rtreefuzz001-210 {
|
||||
catchsql {
|
||||
SELECT rtreecheck('t1');
|
||||
}
|
||||
} {/1 .*corrupt.*/}
|
||||
|
||||
do_test rtreefuzz001-300 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
| size 16384 pagesize 4096 filename c4.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 04 .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 04 ................
|
||||
| 96: 00 00 00 00 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f ...............O
|
||||
| 112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17 ............^...
|
||||
| 3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72 .....tablet1_par
|
||||
| 3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45 entt1_parent.CRE
|
||||
| 3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61 ATE TABLE .t1_pa
|
||||
| 3792: 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 rent.(nodeno INT
|
||||
| 3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
|
||||
| 3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17 ,parentnode)Q...
|
||||
| 3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65 ....tablet1_node
|
||||
| 3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54 t1_node.CREATE T
|
||||
| 3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e ABLE .t1_node.(n
|
||||
| 3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52 odeno INTEGER PR
|
||||
| 3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c IMARY KEY,data).
|
||||
| 3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f ........tablet1_
|
||||
| 3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52 rowidt1_rowid.CR
|
||||
| 3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72 EATE TABLE .t1_r
|
||||
| 3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE
|
||||
| 3984: 47 45 72 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GEr PRIMARY KEY,
|
||||
| 4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07 nodeno,a0,a1)Q..
|
||||
| 4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43 ......tablet1t1C
|
||||
| 4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA
|
||||
| 4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 BLE t1 USING rtr
|
||||
| 4064: 65 65 28 69 64 2c 78 30 2c 78 31 2c 79 30 2c 79 ee(id,x0,x1,y0,y
|
||||
| 4080: 31 2c 2b 6c 61 62 65 6c 2c 2b 6f 74 68 65 72 29 1,+label,+other)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 00 00 00 0e 0e f7 00 0f e8 0f 00 fb 70 f9 e0 .............p..
|
||||
| 16: f9 10 f8 10 f7 00 f5 e0 f4 f0 f3 90 f2 90 f1 80 ................
|
||||
| 32: f0 60 ef 00 00 00 00 00 00 00 00 00 00 00 00 00 .`..............
|
||||
| 3824: 00 00 00 00 00 00 00 0d 0e 05 00 09 1d 00 74 6f ..............to
|
||||
| 3840: 70 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74 p half.....#.bot
|
||||
| 3856: 74 6f 6d 20 68 61 6c 66 0f 0c 05 00 09 21 00 72 tom half.....!.r
|
||||
| 3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00 ight half.......
|
||||
| 3888: 6c 65 66 74 20 68 61 6c 66 14 0a 05 00 09 2b 00 left half.....+.
|
||||
| 3904: 00 03 98 20 49 98 2f 6c 62 05 74 68 69 6e 67 0d ... I./lb.thing.
|
||||
| 3920: 09 05 00 09 1d 00 74 6f 70 20 65 64 67 65 10 08 ......top edge..
|
||||
| 3936: 05 00 09 23 00 62 6f 74 74 6f 6d 20 65 64 67 65 ...#.bottom edge
|
||||
| 3952: 0f 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 .....!.right edg
|
||||
| 3968: 65 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 e.......left edg
|
||||
| 3984: 65 0b 05 05 00 09 19 00 63 65 6e 74 65 72 17 04 e.......center..
|
||||
| 4000: 05 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 ...1.upper-right
|
||||
| 4016: 20 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f corner.....1.lo
|
||||
| 4032: 77 65 72 2d 72 69 67 68 74 20 63 6f 72 6e 65 72 wer-right corner
|
||||
| 4048: 16 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 ...../.upper-lef
|
||||
| 4064: 74 20 63 6f 72 6e 65 72 16 01 05 00 09 2f 00 6c t corner...../.l
|
||||
| 4080: 6f 77 65 72 2d 6c 65 66 74 20 63 6f 72 6e 65 72 ower-left corner
|
||||
| page 3 offset 8192
|
||||
| 0: 0d 00 00 00 01 0b 2d 00 0b 2d 00 00 00 00 00 00 ......-..-......
|
||||
| 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 01 ..............P.
|
||||
| 2864: 04 00 93 24 00 00 00 0e 00 00 00 00 00 00 00 01 ...$............
|
||||
| 2880: 00 00 00 04 01 20 00 00 00 00 00 04 12 00 00 00 ..... ..........
|
||||
| 2896: 00 00 00 00 00 00 00 23 00 00 00 00 41 20 00 00 .......#....A ..
|
||||
| 2912: 42 b4 00 00 42 c8 00 00 00 00 00 00 00 00 00 03 B...B...........
|
||||
| 2928: 42 b4 00 00 42 c8 00 00 00 00 00 00 41 20 00 00 B...B.......A ..
|
||||
| 2944: 00 00 00 00 00 00 00 04 42 b4 00 00 42 c8 00 00 ........B...B...
|
||||
| 2960: 42 b4 00 00 42 c8 00 00 00 00 00 00 00 00 00 05 B...B...........
|
||||
| 2976: 42 20 00 00 42 70 00 00 42 20 00 00 42 70 00 00 B ..Bp..B ..Bp..
|
||||
| 2992: 00 00 00 00 00 00 00 06 00 00 00 00 40 a0 00 00 ............@...
|
||||
| 3008: 00 00 00 04 2c 80 00 00 00 00 00 00 00 00 00 74 ....,..........t
|
||||
| 3024: 2b e0 00 04 2c 80 00 04 2c 80 00 00 00 00 00 00 +...,...,.......
|
||||
| 3040: 00 00 00 80 00 00 00 04 2c 80 00 00 00 00 00 04 ........,.......
|
||||
| 3056: 0a 00 00 00 00 00 b0 80 00 00 04 2c 80 00 04 2b ...........,...+
|
||||
| 3072: e0 00 04 2c 80 00 00 00 00 00 00 00 00 00 a0 00 ...,............
|
||||
| 3088: 00 00 04 2c 80 00 00 00 00 00 04 2c 80 00 00 00 ...,.......,....
|
||||
| 3104: 00 00 00 00 00 00 b0 00 00 00 04 24 80 00 00 00 ...........$....
|
||||
| 3120: 00 00 04 2c 80 00 00 00 00 00 00 00 50 00 91 f0 ...,........P...
|
||||
| 3136: 06 c6 56 67 42 06 86 16 c6 61 40 a0 50 00 92 b0 ..VgB....a@.P...
|
||||
| 3152: 07 46 86 52 07 76 86 f6 c6 52 07 46 86 96 e6 70 .F.R.v...R.F...p
|
||||
| 3168: d0 90 50 00 91 d0 07 46 f7 02 06 56 46 76 51 00 ..P....F...VFvQ.
|
||||
| 3184: 80 50 00 92 30 06 26 f7 47 46 f6 d2 06 56 46 76 .P..0.&.GF...VFv
|
||||
| 3200: 50 f0 70 50 00 92 10 07 26 96 76 87 42 06 56 46 P.pP....&.v.B.VF
|
||||
| 3216: 76 50 e0 60 50 00 91 f0 06 c6 56 67 42 06 56 46 vP.`P.....VgB.VF
|
||||
| 3232: 76 50 b0 50 50 00 91 90 06 36 56 e7 46 57 21 70 vP.PP....6V.FW!p
|
||||
| 3248: 40 50 00 93 10 07 57 07 06 57 22 d7 26 96 76 87 @P....W..W..&.v.
|
||||
| 3264: 42 06 36 f7 26 e6 57 21 70 30 50 00 93 10 06 c6 B.6.&.W!p0P.....
|
||||
| 3280: f7 76 57 22 d7 26 96 76 87 42 06 36 f7 26 e6 57 .vW..&.v.B.6.&.W
|
||||
| 3296: 21 60 20 50 00 92 f0 07 57 07 06 57 22 d6 c6 56 !` P....W..W...V
|
||||
| 3312: 60 00 00 c4 24 c0 00 04 2c 80 00 00 00 00 00 04 `...$...,.......
|
||||
| 3328: 2c 80 00 00 00 00 00 00 00 00 00 d0 00 00 00 04 ,...............
|
||||
| 3344: 2c 80 00 00 00 00 00 04 24 80 00 00 00 00 00 00 ,.......$.......
|
||||
| 3360: 00 00 00 e0 00 00 00 04 2c 80 00 04 24 c0 00 04 ........,...$...
|
||||
| 3376: 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ,...............
|
||||
| page 4 offset 12288
|
||||
| 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| end c4.db
|
||||
}]
|
||||
catchsql {
|
||||
UPDATE t1 SET label='x';
|
||||
}
|
||||
} {1 {rtree constraint failed: t1.(y0<=y1)}}
|
||||
do_test rtreefuzz001-310 {
|
||||
catchsql {
|
||||
SELECT rtreecheck('t1');
|
||||
}
|
||||
} {/1 .*corrupt.*/}
|
||||
|
||||
do_test rtreefuzz001-400 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
| size 16384 pagesize 4096 filename c7.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 04 .....@ ........
|
||||
| 32: 00 00 00 00 01 00 00 00 00 00 00 04 00 00 00 04 ................
|
||||
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f ...............O
|
||||
| 112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17 ............^...
|
||||
| 3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72 .....tablet1_par
|
||||
| 3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45 entt1_parent.CRE
|
||||
| 3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61 ATE TABLE .t1_pa
|
||||
| 3792: 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 rent.(nodeno INT
|
||||
| 3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
|
||||
| 3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17 ,parentnode)Q...
|
||||
| 3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65 ....tablet1_node
|
||||
| 3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54 t1_node.CREATE T
|
||||
| 3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e ABLE .t1_node.(n
|
||||
| 3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52 odeno INTEGER PR
|
||||
| 3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c IMARY KEY,data).
|
||||
| 3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f ........tablet1_
|
||||
| 3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52 rowidt1_rowid.CR
|
||||
| 3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72 EATE TABLE .t1_r
|
||||
| 3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE
|
||||
| 3984: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY,
|
||||
| 4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07 nodeno,a0,a1)Q..
|
||||
| 4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43 ......tablet1t1C
|
||||
| 4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA
|
||||
| 4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 BLE t1 USING rtr
|
||||
| 4064: 65 65 28 69 64 2c 78 30 2c 78 31 2c 79 30 2c 79 ee(id,x0,x1,y0,y
|
||||
| 4080: 31 2c 2b 6c 61 62 65 6c 2c 2b 6f 74 68 65 72 29 1,+label,+other)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 00 00 00 0e 0e f7 00 0f e8 0f d0 0f b7 0f 9e ................
|
||||
| 16: 0f 91 0f 81 0f 70 0f 5e 0f 4f 0f 39 0f 29 0f 18 .....p.^.O.9.)..
|
||||
| 32: 0f 06 0e f7 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3824: 00 00 00 00 00 00 00 0d 0e 05 00 09 1d 00 74 6f ..............to
|
||||
| 3840: 70 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74 p half.....#.bot
|
||||
| 3856: 74 6f 6d 20 68 61 6c 66 0f 0c 05 00 09 21 00 72 tom half.....!.r
|
||||
| 3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00 ight half.......
|
||||
| 3888: 6c 65 66 74 20 68 61 6c 66 14 0a 05 00 09 2b 00 left half.....+.
|
||||
| 3904: 74 68 65 20 77 68 6f 6c 65 20 74 68 69 6e 67 0d the whole thing.
|
||||
| 3920: 09 05 00 09 1d 00 74 6f 70 20 65 64 67 65 10 08 ......top edge..
|
||||
| 3936: 05 00 09 23 00 62 6f 74 74 6f 6d 20 65 64 67 65 ...#.bottom edge
|
||||
| 3952: 0f 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 .....!.right edg
|
||||
| 3968: 65 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 e.......left edg
|
||||
| 3984: 65 0b 05 05 00 09 19 00 23 65 6e 74 65 72 17 04 e.......#enter..
|
||||
| 4000: 05 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 ...1.upper-right
|
||||
| 4016: 20 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f corner.....1.lo
|
||||
| 4032: 77 65 72 2d 72 69 67 68 74 20 63 6f 72 6e 65 72 wer-right corner
|
||||
| 4048: 16 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 ...../.upper-lef
|
||||
| 4064: 74 20 63 6f 72 6e 65 72 16 01 05 00 09 2f 00 6c t corner...../.l
|
||||
| 4080: 6f 77 65 72 2d 6c 65 66 74 20 63 6f 72 6e 65 72 ower-left corner
|
||||
| page 3 offset 8192
|
||||
| 0: 0d 00 00 00 02 0b 2d 00 0b 2d 00 00 00 00 00 00 ......-..-......
|
||||
| 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 01 ..............P.
|
||||
| 2864: 04 00 93 24 00 00 00 00 00 00 00 00 08 00 00 00 ...$............
|
||||
| 2880: 00 42 c8 00 00 00 00 00 00 40 a0 00 00 00 00 00 .B.......@......
|
||||
| 2896: 00 00 00 00 42 c8 00 00 00 00 00 00 00 00 00 07 ....B...........
|
||||
| 2912: 42 be 00 00 42 c8 00 00 00 00 00 00 42 c8 00 00 B...B.......B...
|
||||
| 2928: 00 00 00 00 00 00 00 08 00 00 00 00 42 c8 00 00 ............B...
|
||||
| 2944: 00 00 00 00 40 a0 00 00 00 00 00 00 00 00 00 09 ....@...........
|
||||
| 2960: 00 00 00 00 42 c8 00 00 42 be 00 00 42 c8 00 00 ....B...B...B...
|
||||
| 2976: 00 00 00 00 00 00 00 0a 00 00 00 00 42 c8 00 00 ............B...
|
||||
| 2992: 00 00 00 00 42 c8 00 00 00 00 00 00 00 00 00 0b ....B...........
|
||||
| 3008: 00 00 00 00 42 48 00 00 00 00 00 04 2c 80 00 00 ....BH......,...
|
||||
| 3024: 00 00 00 00 00 00 00 c4 00 00 00 00 00 42 c8 00 .............B..
|
||||
| 3040: 00 00 00 00 00 00 00 00 07 42 be 00 00 42 c8 00 .........B...B..
|
||||
| 3056: 00 00 00 00 00 42 c8 00 00 00 00 00 00 00 00 00 .....B..........
|
||||
| 3072: 08 00 00 00 00 42 c8 00 00 00 00 00 00 40 a0 00 .....B.......@..
|
||||
| 3088: 00 00 00 00 00 00 00 00 09 00 00 00 00 42 c8 00 .............B..
|
||||
| 3104: 00 42 be 00 00 42 c8 00 00 00 00 00 00 00 00 00 .B...B..........
|
||||
| 3120: 0a 00 00 00 00 42 c8 00 00 00 00 00 00 42 c8 00 .....B.......B..
|
||||
| 3136: 00 00 00 00 00 00 00 00 0b 00 00 00 00 42 48 00 .............BH.
|
||||
| 3152: 00 00 00 00 04 2c 80 00 00 00 00 00 00 00 00 00 .....,..........
|
||||
| 3168: c4 24 c0 00 04 2c 80 00 00 00 00 00 04 2c 80 00 .$...,.......,..
|
||||
| 3184: 00 00 00 00 00 00 00 00 d0 00 00 00 04 2c 80 00 .............,..
|
||||
| 3200: 00 00 00 00 04 24 80 00 00 00 00 00 00 00 00 00 .....$..........
|
||||
| 3216: e0 00 00 00 04 2c 80 00 04 24 c0 00 04 2c 00 00 .....,...$...,..
|
||||
| page 4 offset 12288
|
||||
| 0: 0d 00 00 00 00 10 00 00 00 00 00 00 0e 00 00 00 ................
|
||||
| 16: 00 42 c8 00 00 42 4c 00 00 42 c8 00 00 00 00 00 .B...BL..B......
|
||||
| 32: 00 00 00 0a 00 00 00 00 42 c8 00 00 00 00 00 00 ........B.......
|
||||
| 48: 42 c8 00 00 00 00 00 00 00 00 00 0b 00 00 00 00 B...............
|
||||
| 64: 42 48 00 00 00 00 00 04 2c 80 00 00 00 00 00 00 BH......,.......
|
||||
| 80: 00 00 00 c4 24 c0 00 04 2c 80 00 00 00 00 00 04 ....$...,.......
|
||||
| 96: 2c 80 00 00 00 00 00 00 00 00 00 d0 00 00 00 04 ,...............
|
||||
| 112: 2c 80 00 00 00 00 00 04 24 80 00 00 00 00 00 00 ,.......$.......
|
||||
| 128: 00 00 00 e0 00 00 00 04 2c 80 00 04 24 c0 00 04 ........,...$...
|
||||
| 144: 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ,...............
|
||||
| end c7.db
|
||||
}]
|
||||
catchsql {
|
||||
WITH RECURSIVE
|
||||
c1(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c1 WHERE x<8),
|
||||
c2(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM c2 WHERE y<5)
|
||||
INSERT INTO t1(id, x0,x1,y0,y1,label)
|
||||
SELECT 1000+x+y*100, x, x+1, y, y+1, printf('box-%d,%d',x,y) FROM c1, c2;
|
||||
}
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
finish_test
|
||||
@@ -42,7 +42,7 @@ static void usage(const char *argv0){
|
||||
*/
|
||||
static void readFile(const char *zFilename, int *pSz, void **ppBuf){
|
||||
FILE *f;
|
||||
int sz;
|
||||
sqlite3_int64 sz;
|
||||
void *pBuf;
|
||||
f = fopen(zFilename, "rb");
|
||||
if( f==0 ){
|
||||
@@ -50,9 +50,9 @@ static void readFile(const char *zFilename, int *pSz, void **ppBuf){
|
||||
exit(1);
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
sz = (int)ftell(f);
|
||||
sz = ftell(f);
|
||||
rewind(f);
|
||||
pBuf = sqlite3_malloc( sz ? sz : 1 );
|
||||
pBuf = sqlite3_malloc64( sz ? sz : 1 );
|
||||
if( pBuf==0 ){
|
||||
fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n",
|
||||
sz, zFilename);
|
||||
|
||||
@@ -141,7 +141,7 @@ static void usage(const char *argv0){
|
||||
*/
|
||||
static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){
|
||||
FILE *f;
|
||||
int sz;
|
||||
sqlite3_int64 sz;
|
||||
void *pBuf;
|
||||
f = fopen(zFilename, "rb");
|
||||
if( f==0 ){
|
||||
@@ -149,9 +149,9 @@ static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){
|
||||
exit(1);
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
sz = (int)ftell(f);
|
||||
sz = ftell(f);
|
||||
rewind(f);
|
||||
pBuf = sqlite3_malloc( sz ? sz : 1 );
|
||||
pBuf = sqlite3_malloc64( sz ? sz : 1 );
|
||||
if( pBuf==0 ){
|
||||
fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n",
|
||||
sz, zFilename);
|
||||
@@ -340,8 +340,8 @@ struct FuzzChange {
|
||||
/*
|
||||
** Allocate and return nByte bytes of zeroed memory.
|
||||
*/
|
||||
static void *fuzzMalloc(int nByte){
|
||||
void *pRet = sqlite3_malloc(nByte);
|
||||
static void *fuzzMalloc(sqlite3_int64 nByte){
|
||||
void *pRet = sqlite3_malloc64(nByte);
|
||||
if( pRet ){
|
||||
memset(pRet, 0, nByte);
|
||||
}
|
||||
@@ -631,7 +631,7 @@ static int fuzzParseChangeset(
|
||||
/* If the table-header was successfully parsed, add the new change-group
|
||||
** to the array and parse the associated changes. */
|
||||
if( rc==SQLITE_OK ){
|
||||
FuzzChangesetGroup **apNew = (FuzzChangesetGroup**)sqlite3_realloc(
|
||||
FuzzChangesetGroup **apNew = (FuzzChangesetGroup**)sqlite3_realloc64(
|
||||
pParse->apGroup, sizeof(FuzzChangesetGroup*)*(pParse->nGroup+1)
|
||||
);
|
||||
if( apNew==0 ){
|
||||
@@ -1214,7 +1214,7 @@ int main(int argc, char **argv){
|
||||
fuzzPrintGroup(&changeset, changeset.apGroup[i]);
|
||||
}
|
||||
}else{
|
||||
pBuf = (u8*)fuzzMalloc(nChangeset*2 + 1024);
|
||||
pBuf = (u8*)fuzzMalloc((sqlite3_int64)nChangeset*2 + 1024);
|
||||
if( pBuf==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1237,4 +1237,3 @@ int main(int argc, char **argv){
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -356,5 +356,3 @@ int main(int argc, char **argv){
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+60
-16
@@ -30,27 +30,71 @@ proc test_reset {} {
|
||||
sqlite3 db2 test.db2
|
||||
}
|
||||
|
||||
foreach {tn wo} {
|
||||
1 ""
|
||||
2 "WITHOUT ROWID"
|
||||
} {
|
||||
reset_db
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT ROWID;
|
||||
do_execsql_test 1.$tn.0 "CREATE TABLE t1(a PRIMARY KEY, b) $wo ;"
|
||||
|
||||
do_iterator_test 1.$tn.1 t1 {
|
||||
INSERT INTO t1 VALUES('one', 'two');
|
||||
} {
|
||||
{INSERT t1 0 X. {} {t one t two}}
|
||||
}
|
||||
|
||||
do_iterator_test 1.$tn.2 t1 {
|
||||
UPDATE t1 SET b='three'
|
||||
} {
|
||||
{UPDATE t1 0 X. {t one t two} {{} {} t three}}
|
||||
}
|
||||
|
||||
do_iterator_test 1.$tn.3 t1 {
|
||||
REPLACE INTO t1 VALUES('one', 'four');
|
||||
} {
|
||||
{UPDATE t1 0 X. {t one t three} {{} {} t four}}
|
||||
}
|
||||
|
||||
do_iterator_test 1.$tn.4 t1 {
|
||||
DELETE FROM t1;
|
||||
} {
|
||||
{DELETE t1 0 X. {t one t four} {}}
|
||||
}
|
||||
}
|
||||
|
||||
do_iterator_test 1.1 t1 {
|
||||
INSERT INTO t1 VALUES('one', 'two');
|
||||
foreach {tn wo} {
|
||||
1 ""
|
||||
2 "WITHOUT ROWID"
|
||||
} {
|
||||
{INSERT t1 0 X. {} {t one t two}}
|
||||
}
|
||||
reset_db
|
||||
|
||||
do_iterator_test 1.2 t1 {
|
||||
UPDATE t1 SET b='three'
|
||||
} {
|
||||
{UPDATE t1 0 X. {t one t two} {{} {} t three}}
|
||||
}
|
||||
|
||||
do_iterator_test 1.3 t1 {
|
||||
DELETE FROM t1;
|
||||
} {
|
||||
{DELETE t1 0 X. {t one t three} {}}
|
||||
do_execsql_test 2.$tn.0 "CREATE TABLE t1(a INTEGER PRIMARY KEY, b) $wo ;"
|
||||
|
||||
do_iterator_test 1.1 t1 {
|
||||
INSERT INTO t1 VALUES(1, 'two');
|
||||
} {
|
||||
{INSERT t1 0 X. {} {i 1 t two}}
|
||||
}
|
||||
|
||||
do_iterator_test 2.$tn.2 t1 {
|
||||
UPDATE t1 SET b='three'
|
||||
} {
|
||||
{UPDATE t1 0 X. {i 1 t two} {{} {} t three}}
|
||||
}
|
||||
|
||||
do_iterator_test 2.$tn.3 t1 {
|
||||
REPLACE INTO t1 VALUES(1, 'four');
|
||||
} {
|
||||
{UPDATE t1 0 X. {i 1 t three} {{} {} t four}}
|
||||
}
|
||||
|
||||
do_iterator_test 2.$tn.4 t1 {
|
||||
DELETE FROM t1;
|
||||
} {
|
||||
{DELETE t1 0 X. {i 1 t four} {}}
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
|
||||
static int sessionSerializeValue(
|
||||
u8 *aBuf, /* If non-NULL, write serialized value here */
|
||||
sqlite3_value *pValue, /* Value to serialize */
|
||||
int *pnWrite /* IN/OUT: Increment by bytes written */
|
||||
sqlite3_int64 *pnWrite /* IN/OUT: Increment by bytes written */
|
||||
){
|
||||
int nByte; /* Size of serialized value in bytes */
|
||||
|
||||
@@ -904,7 +904,7 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){
|
||||
SessionChange **apNew;
|
||||
int nNew = (pTab->nChange ? pTab->nChange : 128) * 2;
|
||||
|
||||
apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
|
||||
apNew = (SessionChange **)sqlite3_malloc64(sizeof(SessionChange *) * nNew);
|
||||
if( apNew==0 ){
|
||||
if( pTab->nChange==0 ){
|
||||
return SQLITE_ERROR;
|
||||
@@ -970,7 +970,7 @@ static int sessionTableInfo(
|
||||
char *zPragma;
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
int nByte;
|
||||
sqlite3_int64 nByte;
|
||||
int nDbCol = 0;
|
||||
int nThis;
|
||||
int i;
|
||||
@@ -1013,7 +1013,7 @@ static int sessionTableInfo(
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
|
||||
pAlloc = sqlite3_malloc(nByte);
|
||||
pAlloc = sqlite3_malloc64(nByte);
|
||||
if( pAlloc==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
@@ -1154,7 +1154,7 @@ static void sessionPreupdateOneChange(
|
||||
int iHash;
|
||||
int bNull = 0;
|
||||
int rc = SQLITE_OK;
|
||||
SessionStat1Ctx stat1 = {0};
|
||||
SessionStat1Ctx stat1 = {{0,0,0,0,0},0};
|
||||
|
||||
if( pSession->rc ) return;
|
||||
|
||||
@@ -1211,7 +1211,7 @@ static void sessionPreupdateOneChange(
|
||||
** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
|
||||
** values (if this is an INSERT). */
|
||||
SessionChange *pChange; /* New change object */
|
||||
int nByte; /* Number of bytes to allocate */
|
||||
sqlite3_int64 nByte; /* Number of bytes to allocate */
|
||||
int i; /* Used to iterate through columns */
|
||||
|
||||
assert( rc==SQLITE_OK );
|
||||
@@ -1236,7 +1236,7 @@ static void sessionPreupdateOneChange(
|
||||
}
|
||||
|
||||
/* Allocate the change object */
|
||||
pChange = (SessionChange *)sqlite3_malloc(nByte);
|
||||
pChange = (SessionChange *)sqlite3_malloc64(nByte);
|
||||
if( !pChange ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto error_out;
|
||||
@@ -1680,7 +1680,7 @@ int sqlite3session_create(
|
||||
*ppSession = 0;
|
||||
|
||||
/* Allocate and populate the new session object. */
|
||||
pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
|
||||
pNew = (sqlite3_session *)sqlite3_malloc64(sizeof(sqlite3_session) + nDb + 1);
|
||||
if( !pNew ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(sqlite3_session));
|
||||
pNew->db = db;
|
||||
@@ -1799,7 +1799,7 @@ int sqlite3session_attach(
|
||||
|
||||
if( !pTab ){
|
||||
/* Allocate new SessionTable object. */
|
||||
pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
|
||||
pTab = (SessionTable *)sqlite3_malloc64(sizeof(SessionTable) + nName + 1);
|
||||
if( !pTab ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -1859,7 +1859,7 @@ static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
|
||||
static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){
|
||||
int rc = *pRc;
|
||||
if( rc==SQLITE_OK ){
|
||||
int nByte = 0;
|
||||
sqlite3_int64 nByte = 0;
|
||||
rc = sessionSerializeValue(0, pVal, &nByte);
|
||||
sessionBufferGrow(p, nByte, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -2735,7 +2735,7 @@ static int sessionValueSetStr(
|
||||
** argument to sqlite3ValueSetStr() and have the copy created
|
||||
** automatically. But doing so makes it difficult to detect any OOM
|
||||
** error. Hence the code to create the copy externally. */
|
||||
u8 *aCopy = sqlite3_malloc(nData+1);
|
||||
u8 *aCopy = sqlite3_malloc64((sqlite3_int64)nData+1);
|
||||
if( aCopy==0 ) return SQLITE_NOMEM;
|
||||
memcpy(aCopy, aData, nData);
|
||||
sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free);
|
||||
@@ -3348,7 +3348,7 @@ static int sessionChangesetInvert(
|
||||
int iCol;
|
||||
|
||||
if( 0==apVal ){
|
||||
apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2);
|
||||
apVal = (sqlite3_value **)sqlite3_malloc64(sizeof(apVal[0])*nCol*2);
|
||||
if( 0==apVal ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto finished_invert;
|
||||
@@ -4621,7 +4621,7 @@ static int sessionChangeMerge(
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( !pExist ){
|
||||
pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec);
|
||||
pNew = (SessionChange *)sqlite3_malloc64(sizeof(SessionChange) + nRec);
|
||||
if( !pNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -4654,8 +4654,8 @@ static int sessionChangeMerge(
|
||||
if( pExist->op==SQLITE_DELETE && pExist->bIndirect ){
|
||||
*ppNew = pExist;
|
||||
}else{
|
||||
int nByte = nRec + pExist->nRecord + sizeof(SessionChange);
|
||||
pNew = (SessionChange*)sqlite3_malloc(nByte);
|
||||
sqlite3_int64 nByte = nRec + pExist->nRecord + sizeof(SessionChange);
|
||||
pNew = (SessionChange*)sqlite3_malloc64(nByte);
|
||||
if( pNew==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -4715,14 +4715,14 @@ static int sessionChangeMerge(
|
||||
assert( pNew==0 );
|
||||
}else{
|
||||
u8 *aExist = pExist->aRecord;
|
||||
int nByte;
|
||||
sqlite3_int64 nByte;
|
||||
u8 *aCsr;
|
||||
|
||||
/* Allocate a new SessionChange object. Ensure that the aRecord[]
|
||||
** buffer of the new object is large enough to hold any record that
|
||||
** may be generated by combining the input records. */
|
||||
nByte = sizeof(SessionChange) + pExist->nRecord + nRec;
|
||||
pNew = (SessionChange *)sqlite3_malloc(nByte);
|
||||
pNew = (SessionChange *)sqlite3_malloc64(nByte);
|
||||
if( !pNew ){
|
||||
sqlite3_free(pExist);
|
||||
return SQLITE_NOMEM;
|
||||
@@ -4828,7 +4828,7 @@ static int sessionChangesetToHash(
|
||||
if( !pTab ){
|
||||
SessionTable **ppTab;
|
||||
|
||||
pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1);
|
||||
pTab = sqlite3_malloc64(sizeof(SessionTable) + nCol + nNew+1);
|
||||
if( !pTab ){
|
||||
rc = SQLITE_NOMEM;
|
||||
break;
|
||||
|
||||
@@ -548,7 +548,7 @@ int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
|
||||
** sqlite3changeset_next() is called on the iterator or until the
|
||||
** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
|
||||
** set to the number of columns in the table affected by the change. If
|
||||
** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
|
||||
** pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change
|
||||
** is an indirect change, or false (0) otherwise. See the documentation for
|
||||
** [sqlite3session_indirect()] for a description of direct and indirect
|
||||
** changes. Finally, if pOp is not NULL, then *pOp is set to one of
|
||||
|
||||
@@ -369,6 +369,7 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/nextchar.c \
|
||||
$(TOP)/ext/misc/normalize.c \
|
||||
$(TOP)/ext/misc/percentile.c \
|
||||
$(TOP)/ext/misc/prefixes.c \
|
||||
$(TOP)/ext/misc/regexp.c \
|
||||
$(TOP)/ext/misc/remember.c \
|
||||
$(TOP)/ext/misc/series.c \
|
||||
@@ -509,7 +510,8 @@ FUZZDATA = \
|
||||
$(TOP)/test/fuzzdata4.db \
|
||||
$(TOP)/test/fuzzdata5.db \
|
||||
$(TOP)/test/fuzzdata6.db \
|
||||
$(TOP)/test/fuzzdata7.db
|
||||
$(TOP)/test/fuzzdata7.db \
|
||||
$(TOP)/test/fuzzdata8.db
|
||||
|
||||
# Standard options to testfixture
|
||||
#
|
||||
@@ -530,6 +532,11 @@ FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
|
||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_DESERIALIZE
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
DBFUZZ_OPT =
|
||||
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
ST_OPT = -DSQLITE_THREADSAFE=0
|
||||
@@ -574,6 +581,20 @@ dbfuzz$(EXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h
|
||||
$(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c \
|
||||
$(TLIBS) $(THREADLIB)
|
||||
|
||||
DBFUZZ2_OPTS = \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_ENABLE_DESERIALIZE \
|
||||
-DSQLITE_DEBUG \
|
||||
-DSQLITE_ENABLE_DBSTAT_VTAB \
|
||||
-DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_ENABLE_FTS4 \
|
||||
-DSQLITE_ENABLE_FTS5
|
||||
|
||||
dbfuzz2$(EXE): $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
|
||||
$(TCCX) -I. -g -O0 -DSTANDALONE -o dbfuzz2$(EXE) \
|
||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS) $(THREADLIB)
|
||||
|
||||
fuzzcheck$(EXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h $(TOP)/test/ossfuzz.c
|
||||
$(TCCX) -o fuzzcheck$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_ENABLE_MEMSYS5 $(FUZZCHECK_OPT) -DSQLITE_OSS_FUZZ \
|
||||
@@ -719,6 +740,7 @@ SHELL_SRC = \
|
||||
$(TOP)/ext/expert/sqlite3expert.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.h \
|
||||
$(TOP)/ext/misc/zipfile.c \
|
||||
$(TOP)/ext/misc/memtrace.c \
|
||||
$(TOP)/src/test_windirent.c
|
||||
|
||||
shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
|
||||
@@ -976,6 +998,9 @@ $(TEST_EXTENSION): $(TOP)/src/test_loadext.c
|
||||
extensiontest: testfixture$(EXE) $(TEST_EXTENSION)
|
||||
./testfixture$(EXE) $(TOP)/test/loadext.test
|
||||
|
||||
dbtotxt$(EXE): $(TOP)/tool/dbtotxt.c
|
||||
$(TCC) -o dbtotxt$(EXE) $(TOP)/tool/dbtotxt.c
|
||||
|
||||
showdb$(EXE): $(TOP)/tool/showdb.c sqlite3.o
|
||||
$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o showdb$(EXE) \
|
||||
$(TOP)/tool/showdb.c sqlite3.o $(THREADLIB)
|
||||
@@ -995,6 +1020,10 @@ showwal$(EXE): $(TOP)/tool/showwal.c sqlite3.o
|
||||
showshm$(EXE): $(TOP)/tool/showshm.c
|
||||
$(TCC) -o showshm$(EXE) $(TOP)/tool/showshm.c
|
||||
|
||||
index_usage$(EXE): $(TOP)/tool/index_usage.c sqlite3.o
|
||||
$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_DEPRECATED $(SHELL_OPTS) -o index_usage$(EXE) \
|
||||
$(TOP)/tool/index_usage.c sqlite3.o $(THREADLIB)
|
||||
|
||||
changeset$(EXE): $(TOP)/ext/session/changeset.c sqlite3.o
|
||||
$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o changeset$(EXE) \
|
||||
$(TOP)/ext/session/changeset.c sqlite3.o $(THREADLIB)
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
bf8c1b2b7a5960c282e543b9c293686dccff272512d08865f4600fb58238b4f9
|
||||
bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0f6d7
|
||||
|
||||
+46
-10
@@ -28,9 +28,16 @@
|
||||
**
|
||||
** Or, if zName is not a system table, zero is returned.
|
||||
*/
|
||||
static int isSystemTable(Parse *pParse, const char *zName){
|
||||
if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be altered", zName);
|
||||
static int isAlterableTable(Parse *pParse, Table *pTab){
|
||||
if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7)
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|| ( (pTab->tabFlags & TF_Shadow)
|
||||
&& (pParse->db->flags & SQLITE_Defensive)
|
||||
&& pParse->db->nVdbeExec==0
|
||||
)
|
||||
#endif
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -126,7 +133,7 @@ void sqlite3AlterRenameTable(
|
||||
/* Make sure it is not a system table being altered, or a reserved name
|
||||
** that the table is being renamed to.
|
||||
*/
|
||||
if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){
|
||||
if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
|
||||
goto exit_rename_table;
|
||||
}
|
||||
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto
|
||||
@@ -424,7 +431,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a column to a view");
|
||||
goto exit_begin_add_column;
|
||||
}
|
||||
if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){
|
||||
if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
|
||||
goto exit_begin_add_column;
|
||||
}
|
||||
|
||||
@@ -526,7 +533,7 @@ void sqlite3AlterRenameColumn(
|
||||
if( !pTab ) goto exit_rename_column;
|
||||
|
||||
/* Cannot alter a system table */
|
||||
if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column;
|
||||
if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column;
|
||||
if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column;
|
||||
|
||||
/* Which schema holds the table to be altered */
|
||||
@@ -780,14 +787,31 @@ static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Iterate through the Select objects that are part of WITH clauses attached
|
||||
** to select statement pSelect.
|
||||
*/
|
||||
static void renameWalkWith(Walker *pWalker, Select *pSelect){
|
||||
if( pSelect->pWith ){
|
||||
int i;
|
||||
for(i=0; i<pSelect->pWith->nCte; i++){
|
||||
Select *p = pSelect->pWith->a[i].pSelect;
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pWalker->pParse;
|
||||
sqlite3SelectPrep(sNC.pParse, p, &sNC);
|
||||
sqlite3WalkSelect(pWalker, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This is a Walker select callback. It does nothing. It is only required
|
||||
** because without a dummy callback, sqlite3WalkExpr() and similar do not
|
||||
** descend into sub-select statements.
|
||||
*/
|
||||
static int renameColumnSelectCb(Walker *pWalker, Select *p){
|
||||
UNUSED_PARAMETER(pWalker);
|
||||
UNUSED_PARAMETER(p);
|
||||
renameWalkWith(pWalker, p);
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
@@ -937,7 +961,6 @@ static int renameParseSql(
|
||||
rc = sqlite3RunParser(p, zSql, &zErr);
|
||||
assert( p->zErrMsg==0 );
|
||||
assert( rc!=SQLITE_OK || zErr==0 );
|
||||
assert( (0!=p->pNewTable) + (0!=p->pNewIndex) + (0!=p->pNewTrigger)<2 );
|
||||
p->zErrMsg = zErr;
|
||||
if( db->mallocFailed ) rc = SQLITE_NOMEM;
|
||||
if( rc==SQLITE_OK
|
||||
@@ -1120,6 +1143,7 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
|
||||
}
|
||||
sNC.ncFlags = 0;
|
||||
}
|
||||
sNC.pSrcList = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1157,11 +1181,15 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
|
||||
*/
|
||||
static void renameParseCleanup(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
Index *pIdx;
|
||||
if( pParse->pVdbe ){
|
||||
sqlite3VdbeFinalize(pParse->pVdbe);
|
||||
}
|
||||
sqlite3DeleteTable(db, pParse->pNewTable);
|
||||
if( pParse->pNewIndex ) sqlite3FreeIndex(db, pParse->pNewIndex);
|
||||
while( (pIdx = pParse->pNewIndex)!=0 ){
|
||||
pParse->pNewIndex = pIdx->pNext;
|
||||
sqlite3FreeIndex(db, pIdx);
|
||||
}
|
||||
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
||||
sqlite3DbFree(db, pParse->zErrMsg);
|
||||
renameTokenFree(db, pParse->pRename);
|
||||
@@ -1272,6 +1300,9 @@ static void renameColumnFunc(
|
||||
for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
|
||||
}
|
||||
for(pIdx=sParse.pNewIndex; pIdx; pIdx=pIdx->pNext){
|
||||
sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
|
||||
}
|
||||
}
|
||||
|
||||
for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
||||
@@ -1358,12 +1389,17 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
|
||||
int i;
|
||||
RenameCtx *p = pWalker->u.pRename;
|
||||
SrcList *pSrc = pSelect->pSrc;
|
||||
if( pSrc==0 ){
|
||||
assert( pWalker->pParse->db->mallocFailed );
|
||||
return WRC_Abort;
|
||||
}
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
struct SrcList_item *pItem = &pSrc->a[i];
|
||||
if( pItem->pTab==p->pTab ){
|
||||
renameTokenFind(pWalker->pParse, p, pItem->zName);
|
||||
}
|
||||
}
|
||||
renameWalkWith(pWalker, pSelect);
|
||||
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1156,7 +1156,7 @@ static void analyzeOneTable(
|
||||
addrNextRow = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
if( nColTest>0 ){
|
||||
int endDistinctTest = sqlite3VdbeMakeLabel(v);
|
||||
int endDistinctTest = sqlite3VdbeMakeLabel(pParse);
|
||||
int *aGotoChng; /* Array of jump instruction addresses */
|
||||
aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest);
|
||||
if( aGotoChng==0 ) continue;
|
||||
|
||||
+9
-6
@@ -155,8 +155,8 @@ static void attachFunc(
|
||||
assert( pVfs );
|
||||
flags |= SQLITE_OPEN_MAIN_DB;
|
||||
rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
|
||||
sqlite3_free( zPath );
|
||||
db->nDb++;
|
||||
pNew->zDbSName = sqlite3DbStrDup(db, zName);
|
||||
}
|
||||
db->noSharedCache = 0;
|
||||
if( rc==SQLITE_CONSTRAINT ){
|
||||
@@ -184,7 +184,6 @@ static void attachFunc(
|
||||
sqlite3BtreeLeave(pNew->pBt);
|
||||
}
|
||||
pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
|
||||
if( !REOPEN_AS_MEMDB(db) ) pNew->zDbSName = sqlite3DbStrDup(db, zName);
|
||||
if( rc==SQLITE_OK && pNew->zDbSName==0 ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
@@ -212,15 +211,19 @@ static void attachFunc(
|
||||
break;
|
||||
|
||||
case SQLITE_NULL:
|
||||
/* No key specified. Use the key from the main database */
|
||||
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
|
||||
if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
|
||||
rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
||||
/* No key specified. Use the key from URI filename, or if none,
|
||||
** use the key from the main database. */
|
||||
if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){
|
||||
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
|
||||
if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
|
||||
rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sqlite3_free( zPath );
|
||||
|
||||
/* If the file was opened successfully, read the schema for the new database.
|
||||
** If this fails, or if opening the file failed, then close the file and
|
||||
|
||||
@@ -153,6 +153,26 @@ sqlite3_backup *sqlite3_backup_init(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* BEGIN SQLCIPHER */
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
{
|
||||
extern int sqlcipher_find_db_index(sqlite3*, const char*);
|
||||
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
||||
int srcNKey, destNKey;
|
||||
void *zKey;
|
||||
|
||||
sqlite3CodecGetKey(pSrcDb, sqlcipher_find_db_index(pSrcDb, zSrcDb), &zKey, &srcNKey);
|
||||
sqlite3CodecGetKey(pDestDb, sqlcipher_find_db_index(pDestDb, zDestDb), &zKey, &destNKey);
|
||||
zKey = NULL;
|
||||
|
||||
if(srcNKey || destNKey) {
|
||||
sqlite3ErrorWithMsg(pDestDb, SQLITE_ERROR, "backup is not supported with encrypted databases");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* END SQLCIPHER */
|
||||
|
||||
/* Lock the source database handle. The destination database
|
||||
** handle is not locked in this routine, but it is locked in
|
||||
** sqlite3_backup_step(). The user is required to ensure that no
|
||||
|
||||
+278
-123
@@ -660,13 +660,19 @@ static int saveCursorKey(BtCursor *pCur){
|
||||
/* Only the rowid is required for a table btree */
|
||||
pCur->nKey = sqlite3BtreeIntegerKey(pCur);
|
||||
}else{
|
||||
/* For an index btree, save the complete key content */
|
||||
/* For an index btree, save the complete key content. It is possible
|
||||
** that the current key is corrupt. In that case, it is possible that
|
||||
** the sqlite3VdbeRecordUnpack() function may overread the buffer by
|
||||
** up to the size of 1 varint plus 1 8-byte value when the cursor
|
||||
** position is restored. Hence the 17 bytes of padding allocated
|
||||
** below. */
|
||||
void *pKey;
|
||||
pCur->nKey = sqlite3BtreePayloadSize(pCur);
|
||||
pKey = sqlite3Malloc( pCur->nKey );
|
||||
pKey = sqlite3Malloc( pCur->nKey + 9 + 8 );
|
||||
if( pKey ){
|
||||
rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey);
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(((u8*)pKey)+pCur->nKey, 0, 9+8);
|
||||
pCur->pKey = pKey;
|
||||
}else{
|
||||
sqlite3_free(pKey);
|
||||
@@ -798,11 +804,12 @@ static int btreeMoveto(
|
||||
UnpackedRecord *pIdxKey; /* Unpacked index key */
|
||||
|
||||
if( pKey ){
|
||||
KeyInfo *pKeyInfo = pCur->pKeyInfo;
|
||||
assert( nKey==(i64)(int)nKey );
|
||||
pIdxKey = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo);
|
||||
pIdxKey = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
|
||||
if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
|
||||
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
|
||||
if( pIdxKey->nField==0 ){
|
||||
sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey);
|
||||
if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto moveto_done;
|
||||
}
|
||||
@@ -838,7 +845,7 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){
|
||||
sqlite3_free(pCur->pKey);
|
||||
pCur->pKey = 0;
|
||||
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );
|
||||
pCur->skipNext |= skipNext;
|
||||
if( skipNext ) pCur->skipNext = skipNext;
|
||||
if( pCur->skipNext && pCur->eState==CURSOR_VALID ){
|
||||
pCur->eState = CURSOR_SKIPNEXT;
|
||||
}
|
||||
@@ -908,7 +915,6 @@ int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
*pDifferentRow = 1;
|
||||
}else{
|
||||
assert( pCur->skipNext==0 );
|
||||
*pDifferentRow = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
@@ -992,6 +998,13 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
|
||||
*pRC = rc;
|
||||
return;
|
||||
}
|
||||
if( ((char*)sqlite3PagerGetExtra(pDbPage))[0]!=0 ){
|
||||
/* The first byte of the extra data is the MemPage.isInit byte.
|
||||
** If that byte is set, it means this page is also being used
|
||||
** as a btree page. */
|
||||
*pRC = SQLITE_CORRUPT_BKPT;
|
||||
goto ptrmap_exit;
|
||||
}
|
||||
offset = PTRMAP_PTROFFSET(iPtrmap, key);
|
||||
if( offset<0 ){
|
||||
*pRC = SQLITE_CORRUPT_BKPT;
|
||||
@@ -1054,7 +1067,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
|
||||
#else /* if defined SQLITE_OMIT_AUTOVACUUM */
|
||||
#define ptrmapPut(w,x,y,z,rc)
|
||||
#define ptrmapGet(w,x,y,z) SQLITE_OK
|
||||
#define ptrmapPutOvflPtr(x, y, rc)
|
||||
#define ptrmapPutOvflPtr(x, y, z, rc)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -1347,17 +1360,24 @@ static u16 cellSize(MemPage *pPage, int iCell){
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
/*
|
||||
** If the cell pCell, part of page pPage contains a pointer
|
||||
** to an overflow page, insert an entry into the pointer-map
|
||||
** for the overflow page.
|
||||
** The cell pCell is currently part of page pSrc but will ultimately be part
|
||||
** of pPage. (pSrc and pPager are often the same.) If pCell contains a
|
||||
** pointer to an overflow page, insert an entry into the pointer-map for
|
||||
** the overflow page that will be valid after pCell has been moved to pPage.
|
||||
*/
|
||||
static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
|
||||
static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){
|
||||
CellInfo info;
|
||||
if( *pRC ) return;
|
||||
assert( pCell!=0 );
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
if( info.nLocal<info.nPayload ){
|
||||
Pgno ovfl = get4byte(&pCell[info.nSize-4]);
|
||||
Pgno ovfl;
|
||||
if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){
|
||||
testcase( pSrc!=pPage );
|
||||
*pRC = SQLITE_CORRUPT_BKPT;
|
||||
return;
|
||||
}
|
||||
ovfl = get4byte(&pCell[info.nSize-4]);
|
||||
ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
|
||||
}
|
||||
}
|
||||
@@ -1412,19 +1432,14 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
** reconstruct the entire page. */
|
||||
if( (int)data[hdr+7]<=nMaxFrag ){
|
||||
int iFree = get2byte(&data[hdr+1]);
|
||||
|
||||
/* If the initial freeblock offset were out of bounds, that would
|
||||
** have been detected by btreeInitPage() when it was computing the
|
||||
** number of free bytes on the page. */
|
||||
assert( iFree<=usableSize-4 );
|
||||
if( iFree ){
|
||||
int iFree2 = get2byte(&data[iFree]);
|
||||
|
||||
/* pageFindSlot() has already verified that free blocks are sorted
|
||||
** in order of offset within the page, and that no block extends
|
||||
** past the end of the page. Provided the two free slots do not
|
||||
** overlap, this guarantees that the memmove() calls below will not
|
||||
** overwrite the usableSize byte buffer, even if the database page
|
||||
** is corrupt. */
|
||||
assert( iFree2==0 || iFree2>iFree );
|
||||
assert( iFree+get2byte(&data[iFree+2]) <= usableSize );
|
||||
assert( iFree2==0 || iFree2+get2byte(&data[iFree2+2]) <= usableSize );
|
||||
|
||||
if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){
|
||||
u8 *pEnd = &data[cellOffset + nCell*2];
|
||||
u8 *pAddr;
|
||||
@@ -1435,9 +1450,9 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
if( iFree2 ){
|
||||
assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */
|
||||
if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
sz2 = get2byte(&data[iFree2+2]);
|
||||
assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize );
|
||||
if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
|
||||
sz += sz2;
|
||||
}
|
||||
@@ -2992,9 +3007,9 @@ static int newDatabase(BtShared*);
|
||||
static int lockBtree(BtShared *pBt){
|
||||
int rc; /* Result code from subfunctions */
|
||||
MemPage *pPage1; /* Page 1 of the database file */
|
||||
int nPage; /* Number of pages in the database */
|
||||
int nPageFile = 0; /* Number of pages in the database file */
|
||||
int nPageHeader; /* Number of pages in the database according to hdr */
|
||||
u32 nPage; /* Number of pages in the database */
|
||||
u32 nPageFile = 0; /* Number of pages in the database file */
|
||||
u32 nPageHeader; /* Number of pages in the database according to hdr */
|
||||
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
assert( pBt->pPage1==0 );
|
||||
@@ -3007,7 +3022,7 @@ static int lockBtree(BtShared *pBt){
|
||||
** a valid database file.
|
||||
*/
|
||||
nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData);
|
||||
sqlite3PagerPagecount(pBt->pPager, &nPageFile);
|
||||
sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile);
|
||||
if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){
|
||||
nPage = nPageFile;
|
||||
}
|
||||
@@ -3088,6 +3103,7 @@ static int lockBtree(BtShared *pBt){
|
||||
){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
pBt->btsFlags |= BTS_PAGESIZE_FIXED;
|
||||
assert( (pageSize & 7)==0 );
|
||||
/* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte
|
||||
** integer at offset 20 is the number of bytes of space at the end of
|
||||
@@ -3478,7 +3494,7 @@ static int setChildPtrmaps(MemPage *pPage){
|
||||
for(i=0; i<nCell; i++){
|
||||
u8 *pCell = findCell(pPage, i);
|
||||
|
||||
ptrmapPutOvflPtr(pPage, pCell, &rc);
|
||||
ptrmapPutOvflPtr(pPage, pPage, pCell, &rc);
|
||||
|
||||
if( !pPage->leaf ){
|
||||
Pgno childPgno = get4byte(pCell);
|
||||
@@ -4404,6 +4420,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
||||
sqlite3_free(pCur->aOverflow);
|
||||
sqlite3_free(pCur->pKey);
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
pCur->pBtree = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -4502,6 +4519,25 @@ u32 sqlite3BtreePayloadSize(BtCursor *pCur){
|
||||
return pCur->info.nPayload;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return an upper bound on the size of any record for the table
|
||||
** that the cursor is pointing into.
|
||||
**
|
||||
** This is an optimization. Everything will still work if this
|
||||
** routine always returns 2147483647 (which is the largest record
|
||||
** that SQLite can handle) or more. But returning a smaller value might
|
||||
** prevent large memory allocations when trying to interpret a
|
||||
** corrupt datrabase.
|
||||
**
|
||||
** The current implementation merely returns the size of the underlying
|
||||
** database file.
|
||||
*/
|
||||
sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor *pCur){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
return pCur->pBt->pageSize * (sqlite3_int64)pCur->pBt->nPage;
|
||||
}
|
||||
|
||||
/*
|
||||
** Given the page number of an overflow page in the database (parameter
|
||||
** ovfl), this function finds the page number of the next page in the
|
||||
@@ -5316,7 +5352,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
** try to get there using sqlite3BtreeNext() rather than a full
|
||||
** binary search. This is an optimization only. The correct answer
|
||||
** is still obtained without this case, only a little more slowely */
|
||||
if( pCur->info.nKey+1==intKey && !pCur->skipNext ){
|
||||
if( pCur->info.nKey+1==intKey ){
|
||||
*pRes = 0;
|
||||
rc = sqlite3BtreeNext(pCur, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -5458,7 +5494,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */
|
||||
testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */
|
||||
testcase( nCell==2 ); /* Minimum legal index key size */
|
||||
if( nCell<2 ){
|
||||
if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){
|
||||
rc = SQLITE_CORRUPT_PAGE(pPage);
|
||||
goto moveto_finish;
|
||||
}
|
||||
@@ -5590,7 +5626,6 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
|
||||
MemPage *pPage;
|
||||
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
|
||||
rc = restoreCursorPosition(pCur);
|
||||
@@ -5600,14 +5635,9 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
|
||||
if( CURSOR_INVALID==pCur->eState ){
|
||||
return SQLITE_DONE;
|
||||
}
|
||||
if( pCur->skipNext ){
|
||||
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
|
||||
if( pCur->eState==CURSOR_SKIPNEXT ){
|
||||
pCur->eState = CURSOR_VALID;
|
||||
if( pCur->skipNext>0 ){
|
||||
pCur->skipNext = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pCur->skipNext = 0;
|
||||
if( pCur->skipNext>0 ) return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5662,7 +5692,6 @@ int sqlite3BtreeNext(BtCursor *pCur, int flags){
|
||||
UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( flags==0 || flags==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
pCur->info.nSize = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur);
|
||||
@@ -5703,7 +5732,6 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
|
||||
MemPage *pPage;
|
||||
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
|
||||
assert( pCur->info.nSize==0 );
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
@@ -5714,14 +5742,9 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
|
||||
if( CURSOR_INVALID==pCur->eState ){
|
||||
return SQLITE_DONE;
|
||||
}
|
||||
if( pCur->skipNext ){
|
||||
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
|
||||
if( CURSOR_SKIPNEXT==pCur->eState ){
|
||||
pCur->eState = CURSOR_VALID;
|
||||
if( pCur->skipNext<0 ){
|
||||
pCur->skipNext = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pCur->skipNext = 0;
|
||||
if( pCur->skipNext<0 ) return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5756,7 +5779,6 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
|
||||
int sqlite3BtreePrevious(BtCursor *pCur, int flags){
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( flags==0 || flags==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */
|
||||
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
|
||||
pCur->info.nSize = 0;
|
||||
@@ -6092,7 +6114,7 @@ static int allocateBtreePage(
|
||||
TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
|
||||
}
|
||||
|
||||
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
||||
assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
||||
|
||||
end_allocate_page:
|
||||
releasePage(pTrunk);
|
||||
@@ -6647,9 +6669,16 @@ static void insertCell(
|
||||
assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
|
||||
assert( idx+sz <= (int)pPage->pBt->usableSize );
|
||||
pPage->nFree -= (u16)(2 + sz);
|
||||
memcpy(&data[idx], pCell, sz);
|
||||
if( iChild ){
|
||||
/* In a corrupt database where an entry in the cell index section of
|
||||
** a btree page has a value of 3 or less, the pCell value might point
|
||||
** as many as 4 bytes in front of the start of the aData buffer for
|
||||
** the source page. Make sure this does not cause problems by not
|
||||
** reading the first 4 bytes */
|
||||
memcpy(&data[idx+4], pCell+4, sz-4);
|
||||
put4byte(&data[idx], iChild);
|
||||
}else{
|
||||
memcpy(&data[idx], pCell, sz);
|
||||
}
|
||||
pIns = pPage->aCellIdx + i*2;
|
||||
memmove(pIns+2, pIns, 2*(pPage->nCell - i));
|
||||
@@ -6663,15 +6692,89 @@ static void insertCell(
|
||||
/* The cell may contain a pointer to an overflow page. If so, write
|
||||
** the entry for the overflow page into the pointer map.
|
||||
*/
|
||||
ptrmapPutOvflPtr(pPage, pCell, pRC);
|
||||
ptrmapPutOvflPtr(pPage, pPage, pCell, pRC);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The following parameters determine how many adjacent pages get involved
|
||||
** in a balancing operation. NN is the number of neighbors on either side
|
||||
** of the page that participate in the balancing operation. NB is the
|
||||
** total number of pages that participate, including the target page and
|
||||
** NN neighbors on either side.
|
||||
**
|
||||
** The minimum value of NN is 1 (of course). Increasing NN above 1
|
||||
** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance
|
||||
** in exchange for a larger degradation in INSERT and UPDATE performance.
|
||||
** The value of NN appears to give the best results overall.
|
||||
**
|
||||
** (Later:) The description above makes it seem as if these values are
|
||||
** tunable - as if you could change them and recompile and it would all work.
|
||||
** But that is unlikely. NB has been 3 since the inception of SQLite and
|
||||
** we have never tested any other value.
|
||||
*/
|
||||
#define NN 1 /* Number of neighbors on either side of pPage */
|
||||
#define NB 3 /* (NN*2+1): Total pages involved in the balance */
|
||||
|
||||
/*
|
||||
** A CellArray object contains a cache of pointers and sizes for a
|
||||
** consecutive sequence of cells that might be held on multiple pages.
|
||||
**
|
||||
** The cells in this array are the divider cell or cells from the pParent
|
||||
** page plus up to three child pages. There are a total of nCell cells.
|
||||
**
|
||||
** pRef is a pointer to one of the pages that contributes cells. This is
|
||||
** used to access information such as MemPage.intKey and MemPage.pBt->pageSize
|
||||
** which should be common to all pages that contribute cells to this array.
|
||||
**
|
||||
** apCell[] and szCell[] hold, respectively, pointers to the start of each
|
||||
** cell and the size of each cell. Some of the apCell[] pointers might refer
|
||||
** to overflow cells. In other words, some apCel[] pointers might not point
|
||||
** to content area of the pages.
|
||||
**
|
||||
** A szCell[] of zero means the size of that cell has not yet been computed.
|
||||
**
|
||||
** The cells come from as many as four different pages:
|
||||
**
|
||||
** -----------
|
||||
** | Parent |
|
||||
** -----------
|
||||
** / | \
|
||||
** / | \
|
||||
** --------- --------- ---------
|
||||
** |Child-1| |Child-2| |Child-3|
|
||||
** --------- --------- ---------
|
||||
**
|
||||
** The order of cells is in the array is for an index btree is:
|
||||
**
|
||||
** 1. All cells from Child-1 in order
|
||||
** 2. The first divider cell from Parent
|
||||
** 3. All cells from Child-2 in order
|
||||
** 4. The second divider cell from Parent
|
||||
** 5. All cells from Child-3 in order
|
||||
**
|
||||
** For a table-btree (with rowids) the items 2 and 4 are empty because
|
||||
** content exists only in leaves and there are no divider cells.
|
||||
**
|
||||
** For an index btree, the apEnd[] array holds pointer to the end of page
|
||||
** for Child-1, the Parent, Child-2, the Parent (again), and Child-3,
|
||||
** respectively. The ixNx[] array holds the number of cells contained in
|
||||
** each of these 5 stages, and all stages to the left. Hence:
|
||||
**
|
||||
** ixNx[0] = Number of cells in Child-1.
|
||||
** ixNx[1] = Number of cells in Child-1 plus 1 for first divider.
|
||||
** ixNx[2] = Number of cells in Child-1 and Child-2 + 1 for 1st divider.
|
||||
** ixNx[3] = Number of cells in Child-1 and Child-2 + both divider cells
|
||||
** ixNx[4] = Total number of cells.
|
||||
**
|
||||
** For a table-btree, the concept is similar, except only apEnd[0]..apEnd[2]
|
||||
** are used and they point to the leaf pages only, and the ixNx value are:
|
||||
**
|
||||
** ixNx[0] = Number of cells in Child-1.
|
||||
** ixNx[1] = Number of cells in Child-1 and Child-2 + 1 for 1st divider.
|
||||
** ixNx[2] = Number of cells in Child-1 and Child-2 + both divider cells
|
||||
*/
|
||||
typedef struct CellArray CellArray;
|
||||
struct CellArray {
|
||||
@@ -6679,6 +6782,8 @@ struct CellArray {
|
||||
MemPage *pRef; /* Reference page */
|
||||
u8 **apCell; /* All cells begin balanced */
|
||||
u16 *szCell; /* Local size of all cells in apCell[] */
|
||||
u8 *apEnd[NB*2]; /* MemPage.aDataEnd values */
|
||||
int ixNx[NB*2]; /* Index of at which we move to the next apEnd[] */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -6729,36 +6834,59 @@ static u16 cachedCellSize(CellArray *p, int N){
|
||||
** responsibility of the caller to set it correctly.
|
||||
*/
|
||||
static int rebuildPage(
|
||||
MemPage *pPg, /* Edit this page */
|
||||
CellArray *pCArray, /* Content to be added to page pPg */
|
||||
int iFirst, /* First cell in pCArray to use */
|
||||
int nCell, /* Final number of cells on page */
|
||||
u8 **apCell, /* Array of cells */
|
||||
u16 *szCell /* Array of cell sizes */
|
||||
MemPage *pPg /* The page to be reconstructed */
|
||||
){
|
||||
const int hdr = pPg->hdrOffset; /* Offset of header on pPg */
|
||||
u8 * const aData = pPg->aData; /* Pointer to data for pPg */
|
||||
const int usableSize = pPg->pBt->usableSize;
|
||||
u8 * const pEnd = &aData[usableSize];
|
||||
int i;
|
||||
int i = iFirst; /* Which cell to copy from pCArray*/
|
||||
u32 j; /* Start of cell content area */
|
||||
int iEnd = i+nCell; /* Loop terminator */
|
||||
u8 *pCellptr = pPg->aCellIdx;
|
||||
u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
|
||||
u8 *pData;
|
||||
int k; /* Current slot in pCArray->apEnd[] */
|
||||
u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */
|
||||
|
||||
i = get2byte(&aData[hdr+5]);
|
||||
memcpy(&pTmp[i], &aData[i], usableSize - i);
|
||||
assert( i<iEnd );
|
||||
j = get2byte(&aData[hdr+5]);
|
||||
if( NEVER(j>(u32)usableSize) ){ j = 0; }
|
||||
memcpy(&pTmp[j], &aData[j], usableSize - j);
|
||||
|
||||
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
|
||||
pSrcEnd = pCArray->apEnd[k];
|
||||
|
||||
pData = pEnd;
|
||||
for(i=0; i<nCell; i++){
|
||||
u8 *pCell = apCell[i];
|
||||
while( 1/*exit by break*/ ){
|
||||
u8 *pCell = pCArray->apCell[i];
|
||||
u16 sz = pCArray->szCell[i];
|
||||
assert( sz>0 );
|
||||
if( SQLITE_WITHIN(pCell,aData,pEnd) ){
|
||||
if( ((uptr)(pCell+sz))>(uptr)pEnd ) return SQLITE_CORRUPT_BKPT;
|
||||
pCell = &pTmp[pCell - aData];
|
||||
}else if( (uptr)(pCell+sz)>(uptr)pSrcEnd
|
||||
&& (uptr)(pCell)<(uptr)pSrcEnd
|
||||
){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
pData -= szCell[i];
|
||||
|
||||
pData -= sz;
|
||||
put2byte(pCellptr, (pData - aData));
|
||||
pCellptr += 2;
|
||||
if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT;
|
||||
memcpy(pData, pCell, szCell[i]);
|
||||
assert( szCell[i]==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
|
||||
testcase( szCell[i]!=pPg->xCellSize(pPg,pCell) );
|
||||
memcpy(pData, pCell, sz);
|
||||
assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
|
||||
testcase( sz!=pPg->xCellSize(pPg,pCell) );
|
||||
i++;
|
||||
if( i>=iEnd ) break;
|
||||
if( pCArray->ixNx[k]<=i ){
|
||||
k++;
|
||||
pSrcEnd = pCArray->apEnd[k];
|
||||
}
|
||||
}
|
||||
|
||||
/* The pPg->nFree field is now set incorrectly. The caller will fix it. */
|
||||
@@ -6773,12 +6901,11 @@ static int rebuildPage(
|
||||
}
|
||||
|
||||
/*
|
||||
** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
|
||||
** contains the size in bytes of each such cell. This function attempts to
|
||||
** add the cells stored in the array to page pPg. If it cannot (because
|
||||
** the page needs to be defragmented before the cells will fit), non-zero
|
||||
** is returned. Otherwise, if the cells are added successfully, zero is
|
||||
** returned.
|
||||
** The pCArray objects contains pointers to b-tree cells and the cell sizes.
|
||||
** This function attempts to add the cells stored in the array to page pPg.
|
||||
** If it cannot (because the page needs to be defragmented before the cells
|
||||
** will fit), non-zero is returned. Otherwise, if the cells are added
|
||||
** successfully, zero is returned.
|
||||
**
|
||||
** Argument pCellptr points to the first entry in the cell-pointer array
|
||||
** (part of page pPg) to populate. After cell apCell[0] is written to the
|
||||
@@ -6800,18 +6927,23 @@ static int rebuildPage(
|
||||
static int pageInsertArray(
|
||||
MemPage *pPg, /* Page to add cells to */
|
||||
u8 *pBegin, /* End of cell-pointer array */
|
||||
u8 **ppData, /* IN/OUT: Page content -area pointer */
|
||||
u8 **ppData, /* IN/OUT: Page content-area pointer */
|
||||
u8 *pCellptr, /* Pointer to cell-pointer area */
|
||||
int iFirst, /* Index of first cell to add */
|
||||
int nCell, /* Number of cells to add to pPg */
|
||||
CellArray *pCArray /* Array of cells */
|
||||
){
|
||||
int i;
|
||||
u8 *aData = pPg->aData;
|
||||
u8 *pData = *ppData;
|
||||
int iEnd = iFirst + nCell;
|
||||
int i = iFirst; /* Loop counter - cell index to insert */
|
||||
u8 *aData = pPg->aData; /* Complete page */
|
||||
u8 *pData = *ppData; /* Content area. A subset of aData[] */
|
||||
int iEnd = iFirst + nCell; /* End of loop. One past last cell to ins */
|
||||
int k; /* Current slot in pCArray->apEnd[] */
|
||||
u8 *pEnd; /* Maximum extent of cell data */
|
||||
assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
|
||||
for(i=iFirst; i<iEnd; i++){
|
||||
if( iEnd<=iFirst ) return 0;
|
||||
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
|
||||
pEnd = pCArray->apEnd[k];
|
||||
while( 1 /*Exit by break*/ ){
|
||||
int sz, rc;
|
||||
u8 *pSlot;
|
||||
sz = cachedCellSize(pCArray, i);
|
||||
@@ -6826,20 +6958,33 @@ static int pageInsertArray(
|
||||
assert( (pSlot+sz)<=pCArray->apCell[i]
|
||||
|| pSlot>=(pCArray->apCell[i]+sz)
|
||||
|| CORRUPT_DB );
|
||||
if( (uptr)(pCArray->apCell[i]+sz)>(uptr)pEnd
|
||||
&& (uptr)(pCArray->apCell[i])<(uptr)pEnd
|
||||
){
|
||||
assert( CORRUPT_DB );
|
||||
(void)SQLITE_CORRUPT_BKPT;
|
||||
return 1;
|
||||
}
|
||||
memmove(pSlot, pCArray->apCell[i], sz);
|
||||
put2byte(pCellptr, (pSlot - aData));
|
||||
pCellptr += 2;
|
||||
i++;
|
||||
if( i>=iEnd ) break;
|
||||
if( pCArray->ixNx[k]<=i ){
|
||||
k++;
|
||||
pEnd = pCArray->apEnd[k];
|
||||
}
|
||||
}
|
||||
*ppData = pData;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
|
||||
** contains the size in bytes of each such cell. This function adds the
|
||||
** space associated with each cell in the array that is currently stored
|
||||
** within the body of pPg to the pPg free-list. The cell-pointers and other
|
||||
** fields of the page are not updated.
|
||||
** The pCArray object contains pointers to b-tree cells and their sizes.
|
||||
**
|
||||
** This function adds the space associated with each cell in the array
|
||||
** that is currently stored within the body of pPg to the pPg free-list.
|
||||
** The cell-pointers and other fields of the page are not updated.
|
||||
**
|
||||
** This function returns the total number of cells added to the free-list.
|
||||
*/
|
||||
@@ -6889,9 +7034,9 @@ static int pageFreeArray(
|
||||
}
|
||||
|
||||
/*
|
||||
** apCell[] and szCell[] contains pointers to and sizes of all cells in the
|
||||
** pages being balanced. The current page, pPg, has pPg->nCell cells starting
|
||||
** with apCell[iOld]. After balancing, this page should hold nNew cells
|
||||
** pCArray contains pointers to and sizes of all cells in the page being
|
||||
** balanced. The current page, pPg, has pPg->nCell cells starting with
|
||||
** pCArray->apCell[iOld]. After balancing, this page should hold nNew cells
|
||||
** starting at apCell[iNew].
|
||||
**
|
||||
** This routine makes the necessary adjustments to pPg so that it contains
|
||||
@@ -6923,13 +7068,17 @@ static int editPage(
|
||||
#endif
|
||||
|
||||
/* Remove cells from the start and end of the page */
|
||||
assert( nCell>=0 );
|
||||
if( iOld<iNew ){
|
||||
int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray);
|
||||
if( nShift>nCell ) return SQLITE_CORRUPT_BKPT;
|
||||
memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
|
||||
nCell -= nShift;
|
||||
}
|
||||
if( iNewEnd < iOldEnd ){
|
||||
nCell -= pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
|
||||
int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
|
||||
assert( nCell>=nTail );
|
||||
nCell -= nTail;
|
||||
}
|
||||
|
||||
pData = &aData[get2byteNotZero(&aData[hdr+5])];
|
||||
@@ -6939,6 +7088,7 @@ static int editPage(
|
||||
if( iNew<iOld ){
|
||||
int nAdd = MIN(nNew,iOld-iNew);
|
||||
assert( (iOld-iNew)<nNew || nCell==0 || CORRUPT_DB );
|
||||
assert( nAdd>=0 );
|
||||
pCellptr = pPg->aCellIdx;
|
||||
memmove(&pCellptr[nAdd*2], pCellptr, nCell*2);
|
||||
if( pageInsertArray(
|
||||
@@ -6953,6 +7103,7 @@ static int editPage(
|
||||
int iCell = (iOld + pPg->aiOvfl[i]) - iNew;
|
||||
if( iCell>=0 && iCell<nNew ){
|
||||
pCellptr = &pPg->aCellIdx[iCell * 2];
|
||||
assert( nCell>=iCell );
|
||||
memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2);
|
||||
nCell++;
|
||||
if( pageInsertArray(
|
||||
@@ -6963,6 +7114,7 @@ static int editPage(
|
||||
}
|
||||
|
||||
/* Append cells to the end of the page */
|
||||
assert( nCell>=0 );
|
||||
pCellptr = &pPg->aCellIdx[nCell*2];
|
||||
if( pageInsertArray(
|
||||
pPg, pBegin, &pData, pCellptr,
|
||||
@@ -6991,24 +7143,9 @@ static int editPage(
|
||||
editpage_fail:
|
||||
/* Unable to edit this page. Rebuild it from scratch instead. */
|
||||
populateCellCache(pCArray, iNew, nNew);
|
||||
return rebuildPage(pPg, nNew, &pCArray->apCell[iNew], &pCArray->szCell[iNew]);
|
||||
return rebuildPage(pCArray, iNew, nNew, pPg);
|
||||
}
|
||||
|
||||
/*
|
||||
** The following parameters determine how many adjacent pages get involved
|
||||
** in a balancing operation. NN is the number of neighbors on either side
|
||||
** of the page that participate in the balancing operation. NB is the
|
||||
** total number of pages that participate, including the target page and
|
||||
** NN neighbors on either side.
|
||||
**
|
||||
** The minimum value of NN is 1 (of course). Increasing NN above 1
|
||||
** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance
|
||||
** in exchange for a larger degradation in INSERT and UPDATE performance.
|
||||
** The value of NN appears to give the best results overall.
|
||||
*/
|
||||
#define NN 1 /* Number of neighbors on either side of pPage */
|
||||
#define NB (NN*2+1) /* Total pages involved in the balance */
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_QUICKBALANCE
|
||||
/*
|
||||
@@ -7044,8 +7181,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
||||
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
|
||||
assert( pPage->nOverflow==1 );
|
||||
|
||||
/* This error condition is now caught prior to reaching this function */
|
||||
if( NEVER(pPage->nCell==0) ) return SQLITE_CORRUPT_BKPT;
|
||||
if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; /* dbfuzz001.test */
|
||||
|
||||
/* Allocate a new page. This page will become the right-sibling of
|
||||
** pPage. Make the parent page writable, so that the new divider cell
|
||||
@@ -7059,12 +7195,22 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
||||
u8 *pCell = pPage->apOvfl[0];
|
||||
u16 szCell = pPage->xCellSize(pPage, pCell);
|
||||
u8 *pStop;
|
||||
CellArray b;
|
||||
|
||||
assert( sqlite3PagerIswriteable(pNew->pDbPage) );
|
||||
assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
|
||||
assert( CORRUPT_DB || pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
|
||||
zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
|
||||
rc = rebuildPage(pNew, 1, &pCell, &szCell);
|
||||
if( NEVER(rc) ) return rc;
|
||||
b.nCell = 1;
|
||||
b.pRef = pPage;
|
||||
b.apCell = &pCell;
|
||||
b.szCell = &szCell;
|
||||
b.apEnd[0] = pPage->aDataEnd;
|
||||
b.ixNx[0] = 2;
|
||||
rc = rebuildPage(&b, 0, 1, pNew);
|
||||
if( NEVER(rc) ){
|
||||
releasePage(pNew);
|
||||
return rc;
|
||||
}
|
||||
pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell;
|
||||
|
||||
/* If this is an auto-vacuum database, update the pointer map
|
||||
@@ -7079,7 +7225,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
||||
if( ISAUTOVACUUM ){
|
||||
ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc);
|
||||
if( szCell>pNew->minLocal ){
|
||||
ptrmapPutOvflPtr(pNew, pCell, &rc);
|
||||
ptrmapPutOvflPtr(pNew, pNew, pCell, &rc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7302,10 +7448,6 @@ static int balance_nonroot(
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
|
||||
|
||||
#if 0
|
||||
TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno));
|
||||
#endif
|
||||
|
||||
/* At this point pParent may have at most one overflow cell. And if
|
||||
** this overflow cell is present, it must be the cell with
|
||||
** index iParentIdx. This scenario comes about when this function
|
||||
@@ -7546,8 +7688,15 @@ static int balance_nonroot(
|
||||
**
|
||||
*/
|
||||
usableSpace = pBt->usableSize - 12 + leafCorrection;
|
||||
for(i=0; i<nOld; i++){
|
||||
for(i=k=0; i<nOld; i++, k++){
|
||||
MemPage *p = apOld[i];
|
||||
b.apEnd[k] = p->aDataEnd;
|
||||
b.ixNx[k] = cntOld[i];
|
||||
if( !leafData ){
|
||||
k++;
|
||||
b.apEnd[k] = pParent->aDataEnd;
|
||||
b.ixNx[k] = cntOld[i]+1;
|
||||
}
|
||||
szNew[i] = usableSpace - p->nFree;
|
||||
for(j=0; j<p->nOverflow; j++){
|
||||
szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]);
|
||||
@@ -7771,7 +7920,8 @@ static int balance_nonroot(
|
||||
** populated, not here.
|
||||
*/
|
||||
if( ISAUTOVACUUM ){
|
||||
MemPage *pNew = apNew[0];
|
||||
MemPage *pOld;
|
||||
MemPage *pNew = pOld = apNew[0];
|
||||
u8 *aOld = pNew->aData;
|
||||
int cntOldNext = pNew->nCell + pNew->nOverflow;
|
||||
int usableSize = pBt->usableSize;
|
||||
@@ -7781,7 +7931,7 @@ static int balance_nonroot(
|
||||
for(i=0; i<b.nCell; i++){
|
||||
u8 *pCell = b.apCell[i];
|
||||
if( i==cntOldNext ){
|
||||
MemPage *pOld = (++iOld)<nNew ? apNew[iOld] : apOld[iOld];
|
||||
pOld = (++iOld)<nNew ? apNew[iOld] : apOld[iOld];
|
||||
cntOldNext += pOld->nCell + pOld->nOverflow + !leafData;
|
||||
aOld = pOld->aData;
|
||||
}
|
||||
@@ -7804,7 +7954,7 @@ static int balance_nonroot(
|
||||
ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc);
|
||||
}
|
||||
if( cachedCellSize(&b,i)>pNew->minLocal ){
|
||||
ptrmapPutOvflPtr(pNew, pCell, &rc);
|
||||
ptrmapPutOvflPtr(pNew, pOld, pCell, &rc);
|
||||
}
|
||||
if( rc ) goto balance_cleanup;
|
||||
}
|
||||
@@ -8228,7 +8378,11 @@ static int btreeOverwriteContent(
|
||||
if( memcmp(pDest, ((u8*)pX->pData) + iOffset, iAmt)!=0 ){
|
||||
int rc = sqlite3PagerWrite(pPage->pDbPage);
|
||||
if( rc ) return rc;
|
||||
memcpy(pDest, ((u8*)pX->pData) + iOffset, iAmt);
|
||||
/* In a corrupt database, it is possible for the source and destination
|
||||
** buffers to overlap. This is harmless since the database is already
|
||||
** corrupt but it does cause valgrind and ASAN warnings. So use
|
||||
** memmove(). */
|
||||
memmove(pDest, ((u8*)pX->pData) + iOffset, iAmt);
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
@@ -8623,6 +8777,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
if( bPreserve ){
|
||||
if( !pPage->leaf
|
||||
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
|
||||
|| pPage->nCell==1 /* See dbfuzz001.test for a test case */
|
||||
){
|
||||
/* A b-tree rebalance will be required after deleting this entry.
|
||||
** Save the cursor key. */
|
||||
@@ -9401,18 +9556,18 @@ static void checkList(
|
||||
}
|
||||
pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
|
||||
if( isFreeList ){
|
||||
int n = get4byte(&pOvflData[4]);
|
||||
u32 n = (u32)get4byte(&pOvflData[4]);
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pCheck->pBt->autoVacuum ){
|
||||
checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0);
|
||||
}
|
||||
#endif
|
||||
if( n>(int)pCheck->pBt->usableSize/4-2 ){
|
||||
if( n>pCheck->pBt->usableSize/4-2 ){
|
||||
checkAppendMsg(pCheck,
|
||||
"freelist leaf count too big on page %d", iPage);
|
||||
N--;
|
||||
}else{
|
||||
for(i=0; i<n; i++){
|
||||
for(i=0; i<(int)n; i++){
|
||||
Pgno iFreePage = get4byte(&pOvflData[8+i*4]);
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pCheck->pBt->autoVacuum ){
|
||||
@@ -9789,7 +9944,7 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
Pgno i;
|
||||
IntegrityCk sCheck;
|
||||
BtShared *pBt = p->pBt;
|
||||
int savedDbFlags = pBt->db->flags;
|
||||
u64 savedDbFlags = pBt->db->flags;
|
||||
char zErr[100];
|
||||
VVA_ONLY( int nRef );
|
||||
|
||||
@@ -9856,7 +10011,7 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
}
|
||||
#endif
|
||||
testcase( pBt->db->flags & SQLITE_CellSizeCk );
|
||||
pBt->db->flags &= ~SQLITE_CellSizeCk;
|
||||
pBt->db->flags &= ~(u64)SQLITE_CellSizeCk;
|
||||
for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
|
||||
i64 notUsed;
|
||||
if( aRoot[i]==0 ) continue;
|
||||
|
||||
@@ -315,6 +315,7 @@ i64 sqlite3BtreeOffset(BtCursor*);
|
||||
int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
|
||||
const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
|
||||
u32 sqlite3BtreePayloadSize(BtCursor*);
|
||||
sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
|
||||
|
||||
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
|
||||
struct Pager *sqlite3BtreePager(Btree*);
|
||||
|
||||
+10
-3
@@ -494,9 +494,16 @@ struct CellInfo {
|
||||
** found at self->pBt->mutex.
|
||||
**
|
||||
** skipNext meaning:
|
||||
** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op.
|
||||
** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op.
|
||||
** eState==FAULT: Cursor fault with skipNext as error code.
|
||||
** The meaning of skipNext depends on the value of eState:
|
||||
**
|
||||
** eState Meaning of skipNext
|
||||
** VALID skipNext is meaningless and is ignored
|
||||
** INVALID skipNext is meaningless and is ignored
|
||||
** SKIPNEXT sqlite3BtreeNext() is a no-op if skipNext>0 and
|
||||
** sqlite3BtreePrevious() is no-op if skipNext<0.
|
||||
** REQUIRESEEK restoreCursorPosition() restores the cursor to
|
||||
** eState=SKIPNEXT if skipNext!=0
|
||||
** FAULT skipNext holds the cursor fault error code.
|
||||
*/
|
||||
struct BtCursor {
|
||||
u8 eState; /* One of the CURSOR_XXX constants (see below) */
|
||||
|
||||
+85
-47
@@ -227,7 +227,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
if( v && pParse->nErr==0 && !db->mallocFailed ){
|
||||
/* A minimum of one cursor is required if autoincrement is used
|
||||
* See ticket [a696379c1f08866] */
|
||||
if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
|
||||
assert( pParse->pAinc==0 || pParse->nTab>0 );
|
||||
sqlite3VdbeMakeReady(v, pParse);
|
||||
pParse->rc = SQLITE_DONE;
|
||||
}else{
|
||||
@@ -354,26 +354,32 @@ Table *sqlite3LocateTable(
|
||||
|
||||
p = sqlite3FindTable(db, zName, zDbase);
|
||||
if( p==0 ){
|
||||
const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/* If zName is the not the name of a table in the schema created using
|
||||
** CREATE, then check to see if it is the name of an virtual table that
|
||||
** can be an eponymous virtual table. */
|
||||
Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
|
||||
if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
|
||||
pMod = sqlite3PragmaVtabRegister(db, zName);
|
||||
}
|
||||
if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
|
||||
return pMod->pEpoTab;
|
||||
if( pParse->disableVtab==0 ){
|
||||
Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
|
||||
if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
|
||||
pMod = sqlite3PragmaVtabRegister(db, zName);
|
||||
}
|
||||
if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
|
||||
return pMod->pEpoTab;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( (flags & LOCATE_NOERR)==0 ){
|
||||
if( zDbase ){
|
||||
sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
if( flags & LOCATE_NOERR ) return 0;
|
||||
pParse->checkSchema = 1;
|
||||
}else if( IsVirtual(p) && pParse->disableVtab ){
|
||||
p = 0;
|
||||
}
|
||||
|
||||
if( p==0 ){
|
||||
const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
|
||||
if( zDbase ){
|
||||
sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -636,12 +642,6 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
|
||||
|
||||
/* Delete the Table structure itself.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
if( pTable->pColHash ){
|
||||
sqlite3HashClear(pTable->pColHash);
|
||||
sqlite3_free(pTable->pColHash);
|
||||
}
|
||||
#endif
|
||||
sqlite3DeleteColumnNames(db, pTable);
|
||||
sqlite3DbFree(db, pTable->zName);
|
||||
sqlite3DbFree(db, pTable->zColAff);
|
||||
@@ -2638,6 +2638,7 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
|
||||
*/
|
||||
if( IsVirtual(pTab) ){
|
||||
sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0);
|
||||
sqlite3MayAbort(pParse);
|
||||
}
|
||||
sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
@@ -3466,6 +3467,11 @@ void sqlite3CreateIndex(
|
||||
}
|
||||
}
|
||||
if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType;
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pIndex->pNext = pParse->pNewIndex;
|
||||
pParse->pNewIndex = pIndex;
|
||||
pIndex = 0;
|
||||
}
|
||||
goto exit_create_index;
|
||||
}
|
||||
}
|
||||
@@ -3481,6 +3487,14 @@ void sqlite3CreateIndex(
|
||||
Index *p;
|
||||
assert( !IN_SPECIAL_PARSE );
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
|
||||
if( pTblName!=0 ){
|
||||
pIndex->tnum = db->init.newTnum;
|
||||
if( sqlite3IndexHasDuplicateRootPage(pIndex) ){
|
||||
sqlite3ErrorMsg(pParse, "invalid rootpage");
|
||||
pParse->rc = SQLITE_CORRUPT_BKPT;
|
||||
goto exit_create_index;
|
||||
}
|
||||
}
|
||||
p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
|
||||
pIndex->zName, pIndex);
|
||||
if( p ){
|
||||
@@ -3489,9 +3503,6 @@ void sqlite3CreateIndex(
|
||||
goto exit_create_index;
|
||||
}
|
||||
db->mDbFlags |= DBFLAG_SchemaChange;
|
||||
if( pTblName!=0 ){
|
||||
pIndex->tnum = db->init.newTnum;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is the initial CREATE INDEX statement (or CREATE TABLE if the
|
||||
@@ -3817,6 +3828,18 @@ int sqlite3IdListIndex(IdList *pList, const char *zName){
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Maximum size of a SrcList object.
|
||||
** The SrcList object is used to represent the FROM clause of a
|
||||
** SELECT statement, and the query planner cannot deal with more
|
||||
** than 64 tables in a join. So any value larger than 64 here
|
||||
** is sufficient for most uses. Smaller values, like say 10, are
|
||||
** appropriate for small and memory-limited applications.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_SRCLIST
|
||||
# define SQLITE_MAX_SRCLIST 200
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Expand the space allocated for the given SrcList object by
|
||||
** creating nExtra new slots beginning at iStart. iStart is zero based.
|
||||
@@ -3833,11 +3856,12 @@ int sqlite3IdListIndex(IdList *pList, const char *zName){
|
||||
** the iStart value would be 0. The result then would
|
||||
** be: nil, nil, nil, A, B.
|
||||
**
|
||||
** If a memory allocation fails the SrcList is unchanged. The
|
||||
** db->mallocFailed flag will be set to true.
|
||||
** If a memory allocation fails or the SrcList becomes too large, leave
|
||||
** the original SrcList unchanged, return NULL, and leave an error message
|
||||
** in pParse.
|
||||
*/
|
||||
SrcList *sqlite3SrcListEnlarge(
|
||||
sqlite3 *db, /* Database connection to notify of OOM errors */
|
||||
Parse *pParse, /* Parsing context into which errors are reported */
|
||||
SrcList *pSrc, /* The SrcList to be enlarged */
|
||||
int nExtra, /* Number of new slots to add to pSrc->a[] */
|
||||
int iStart /* Index in pSrc->a[] of first new slot */
|
||||
@@ -3854,16 +3878,22 @@ SrcList *sqlite3SrcListEnlarge(
|
||||
if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){
|
||||
SrcList *pNew;
|
||||
int nAlloc = pSrc->nSrc*2+nExtra;
|
||||
int nGot;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
if( pSrc->nSrc+nExtra>=SQLITE_MAX_SRCLIST ){
|
||||
sqlite3ErrorMsg(pParse, "too many FROM clause terms, max: %d",
|
||||
SQLITE_MAX_SRCLIST);
|
||||
return 0;
|
||||
}
|
||||
if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST;
|
||||
pNew = sqlite3DbRealloc(db, pSrc,
|
||||
sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) );
|
||||
if( pNew==0 ){
|
||||
assert( db->mallocFailed );
|
||||
return pSrc;
|
||||
return 0;
|
||||
}
|
||||
pSrc = pNew;
|
||||
nGot = (sqlite3DbMallocSize(db, pNew) - sizeof(*pSrc))/sizeof(pSrc->a[0])+1;
|
||||
pSrc->nAlloc = nGot;
|
||||
pSrc->nAlloc = nAlloc;
|
||||
}
|
||||
|
||||
/* Move existing slots that come after the newly inserted slots
|
||||
@@ -3888,7 +3918,8 @@ SrcList *sqlite3SrcListEnlarge(
|
||||
** Append a new table name to the given SrcList. Create a new SrcList if
|
||||
** need be. A new entry is created in the SrcList even if pTable is NULL.
|
||||
**
|
||||
** A SrcList is returned, or NULL if there is an OOM error. The returned
|
||||
** A SrcList is returned, or NULL if there is an OOM error or if the
|
||||
** SrcList grows to large. The returned
|
||||
** SrcList might be the same as the SrcList that was input or it might be
|
||||
** a new one. If an OOM error does occurs, then the prior value of pList
|
||||
** that is input to this routine is automatically freed.
|
||||
@@ -3919,27 +3950,32 @@ SrcList *sqlite3SrcListEnlarge(
|
||||
** before being added to the SrcList.
|
||||
*/
|
||||
SrcList *sqlite3SrcListAppend(
|
||||
sqlite3 *db, /* Connection to notify of malloc failures */
|
||||
Parse *pParse, /* Parsing context, in which errors are reported */
|
||||
SrcList *pList, /* Append to this SrcList. NULL creates a new SrcList */
|
||||
Token *pTable, /* Table to append */
|
||||
Token *pDatabase /* Database of the table */
|
||||
){
|
||||
struct SrcList_item *pItem;
|
||||
sqlite3 *db;
|
||||
assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
|
||||
assert( db!=0 );
|
||||
assert( pParse!=0 );
|
||||
assert( pParse->db!=0 );
|
||||
db = pParse->db;
|
||||
if( pList==0 ){
|
||||
pList = sqlite3DbMallocRawNN(db, sizeof(SrcList) );
|
||||
pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) );
|
||||
if( pList==0 ) return 0;
|
||||
pList->nAlloc = 1;
|
||||
pList->nSrc = 1;
|
||||
memset(&pList->a[0], 0, sizeof(pList->a[0]));
|
||||
pList->a[0].iCursor = -1;
|
||||
}else{
|
||||
pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
sqlite3SrcListDelete(db, pList);
|
||||
return 0;
|
||||
SrcList *pNew = sqlite3SrcListEnlarge(pParse, pList, 1, pList->nSrc);
|
||||
if( pNew==0 ){
|
||||
sqlite3SrcListDelete(db, pList);
|
||||
return 0;
|
||||
}else{
|
||||
pList = pNew;
|
||||
}
|
||||
}
|
||||
pItem = &pList->a[pList->nSrc-1];
|
||||
if( pDatabase && pDatabase->z==0 ){
|
||||
@@ -4028,7 +4064,7 @@ SrcList *sqlite3SrcListAppendFromTerm(
|
||||
);
|
||||
goto append_from_error;
|
||||
}
|
||||
p = sqlite3SrcListAppend(db, p, pTable, pDatabase);
|
||||
p = sqlite3SrcListAppend(pParse, p, pTable, pDatabase);
|
||||
if( p==0 ){
|
||||
goto append_from_error;
|
||||
}
|
||||
@@ -4417,13 +4453,15 @@ static int collationMatch(const char *zColl, Index *pIndex){
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_REINDEX
|
||||
static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){
|
||||
Index *pIndex; /* An index associated with pTab */
|
||||
if( !IsVirtual(pTab) ){
|
||||
Index *pIndex; /* An index associated with pTab */
|
||||
|
||||
for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
|
||||
if( zColl==0 || collationMatch(zColl, pIndex) ){
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3RefillIndex(pParse, pIndex, -1);
|
||||
for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
|
||||
if( zColl==0 || collationMatch(zColl, pIndex) ){
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3RefillIndex(pParse, pIndex, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-18
@@ -283,7 +283,7 @@ static int matchQuality(
|
||||
** Search a FuncDefHash for a function with the given name. Return
|
||||
** a pointer to the matching FuncDef if found, or 0 if there is no match.
|
||||
*/
|
||||
static FuncDef *functionSearch(
|
||||
FuncDef *sqlite3FunctionSearch(
|
||||
int h, /* Hash of the name */
|
||||
const char *zFunc /* Name of function */
|
||||
){
|
||||
@@ -295,21 +295,6 @@ static FuncDef *functionSearch(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
FuncDef *sqlite3FunctionSearchN(
|
||||
int h, /* Hash of the name */
|
||||
const char *zFunc, /* Name of function */
|
||||
int nFunc /* Length of the name */
|
||||
){
|
||||
FuncDef *p;
|
||||
for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
|
||||
if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 ){
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_NORMALIZE */
|
||||
|
||||
/*
|
||||
** Insert a new FuncDef into a FuncDefHash hash table.
|
||||
@@ -325,7 +310,7 @@ void sqlite3InsertBuiltinFuncs(
|
||||
int nName = sqlite3Strlen30(zName);
|
||||
int h = SQLITE_FUNC_HASH(zName[0], nName);
|
||||
assert( zName[0]>='a' && zName[0]<='z' );
|
||||
pOther = functionSearch(h, zName);
|
||||
pOther = sqlite3FunctionSearch(h, zName);
|
||||
if( pOther ){
|
||||
assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
|
||||
aDef[i].pNext = pOther->pNext;
|
||||
@@ -403,7 +388,7 @@ FuncDef *sqlite3FindFunction(
|
||||
if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){
|
||||
bestScore = 0;
|
||||
h = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zName[0]], nName);
|
||||
p = functionSearch(h, zName);
|
||||
p = sqlite3FunctionSearch(h, zName);
|
||||
while( p ){
|
||||
int score = matchQuality(p, nArg, enc);
|
||||
if( score>bestScore ){
|
||||
|
||||
+127
-19
@@ -180,7 +180,7 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
|
||||
}else
|
||||
if( sqlite3StrICmp(zLeft,"cipher_default_kdf_iter")==0 ){
|
||||
if( zRight ) {
|
||||
sqlcipher_set_default_kdf_iter(atoi(zRight)); // change default KDF iterations
|
||||
sqlcipher_set_default_kdf_iter(atoi(zRight)); /* change default KDF iterations */
|
||||
} else {
|
||||
char *kdf_iter = sqlite3_mprintf("%d", sqlcipher_get_default_kdf_iter());
|
||||
codec_vdbe_return_string(pParse, "cipher_default_kdf_iter", kdf_iter, P4_DYNAMIC);
|
||||
@@ -189,7 +189,7 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
|
||||
if( sqlite3StrICmp(zLeft, "kdf_iter")==0 ){
|
||||
if(ctx) {
|
||||
if( zRight ) {
|
||||
sqlcipher_codec_ctx_set_kdf_iter(ctx, atoi(zRight)); // change of RW PBKDF2 iteration
|
||||
sqlcipher_codec_ctx_set_kdf_iter(ctx, atoi(zRight)); /* change of RW PBKDF2 iteration */
|
||||
} else {
|
||||
char *kdf_iter = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_kdf_iter(ctx));
|
||||
codec_vdbe_return_string(pParse, "kdf_iter", kdf_iter, P4_DYNAMIC);
|
||||
@@ -199,7 +199,10 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
|
||||
if( sqlite3StrICmp(zLeft, "fast_kdf_iter")==0){
|
||||
if(ctx) {
|
||||
if( zRight ) {
|
||||
sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, atoi(zRight)); // change of RW PBKDF2 iteration
|
||||
char *deprecation = "PRAGMA fast_kdf_iter is deprecated, please remove from use";
|
||||
sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, atoi(zRight)); /* change of RW PBKDF2 iteration */
|
||||
codec_vdbe_return_string(pParse, "fast_kdf_iter", deprecation, P4_TRANSIENT);
|
||||
sqlite3_log(SQLITE_WARNING, deprecation);
|
||||
} else {
|
||||
char *fast_kdf_iter = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_fast_kdf_iter(ctx));
|
||||
codec_vdbe_return_string(pParse, "fast_kdf_iter", fast_kdf_iter, P4_DYNAMIC);
|
||||
@@ -258,7 +261,8 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
|
||||
if( sqlite3StrICmp(zLeft,"cipher_hmac_pgno")==0 ){
|
||||
if(ctx) {
|
||||
if(zRight) {
|
||||
// clear both pgno endian flags
|
||||
char *deprecation = "PRAGMA cipher_hmac_pgno is deprecated, please remove from use";
|
||||
/* clear both pgno endian flags */
|
||||
if(sqlite3StrICmp(zRight, "le") == 0) {
|
||||
sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_BE_PGNO);
|
||||
sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_LE_PGNO);
|
||||
@@ -269,6 +273,9 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
|
||||
sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_LE_PGNO);
|
||||
sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_BE_PGNO);
|
||||
}
|
||||
codec_vdbe_return_string(pParse, "cipher_hmac_pgno", deprecation, P4_TRANSIENT);
|
||||
sqlite3_log(SQLITE_WARNING, deprecation);
|
||||
|
||||
} else {
|
||||
if(sqlcipher_codec_ctx_get_flag(ctx, CIPHER_FLAG_LE_PGNO)) {
|
||||
codec_vdbe_return_string(pParse, "cipher_hmac_pgno", "le", P4_TRANSIENT);
|
||||
@@ -283,15 +290,18 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
|
||||
if( sqlite3StrICmp(zLeft,"cipher_hmac_salt_mask")==0 ){
|
||||
if(ctx) {
|
||||
if(zRight) {
|
||||
char *deprecation = "PRAGMA cipher_hmac_salt_mask is deprecated, please remove from use";
|
||||
if (sqlite3StrNICmp(zRight ,"x'", 2) == 0 && sqlite3Strlen30(zRight) == 5) {
|
||||
unsigned char mask = 0;
|
||||
const unsigned char *hex = (const unsigned char *)zRight+2;
|
||||
cipher_hex2bin(hex,2,&mask);
|
||||
sqlcipher_set_hmac_salt_mask(mask);
|
||||
}
|
||||
codec_vdbe_return_string(pParse, "cipher_hmac_salt_mask", deprecation, P4_TRANSIENT);
|
||||
sqlite3_log(SQLITE_WARNING, deprecation);
|
||||
} else {
|
||||
char *hmac_salt_mask = sqlite3_mprintf("%02x", sqlcipher_get_hmac_salt_mask());
|
||||
codec_vdbe_return_string(pParse, "cipher_hmac_salt_mask", hmac_salt_mask, P4_DYNAMIC);
|
||||
char *hmac_salt_mask = sqlite3_mprintf("%02x", sqlcipher_get_hmac_salt_mask());
|
||||
codec_vdbe_return_string(pParse, "cipher_hmac_salt_mask", hmac_salt_mask, P4_DYNAMIC);
|
||||
}
|
||||
}
|
||||
}else
|
||||
@@ -327,9 +337,15 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
|
||||
sqlite3_free(salt);
|
||||
}
|
||||
} else {
|
||||
char *salt = (char*) sqlite3_malloc((FILE_HEADER_SZ*2)+1);
|
||||
cipher_bin2hex(sqlcipher_codec_ctx_get_kdf_salt(ctx), FILE_HEADER_SZ, salt);
|
||||
codec_vdbe_return_string(pParse, "cipher_salt", salt, P4_DYNAMIC);
|
||||
void *salt;
|
||||
char *hexsalt = (char*) sqlite3_malloc((FILE_HEADER_SZ*2)+1);
|
||||
if((rc = sqlcipher_codec_ctx_get_kdf_salt(ctx, &salt)) == SQLITE_OK) {
|
||||
cipher_bin2hex(salt, FILE_HEADER_SZ, hexsalt);
|
||||
codec_vdbe_return_string(pParse, "cipher_salt", hexsalt, P4_DYNAMIC);
|
||||
} else {
|
||||
sqlite3_free(hexsalt);
|
||||
sqlcipher_codec_ctx_set_error(ctx, rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else
|
||||
@@ -534,6 +550,85 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
|
||||
char *on = sqlite3_mprintf("%d", sqlcipher_get_mem_security());
|
||||
codec_vdbe_return_string(pParse, "cipher_memory_security", on, P4_DYNAMIC);
|
||||
}
|
||||
}else
|
||||
if( sqlite3StrICmp(zLeft,"cipher_settings")==0 ){
|
||||
if(ctx) {
|
||||
int algorithm;
|
||||
char *pragma;
|
||||
|
||||
pragma = sqlite3_mprintf("PRAGMA kdf_iter = %d;", sqlcipher_codec_ctx_get_kdf_iter(ctx));
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_page_size = %d;", sqlcipher_codec_ctx_get_pagesize(ctx));
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_use_hmac = %d;", sqlcipher_codec_ctx_get_use_hmac(ctx));
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_plaintext_header_size = %d;", sqlcipher_codec_ctx_get_plaintext_header_size(ctx));
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
|
||||
algorithm = sqlcipher_codec_ctx_get_hmac_algorithm(ctx);
|
||||
pragma = NULL;
|
||||
if(algorithm == SQLCIPHER_HMAC_SHA1) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA1_LABEL);
|
||||
} else if(algorithm == SQLCIPHER_HMAC_SHA256) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA256_LABEL);
|
||||
} else if(algorithm == SQLCIPHER_HMAC_SHA512) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA512_LABEL);
|
||||
}
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
|
||||
algorithm = sqlcipher_codec_ctx_get_kdf_algorithm(ctx);
|
||||
pragma = NULL;
|
||||
if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL);
|
||||
} else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL);
|
||||
} else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL);
|
||||
}
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
|
||||
}
|
||||
}else
|
||||
if( sqlite3StrICmp(zLeft,"cipher_default_settings")==0 ){
|
||||
int algorithm;
|
||||
char *pragma;
|
||||
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_default_kdf_iter = %d;", sqlcipher_get_default_kdf_iter());
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_default_page_size = %d;", sqlcipher_get_default_pagesize());
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_default_use_hmac = %d;", sqlcipher_get_default_use_hmac());
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_default_plaintext_header_size = %d;", sqlcipher_get_default_plaintext_header_size());
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
|
||||
algorithm = sqlcipher_get_default_hmac_algorithm();
|
||||
pragma = NULL;
|
||||
if(algorithm == SQLCIPHER_HMAC_SHA1) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_default_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA1_LABEL);
|
||||
} else if(algorithm == SQLCIPHER_HMAC_SHA256) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_default_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA256_LABEL);
|
||||
} else if(algorithm == SQLCIPHER_HMAC_SHA512) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_default_hmac_algorithm = %s;", SQLCIPHER_HMAC_SHA512_LABEL);
|
||||
}
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
|
||||
algorithm = sqlcipher_get_default_kdf_algorithm();
|
||||
pragma = NULL;
|
||||
if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_default_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL);
|
||||
} else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_default_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL);
|
||||
} else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
|
||||
pragma = sqlite3_mprintf("PRAGMA cipher_default_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL);
|
||||
}
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
}else {
|
||||
return 0;
|
||||
}
|
||||
@@ -562,7 +657,6 @@ static void* sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
|
||||
int page_sz = sqlcipher_codec_ctx_get_pagesize(ctx);
|
||||
unsigned char *pData = (unsigned char *) data;
|
||||
void *buffer = sqlcipher_codec_ctx_get_data(ctx);
|
||||
void *kdf_salt = sqlcipher_codec_ctx_get_kdf_salt(ctx);
|
||||
int plaintext_header_sz = sqlcipher_codec_ctx_get_plaintext_header_size(ctx);
|
||||
int cctx = CIPHER_READ_CTX;
|
||||
|
||||
@@ -589,7 +683,10 @@ static void* sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
|
||||
memcpy(buffer, plaintext_header_sz ? pData : (void *) SQLITE_FILE_HEADER, offset);
|
||||
|
||||
rc = sqlcipher_page_cipher(ctx, cctx, pgno, CIPHER_DECRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset);
|
||||
if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
|
||||
if(rc != SQLITE_OK) { /* clear results of failed cipher operation and set error */
|
||||
sqlcipher_memset((unsigned char*) buffer+offset, 0, page_sz-offset);
|
||||
sqlcipher_codec_ctx_set_error(ctx, rc);
|
||||
}
|
||||
memcpy(pData, buffer, page_sz); /* copy buffer data back to pData and return */
|
||||
return pData;
|
||||
break;
|
||||
@@ -598,11 +695,20 @@ static void* sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
|
||||
cctx = CIPHER_WRITE_CTX;
|
||||
|
||||
case CODEC_JOURNAL_OP: /* encrypt journal page, operate on read context use to get the original page data from the database */
|
||||
if(pgno == 1) /* copy initial part of file header or salt to buffer */
|
||||
if(pgno == 1) { /* copy initial part of file header or salt to buffer */
|
||||
void *kdf_salt = NULL;
|
||||
/* retrieve the kdf salt */
|
||||
if((rc = sqlcipher_codec_ctx_get_kdf_salt(ctx, &kdf_salt)) != SQLITE_OK) {
|
||||
sqlcipher_codec_ctx_set_error(ctx, rc);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(buffer, plaintext_header_sz ? pData : kdf_salt, offset);
|
||||
|
||||
}
|
||||
rc = sqlcipher_page_cipher(ctx, cctx, pgno, CIPHER_ENCRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset);
|
||||
if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
|
||||
if(rc != SQLITE_OK) { /* clear results of failed cipher operation and set error */
|
||||
sqlcipher_memset((unsigned char*)buffer+offset, 0, page_sz-offset);
|
||||
sqlcipher_codec_ctx_set_error(ctx, rc);
|
||||
}
|
||||
return buffer; /* return persistent buffer data, pData remains intact */
|
||||
break;
|
||||
|
||||
@@ -616,7 +722,7 @@ static void* sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
|
||||
static void sqlite3FreeCodecArg(void *pCodecArg) {
|
||||
codec_ctx *ctx = (codec_ctx *) pCodecArg;
|
||||
if(pCodecArg == NULL) return;
|
||||
sqlcipher_codec_ctx_free(&ctx); // wipe and free allocated memory for the context
|
||||
sqlcipher_codec_ctx_free(&ctx); /* wipe and free allocated memory for the context */
|
||||
sqlcipher_deactivate(); /* cleanup related structures, OpenSSL etc, when codec is detatched */
|
||||
}
|
||||
|
||||
@@ -651,7 +757,7 @@ int sqlite3CodecAttach(sqlite3* db, int nDb, const void *zKey, int nKey) {
|
||||
|
||||
/* point the internal codec argument against the contet to be prepared */
|
||||
CODEC_TRACE("sqlite3CodecAttach: calling sqlcipher_codec_ctx_init()\n");
|
||||
rc = sqlcipher_codec_ctx_init(&ctx, pDb, pDb->pBt->pBt->pPager, fd, zKey, nKey);
|
||||
rc = sqlcipher_codec_ctx_init(&ctx, pDb, pDb->pBt->pBt->pPager, zKey, nKey);
|
||||
|
||||
if(rc != SQLITE_OK) {
|
||||
/* initialization failed, do not attach potentially corrupted context */
|
||||
@@ -813,10 +919,12 @@ void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) {
|
||||
codec_ctx *ctx = (codec_ctx*) sqlite3PagerGetCodec(pDb->pBt->pBt->pPager);
|
||||
|
||||
if(ctx) {
|
||||
if(sqlcipher_codec_get_store_pass(ctx) == 1) {
|
||||
/* pass back the keyspec from the codec, unless PRAGMA cipher_store_pass
|
||||
is set or keyspec has not yet been derived, in which case pass
|
||||
back the password key material */
|
||||
sqlcipher_codec_get_keyspec(ctx, zKey, nKey);
|
||||
if(sqlcipher_codec_get_store_pass(ctx) == 1 || *zKey == NULL) {
|
||||
sqlcipher_codec_get_pass(ctx, zKey, nKey);
|
||||
} else {
|
||||
sqlcipher_codec_get_keyspec(ctx, zKey, nKey);
|
||||
}
|
||||
} else {
|
||||
*zKey = NULL;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user