Snapshot of upstream SQLite 3.27.1

This commit is contained in:
Stephen Lombardo
2019-02-10 10:35:42 -05:00
parent 4d9565b805
commit 4745d8a485
220 changed files with 21148 additions and 2769 deletions
+37 -6
View File
@@ -452,6 +452,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 \
@@ -588,7 +589,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
#
@@ -611,6 +613,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 =
@@ -669,7 +677,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)
@@ -682,11 +690,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
@@ -1052,6 +1075,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
@@ -1189,6 +1213,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) libsqlite3.la
TESTFIXTURE_SRC1 = sqlite3.c
@@ -1291,6 +1316,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)
@@ -1306,6 +1334,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
View File
@@ -1527,6 +1527,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 \
@@ -1625,7 +1626,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
@@ -1643,7 +1645,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
@@ -1730,10 +1738,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)
@@ -2130,6 +2138,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.
@@ -2298,6 +2307,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)
@@ -2425,6 +2435,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)
@@ -2444,6 +2457,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 \
+1 -1
View File
@@ -1 +1 @@
3.26.0
3.27.1
+2
View File
@@ -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
Vendored
+9 -9
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for sqlite 3.26.0.
# Generated by GNU Autoconf 2.69 for sqlite 3.27.1.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -726,8 +726,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.26.0'
PACKAGE_STRING='sqlite 3.26.0'
PACKAGE_VERSION='3.27.1'
PACKAGE_STRING='sqlite 3.27.1'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1466,7 +1466,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures sqlite 3.26.0 to adapt to many kinds of systems.
\`configure' configures sqlite 3.27.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1531,7 +1531,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.26.0:";;
short | recursive ) echo "Configuration of sqlite 3.27.1:";;
esac
cat <<\_ACEOF
@@ -1657,7 +1657,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.26.0
sqlite configure 3.27.1
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2076,7 +2076,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.26.0, which was
It was created by sqlite $as_me 3.27.1, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -12232,7 +12232,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.26.0, which was
This file was extended by sqlite $as_me 3.27.1, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12298,7 +12298,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
sqlite config.status 3.26.0
sqlite config.status 3.27.1
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
+4 -2
View File
@@ -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
View File
@@ -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);
}
}
+14
View File
@@ -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
View File
@@ -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 ){
+7 -8
View File
@@ -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;
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+3 -3
View File
@@ -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
View File
@@ -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 */
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+31 -22
View File
@@ -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:
+27 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+6 -6
View File
@@ -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{
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+2 -2
View File
@@ -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;
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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++;
}
}
+1 -2
View File
@@ -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
View File
@@ -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;
+1 -2
View File
@@ -38,8 +38,7 @@ do_execsql_test 1.0 {
do_execsql_test 1.1 {
DROP TABLE t1;
SELECT name, sql FROM sqlite_master;
} {
}
} {}
#-------------------------------------------------------------------------
#
+6
View File
@@ -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;
}
}
+8
View File
@@ -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
+80
View File
@@ -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
File diff suppressed because one or more lines are too long
+67
View File
@@ -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
+1 -1
View File
@@ -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 {
+65
View File
@@ -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
+18 -6
View File
@@ -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
+38
View File
@@ -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
+64 -2
View File
@@ -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
+34 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+108
View File
@@ -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;
}
-1
View File
@@ -105,4 +105,3 @@ int sqlite3_mmap_warm(sqlite3 *db, const char *zDb){
return rc;
}
+2 -2
View File
@@ -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{
+1 -1
View File
@@ -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));
+319
View File
@@ -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
View File
@@ -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;
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
}
+7 -6
View File
@@ -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
View File
@@ -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
+63
View File
@@ -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
View File
@@ -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);
}
+5 -1
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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{
+14
View File
@@ -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
+13
View File
@@ -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
+66
View File
@@ -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
+777
View File
@@ -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
+3 -3
View File
@@ -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);
+7 -8
View File
@@ -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;
}
-2
View File
@@ -356,5 +356,3 @@ int main(int argc, char **argv){
return 0;
}
+60 -16
View File
@@ -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
+18 -18
View File
@@ -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;
+1 -1
View File
@@ -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
+30 -1
View File
@@ -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)
+224 -199
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
bf8c1b2b7a5960c282e543b9c293686dccff272512d08865f4600fb58238b4f9
0eca3dd3d38b31c92b49ca2d311128b74584714d9e7de895b1a6286ef959a1dd
+46 -10
View File
@@ -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
View File
@@ -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
View File
@@ -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
+278 -123
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 ){
+6 -4
View File
@@ -531,6 +531,10 @@ statNextRestart:
goto statNextRestart; /* Tail recursion */
}
pCsr->iPage++;
if( pCsr->iPage>=ArraySize(pCsr->aPage) ){
statResetCsr(pCsr);
return SQLITE_CORRUPT_BKPT;
}
assert( p==&pCsr->aPage[pCsr->iPage-1] );
if( p->iCell==p->nCell ){
@@ -602,7 +606,6 @@ static int statFilter(
StatTable *pTab = (StatTable*)(pCursor->pVtab);
char *zSql;
int rc = SQLITE_OK;
char *zMaster;
if( idxNum==1 ){
const char *zDbase = (const char*)sqlite3_value_text(argv[0]);
@@ -618,13 +621,12 @@ static int statFilter(
statResetCsr(pCsr);
sqlite3_finalize(pCsr->pStmt);
pCsr->pStmt = 0;
zMaster = pCsr->iDb==1 ? "sqlite_temp_master" : "sqlite_master";
zSql = sqlite3_mprintf(
"SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
" UNION ALL "
"SELECT name, rootpage, type"
" FROM \"%w\".%s WHERE rootpage!=0"
" ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster);
" FROM \"%w\".sqlite_master WHERE rootpage!=0"
" ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName);
if( zSql==0 ){
return SQLITE_NOMEM_BKPT;
}else{
+4 -4
View File
@@ -117,7 +117,7 @@ void sqlite3MaterializeView(
sqlite3 *db = pParse->db;
int iDb = sqlite3SchemaToIndex(db, pView->pSchema);
pWhere = sqlite3ExprDup(db, pWhere, 0);
pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
pFrom = sqlite3SrcListAppend(pParse, 0, 0, 0);
if( pFrom ){
assert( pFrom->nSrc==1 );
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
@@ -517,7 +517,7 @@ void sqlite3DeleteFrom(
/* If this DELETE cannot use the ONEPASS strategy, this is the
** end of the WHERE loop */
if( eOnePass!=ONEPASS_OFF ){
addrBypass = sqlite3VdbeMakeLabel(v);
addrBypass = sqlite3VdbeMakeLabel(pParse);
}else{
sqlite3WhereEnd(pWInfo);
}
@@ -706,7 +706,7 @@ void sqlite3GenerateRowDelete(
/* Seek cursor iCur to the row to delete. If this row no longer exists
** (this can happen if a trigger program has already deleted it), do
** not attempt to delete it or fire any DELETE triggers. */
iLabel = sqlite3VdbeMakeLabel(v);
iLabel = sqlite3VdbeMakeLabel(pParse);
opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
if( eMode==ONEPASS_OFF ){
sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
@@ -912,7 +912,7 @@ int sqlite3GenerateIndexKey(
if( piPartIdxLabel ){
if( pIdx->pPartIdxWhere ){
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
*piPartIdxLabel = sqlite3VdbeMakeLabel(pParse);
pParse->iSelfTab = iDataCur + 1;
sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
SQLITE_JUMPIFNULL);
+399 -281
View File
File diff suppressed because it is too large Load Diff
+12 -10
View File
@@ -329,7 +329,7 @@ static void fkLookupParent(
int i; /* Iterator variable */
Vdbe *v = sqlite3GetVdbe(pParse); /* Vdbe to add code to */
int iCur = pParse->nTab - 1; /* Cursor number to use */
int iOk = sqlite3VdbeMakeLabel(v); /* jump here if parent key found */
int iOk = sqlite3VdbeMakeLabel(pParse); /* jump here if parent key found */
sqlite3VdbeVerifyAbortable(v,
(!pFKey->isDeferred
@@ -602,8 +602,11 @@ static void fkScanChildren(
** NOT( $current_a==a AND $current_b==b AND ... )
**
** The first form is used for rowid tables. The second form is used
** for WITHOUT ROWID tables. In the second form, the primary key is
** (a,b,...)
** for WITHOUT ROWID tables. In the second form, the *parent* key is
** (a,b,...). Either the parent or primary key could be used to
** uniquely identify the current row, but the parent key is more convenient
** as the required values have already been loaded into registers
** by the caller.
*/
if( pTab==pFKey->pFrom && nIncr>0 ){
Expr *pNe; /* Expression (pLeft != pRight) */
@@ -615,14 +618,13 @@ static void fkScanChildren(
pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight);
}else{
Expr *pEq, *pAll = 0;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
assert( pIdx!=0 );
for(i=0; i<pPk->nKeyCol; i++){
for(i=0; i<pIdx->nKeyCol; i++){
i16 iCol = pIdx->aiColumn[i];
assert( iCol>=0 );
pLeft = exprTableRegister(pParse, pTab, regData, iCol);
pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol);
pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zName);
pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight);
pAll = sqlite3ExprAnd(db, pAll, pEq);
}
pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0);
@@ -727,7 +729,7 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break;
}
if( !p ) return;
iSkip = sqlite3VdbeMakeLabel(v);
iSkip = sqlite3VdbeMakeLabel(pParse);
sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); VdbeCoverage(v);
}
@@ -1012,7 +1014,7 @@ void sqlite3FkCheck(
/* Create a SrcList structure containing the child table. We need the
** child table as a SrcList for sqlite3WhereBegin() */
pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
if( pSrc ){
struct SrcList_item *pItem = pSrc->a;
pItem->pTab = pFKey->pFrom;
@@ -1289,7 +1291,7 @@ static Trigger *fkActionTrigger(
}
pSelect = sqlite3SelectNew(pParse,
sqlite3ExprListAppend(pParse, 0, pRaise),
sqlite3SrcListAppend(db, 0, &tFrom, 0),
sqlite3SrcListAppend(pParse, 0, &tFrom, 0),
pWhere,
0, 0, 0, 0, 0
);

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