aboutsummaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/fts3/fts3.c45
-rw-r--r--ext/fts3/fts3Int.h4
-rw-r--r--ext/fts3/fts3_write.c31
-rw-r--r--ext/fts5/fts5_index.c50
-rw-r--r--ext/fts5/fts5_main.c5
-rw-r--r--ext/fts5/fts5_storage.c15
-rw-r--r--ext/fts5/test/fts5corrupt3.test223
-rw-r--r--ext/fts5/test/fts5integrity.test45
-rw-r--r--ext/fts5/test/fts5misc.test72
-rw-r--r--ext/fts5/test/fts5savepoint.test85
-rw-r--r--ext/misc/regexp.c2
-rw-r--r--ext/misc/zipfile.c22
-rw-r--r--ext/rbu/sqlite3rbu.c2
-rw-r--r--ext/rtree/geopoly.c8
-rw-r--r--ext/rtree/rtree.c27
15 files changed, 552 insertions, 84 deletions
diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c
index 5067c1cf0..77738eb54 100644
--- a/ext/fts3/fts3.c
+++ b/ext/fts3/fts3.c
@@ -308,18 +308,6 @@
SQLITE_EXTENSION_INIT1
#endif
-/*
-** The following are copied from sqliteInt.h.
-**
-** Constants for the largest and smallest possible 64-bit signed integers.
-** These macros are designed to work correctly on both 32-bit and 64-bit
-** compilers.
-*/
-#ifndef SQLITE_AMALGAMATION
-# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
-#endif
-
static int fts3EvalNext(Fts3Cursor *pCsr);
static int fts3EvalStart(Fts3Cursor *pCsr);
static int fts3TermSegReaderCursor(
@@ -364,12 +352,7 @@ int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
v = (*ptr++); \
if( (v & mask2)==0 ){ var = v; return ret; }
-/*
-** Read a 64-bit variable-length integer from memory starting at p[0].
-** Return the number of bytes read, or 0 on error.
-** The value is stored in *v.
-*/
-int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
+int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){
const unsigned char *p = (const unsigned char*)pBuf;
const unsigned char *pStart = p;
u32 a;
@@ -392,6 +375,15 @@ int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
}
/*
+** Read a 64-bit variable-length integer from memory starting at p[0].
+** Return the number of bytes read, or 0 on error.
+** The value is stored in *v.
+*/
+int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
+ return sqlite3Fts3GetVarintU(pBuf, (sqlite3_uint64*)v);
+}
+
+/*
** Read a 64-bit variable-length integer from memory starting at p[0] and
** not extending past pEnd[-1].
** Return the number of bytes read, or 0 on error.
@@ -2496,12 +2488,12 @@ static void fts3GetDeltaVarint3(
if( *pp>=pEnd ){
*pp = 0;
}else{
- sqlite3_int64 iVal;
- *pp += sqlite3Fts3GetVarint(*pp, &iVal);
+ u64 iVal;
+ *pp += sqlite3Fts3GetVarintU(*pp, &iVal);
if( bDescIdx ){
- *pVal -= iVal;
+ *pVal = (i64)((u64)*pVal - iVal);
}else{
- *pVal += iVal;
+ *pVal = (i64)((u64)*pVal + iVal);
}
}
}
@@ -2531,10 +2523,10 @@ static void fts3PutDeltaVarint3(
sqlite3_uint64 iWrite;
if( bDescIdx==0 || *pbFirst==0 ){
assert_fts3_nc( *pbFirst==0 || iVal>=*piPrev );
- iWrite = iVal - *piPrev;
+ iWrite = (u64)iVal - (u64)*piPrev;
}else{
assert_fts3_nc( *piPrev>=iVal );
- iWrite = *piPrev - iVal;
+ iWrite = (u64)*piPrev - (u64)iVal;
}
assert( *pbFirst || *piPrev==0 );
assert_fts3_nc( *pbFirst==0 || iWrite>0 );
@@ -2553,7 +2545,8 @@ static void fts3PutDeltaVarint3(
** Using this makes it easier to write code that can merge doclists that are
** sorted in either ascending or descending order.
*/
-#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1-i2))
+/* #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i64)((u64)i1-i2)) */
+#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1>i2?1:((i1==i2)?0:-1)))
/*
** This function does an "OR" merge of two doclists (output contains all
@@ -2967,7 +2960,7 @@ static int fts3SegReaderCursor(
** Fts3SegReaderPending might segfault, as the data structures used by
** fts4aux are not completely populated. So it's easiest to filter these
** calls out here. */
- if( iLevel<0 && p->aIndex ){
+ if( iLevel<0 && p->aIndex && p->iPrevLangid==iLangid ){
Fts3SegReader *pSeg = 0;
rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg);
if( rc==SQLITE_OK && pSeg ){
diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h
index 26b23b66f..50370a910 100644
--- a/ext/fts3/fts3Int.h
+++ b/ext/fts3/fts3Int.h
@@ -196,6 +196,9 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
# define TESTONLY(X)
#endif
+#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
+#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
+
#endif /* SQLITE_AMALGAMATION */
#ifdef SQLITE_DEBUG
@@ -578,6 +581,7 @@ int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
void sqlite3Fts3ErrMsg(char**,const char*,...);
int sqlite3Fts3PutVarint(char *, sqlite3_int64);
int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
+int sqlite3Fts3GetVarintU(const char *, sqlite_uint64 *);
int sqlite3Fts3GetVarintBounded(const char*,const char*,sqlite3_int64*);
int sqlite3Fts3GetVarint32(const char *, int *);
int sqlite3Fts3VarintLen(sqlite3_uint64);
diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c
index a6b45aef2..203b48e2d 100644
--- a/ext/fts3/fts3_write.c
+++ b/ext/fts3/fts3_write.c
@@ -696,7 +696,7 @@ static int fts3PendingListAppend(
assert( !p || p->iLastDocid<=iDocid );
if( !p || p->iLastDocid!=iDocid ){
- sqlite3_int64 iDelta = iDocid - (p ? p->iLastDocid : 0);
+ u64 iDelta = (u64)iDocid - (u64)(p ? p->iLastDocid : 0);
if( p ){
assert( p->nData<p->nSpace );
assert( p->aData[p->nData]==0 );
@@ -1531,18 +1531,18 @@ static int fts3SegReaderNextDocid(
}else{
rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX);
if( rc==SQLITE_OK ){
- sqlite3_int64 iDelta;
- pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta);
+ u64 iDelta;
+ pReader->pOffsetList = p + sqlite3Fts3GetVarintU(p, &iDelta);
if( pTab->bDescIdx ){
- pReader->iDocid -= iDelta;
+ pReader->iDocid = (i64)((u64)pReader->iDocid - iDelta);
}else{
- pReader->iDocid += iDelta;
+ pReader->iDocid = (i64)((u64)pReader->iDocid + iDelta);
}
}
}
}
- return SQLITE_OK;
+ return rc;
}
@@ -2281,6 +2281,7 @@ static int fts3SegWriterAdd(
int rc;
/* The current leaf node is full. Write it out to the database. */
+ if( pWriter->iFree==LARGEST_INT64 ) return FTS_CORRUPT_VTAB;
rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
if( rc!=SQLITE_OK ) return rc;
p->nLeafAdd++;
@@ -2978,10 +2979,10 @@ int sqlite3Fts3SegReaderStep(
sqlite3_int64 iDelta;
if( p->bDescIdx && nDoclist>0 ){
if( iPrev<=iDocid ) return FTS_CORRUPT_VTAB;
- iDelta = iPrev - iDocid;
+ iDelta = (i64)((u64)iPrev - (u64)iDocid);
}else{
if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB;
- iDelta = iDocid - iPrev;
+ iDelta = (i64)((u64)iDocid - (u64)iPrev);
}
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
@@ -3264,7 +3265,7 @@ static int fts3SegmentMerge(
csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist);
}
if( rc!=SQLITE_OK ) goto finished;
- assert( pWriter || bIgnoreEmpty );
+ assert_fts3_nc( pWriter || bIgnoreEmpty );
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
rc = fts3DeleteSegdir(
@@ -5190,12 +5191,12 @@ static u64 fts3ChecksumIndex(
i64 iDocid = 0;
i64 iCol = 0;
- i64 iPos = 0;
+ u64 iPos = 0;
pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid);
while( pCsr<pEnd ){
- i64 iVal = 0;
- pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
+ u64 iVal = 0;
+ pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
if( pCsr<pEnd ){
if( iVal==0 || iVal==1 ){
iCol = 0;
@@ -5203,11 +5204,11 @@ static u64 fts3ChecksumIndex(
if( iVal ){
pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
}else{
- pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
+ pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
if( p->bDescIdx ){
- iDocid -= iVal;
+ iDocid = (i64)((u64)iDocid - iVal);
}else{
- iDocid += iVal;
+ iDocid = (i64)((u64)iDocid + iVal);
}
}
}else{
diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c
index 015696f7b..eb20af816 100644
--- a/ext/fts5/fts5_index.c
+++ b/ext/fts5/fts5_index.c
@@ -5318,10 +5318,13 @@ int sqlite3Fts5IndexCharlenToBytelen(
for(i=0; i<nChar; i++){
if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */
if( (unsigned char)p[n++]>=0xc0 ){
- if( n>=nByte ) break;
+ if( n>=nByte ) return 0;
while( (p[n] & 0xc0)==0x80 ){
n++;
- if( n>=nByte ) break;
+ if( n>=nByte ){
+ if( i+1==nChar ) break;
+ return 0;
+ }
}
}
}
@@ -5723,6 +5726,37 @@ static int fts5QueryCksum(
return rc;
}
+/*
+** Check if buffer z[], size n bytes, contains as series of valid utf-8
+** encoded codepoints. If so, return 0. Otherwise, if the buffer does not
+** contain valid utf-8, return non-zero.
+*/
+static int fts5TestUtf8(const char *z, int n){
+ assert_nc( n>0 );
+ int i = 0;
+ while( i<n ){
+ if( (z[i] & 0x80)==0x00 ){
+ i++;
+ }else
+ if( (z[i] & 0xE0)==0xC0 ){
+ if( i+1>=n || (z[i+1] & 0xC0)!=0x80 ) return 1;
+ i += 2;
+ }else
+ if( (z[i] & 0xF0)==0xE0 ){
+ if( i+2>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
+ i += 3;
+ }else
+ if( (z[i] & 0xF8)==0xF0 ){
+ if( i+3>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
+ if( (z[i+2] & 0xC0)!=0x80 ) return 1;
+ i += 3;
+ }else{
+ return 1;
+ }
+ }
+
+ return 0;
+}
/*
** This function is also purely an internal test. It does not contribute to
@@ -5763,8 +5797,14 @@ static void fts5TestTerm(
** This check may only be performed if the hash table is empty. This
** is because the hash table only supports a single scan query at
** a time, and the multi-iter loop from which this function is called
- ** is already performing such a scan. */
- if( p->nPendingData==0 ){
+ ** is already performing such a scan.
+ **
+ ** Also only do this if buffer zTerm contains nTerm bytes of valid
+ ** utf-8. Otherwise, the last part of the buffer contents might contain
+ ** a non-utf-8 sequence that happens to be a prefix of a valid utf-8
+ ** character stored in the main fts index, which will cause the
+ ** test to fail. */
+ if( p->nPendingData==0 && 0==fts5TestUtf8(zTerm, nTerm) ){
if( iIdx>0 && rc==SQLITE_OK ){
int f = flags|FTS5INDEX_QUERY_TEST_NOIDX;
ck2 = 0;
@@ -5897,8 +5937,8 @@ static void fts5IndexIntegrityCheckSegment(
i64 iRow; /* Rowid for this leaf */
Fts5Data *pLeaf; /* Data for this leaf */
+ const char *zIdxTerm = (const char*)sqlite3_column_blob(pStmt, 1);
int nIdxTerm = sqlite3_column_bytes(pStmt, 1);
- const char *zIdxTerm = (const char*)sqlite3_column_text(pStmt, 1);
int iIdxLeaf = sqlite3_column_int(pStmt, 2);
int bIdxDlidx = sqlite3_column_int(pStmt, 3);
diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c
index 0980c5b4d..347bf7f23 100644
--- a/ext/fts5/fts5_main.c
+++ b/ext/fts5/fts5_main.c
@@ -289,7 +289,10 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
case FTS5_ROLLBACKTO:
assert( p->ts.eState==1 );
assert( iSavepoint>=-1 );
- assert( iSavepoint<=p->ts.iSavepoint );
+ /* The following assert() can fail if another vtab strikes an error
+ ** within an xSavepoint() call then SQLite calls xRollbackTo() - without
+ ** having called xSavepoint() on this vtab. */
+ /* assert( iSavepoint<=p->ts.iSavepoint ); */
p->ts.iSavepoint = iSavepoint;
break;
}
diff --git a/ext/fts5/fts5_storage.c b/ext/fts5/fts5_storage.c
index c5bf8024d..22f90c0ef 100644
--- a/ext/fts5/fts5_storage.c
+++ b/ext/fts5/fts5_storage.c
@@ -613,10 +613,11 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
+ const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1);
+ int nText = sqlite3_column_bytes(pScan, ctx.iCol+1);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_column_text(pScan, ctx.iCol+1),
- sqlite3_column_bytes(pScan, ctx.iCol+1),
+ zText, nText,
(void*)&ctx,
fts5StorageInsertCallback
);
@@ -738,10 +739,11 @@ int sqlite3Fts5StorageIndexInsert(
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
+ const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]);
+ int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_value_text(apVal[ctx.iCol+2]),
- sqlite3_value_bytes(apVal[ctx.iCol+2]),
+ zText, nText,
(void*)&ctx,
fts5StorageInsertCallback
);
@@ -910,10 +912,11 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
if( rc==SQLITE_OK ){
+ const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
+ int nText = sqlite3_column_bytes(pScan, i+1);
rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_column_text(pScan, i+1),
- sqlite3_column_bytes(pScan, i+1),
+ zText, nText,
(void*)&ctx,
fts5StorageIntegrityCallback
);
diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test
index 2d6856d05..4e0ae64a9 100644
--- a/ext/fts5/test/fts5corrupt3.test
+++ b/ext/fts5/test/fts5corrupt3.test
@@ -9886,6 +9886,229 @@ do_catchsql_test 67.1 {
), * FROM ttt('e')
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+#
+reset_db
+do_test 68.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 32768 pagesize 4096 filename crash-41234e232809e7.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 08 .....@ ........
+| 32: 00 00 00 02 00 00 00 01 00 00 00 09 00 00 00 04 ................
+| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
+| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 0d 92 00 00 00 00 ...k............
+| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
+| 3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
+| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
+| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
+| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
+| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
+| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
+| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
+| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
+| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
+| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
+| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
+| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
+| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
+| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
+| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
+| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
+| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
+| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
+| 3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, c1, c2)i....
+| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
+| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
+| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
+| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
+| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
+| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
+| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
+| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
+| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
+| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
+| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
+| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
+| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
+| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
+| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
+| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c).........
+| page 3 offset 8192
+| 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00 ................
+| 16: 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
+| 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J..........
+| 3232: 00 00 03 2b 02 30 30 01 02 06 01 02 06 01 02 06 ...+.00.........
+| 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160
+| 3264: 36 30 39 01 02 07 01 02 07 01 02 07 00 01 34 01 609...........4.
+| 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5.....
+| 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000...
+| 3312: 01 02 04 01 02 03 f1 06 62 69 6e 62 72 79 03 06 ........binbry..
+| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 01 03 16 01 ................
+| 3344: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3376: 03 04 71 02 02 03 06 11 02 02 01 08 63 6f 6d 70 ..q.........comp
+| 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d
+| 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat...........
+| 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e
+| 3440: 6e 61 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 nable...........
+| 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 03 02 ................
+| 3472: 00 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
+| 3488: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
+| 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension..
+| 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 0a 02 03 .........fts4...
+| 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5.......
+| 3552: 02 03 01 03 66 63 63 01 02 03 01 02 03 01 02 03 ....fcc.........
+| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 01 02 03 01 02 ..eopoly........
+| 3584: 03 01 05 6a 73 6f 5e 31 13 02 03 01 02 03 01 02 ...jso^1........
+| 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load.........
+| 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max...........
+| 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory...........
+| 3648: 73 79 73 35 16 02 03 01 02 03 01 02 03 01 06 6e sys5...........n
+| 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase...........
+| 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 13 06 ................
+| 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 02 ...omit.........
+| 3744: 01 05 72 74 72 65 65 19 02 03 01 02 03 01 02 03 ..rtree.........
+| 3760: 04 02 69 6d 01 06 01 02 02 03 06 01 12 02 03 06 ..im............
+| 3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
+| 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
+| 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
+| 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 22 02 02 01 ..threadsafe....
+| 3840: 02 02 01 02 02 01 04 76 74 61 62 07 02 04 01 02 .......vtab.....
+| 3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01 ......x.........
+| 3872: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
+| 3888: 01 06 01 01 02 01 06 01 01 02 01 05 f1 01 02 01 ................
+| 3904: 06 01 01 02 01 06 01 5b 02 01 06 01 01 02 01 06 .......[........
+| 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 3936: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
+| 3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
+| 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
+| 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
+| 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
+| 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
+| 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................
+| 4048: 12 44 13 11 0f 47 13 0f 0c 0e 11 10 0f 0e 10 0f .D...G..........
+| 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$.
+| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
+| page 4 offset 12288
+| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0b 01 02 ................
+| page 5 offset 16384
+| 0: 0d 00 00 00 24 0c 0a 00 0f d8 0f af 0f 86 0f 74 ....$..........t
+| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./..........
+| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$......
+| 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5....
+| 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$..
+| 3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f ...........$..%.
+| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI
+| 3104: 4f 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 OARY.#..%..THREA
+| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE..
+| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE=
+| 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM
+| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO
+| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O
+| 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI
+| 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3..
+| 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS
+| 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3..
+| 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000
+| 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3.
+| 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000
+| 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3
+| 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500
+| 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....%
+| 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB
+| 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3392: 4c 45 20 52 54 52 46 45 58 4e 4f 43 41 53 45 17 LE RTRFEXNOCASE.
+| 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR
+| 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E
+| 3440: 49 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 IABLE MEMSYS5XBI
+| 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL
+| 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE
+| 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME
+| 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....%
+| 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB
+| 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE.
+| 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO
+| 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E
+| 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 57 42 49 NABLE GEOPOLYWBI
+| 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL
+| 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 42 41 53 45 E GEOPOLYXNOBASE
+| 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE
+| 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....#
+| 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI
+| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL
+| 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE...
+| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X
+| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB
+| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY..
+| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4
+| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN
+| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM.
+| 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY.
+| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE.
+| 3888: 07 05 00 31 0f 17 b7 4e 41 42 4c 45 20 44 42 53 ...1...NABLE DBS
+| 3904: 54 41 54 20 66 54 41 42 58 52 54 52 49 4d 11 06 TAT fTABXRTRIM..
+| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR
+| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO
+| 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG
+| 3968: 58 62 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XbTRIM'...C..COM
+| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0
+| 4000: 32 30 31 36 30 36 30 39 52 02 4a 4e 41 52 59 27 20160609R.JNARY'
+| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g
+| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060
+| 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C
+| 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4.
+| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM
+| page 6 offset 20480
+| 0: 0d 00 00 00 24 0e e0 00 0f f8 0f f0 0f e8 0f e0 ....$...........
+| 16: 0f d8 0f d0 0f c8 0f c0 0f b8 0f b0 0f a8 0f a0 ................
+| 32: 0f 98 0f 90 0f 88 0f 80 0f 78 0f 70 0f 68 0f 60 .........x.p.h.`
+| 48: 0f 58 0f 50 0f 48 0f 40 0f 38 0f 30 0f 28 0f 20 .X.P.H.@.8.0.(.
+| 64: 0f 18 0f 10 0f 08 0f 00 0e f8 0e f0 0e e8 0e e0 ................
+| 3808: 06 24 03 00 12 02 01 01 06 23 03 00 12 02 01 01 .$.......#......
+| 3824: 06 22 03 00 12 02 01 01 06 21 03 00 12 03 01 01 .........!......
+| 3840: 06 20 03 00 12 03 01 01 06 1f 03 00 12 03 01 01 . ..............
+| 3856: 06 1e 03 00 12 03 01 01 06 1d 03 00 12 03 01 01 ................
+| 3872: 06 1c 03 00 12 03 01 01 06 1b 03 00 12 02 01 01 ................
+| 3888: 06 1a 03 00 12 02 01 01 06 19 03 00 12 02 01 01 ................
+| 3904: 06 18 03 00 12 02 01 01 06 17 03 00 12 02 01 01 ................
+| 3920: 06 16 03 00 12 02 01 01 06 15 03 00 12 02 01 01 ................
+| 3936: 06 14 03 00 12 02 01 01 06 13 03 00 12 02 01 01 ................
+| 3952: 06 12 03 00 12 02 01 01 06 11 03 00 12 02 01 01 ................
+| 3968: 06 10 03 00 12 02 01 01 06 0f 03 00 12 02 01 01 ................
+| 3984: 06 0e 03 00 12 02 01 01 06 0d 03 00 12 02 01 01 ................
+| 4000: 06 0c 03 00 12 02 01 01 06 0b 03 00 12 02 01 01 ................
+| 4016: 06 0a 03 00 12 02 01 01 06 09 03 00 12 03 01 01 ................
+| 4032: 06 08 03 00 12 03 01 01 06 07 03 00 12 03 01 01 ................
+| 4048: 06 06 03 00 12 01 01 01 06 05 03 00 12 01 01 01 ................
+| 4064: 06 04 03 00 12 01 01 01 06 03 03 00 12 06 01 01 ................
+| 4080: 06 02 03 00 12 06 01 01 06 01 03 00 12 06 01 01 ................
+| page 7 offset 24576
+| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
+| page 8 offset 28672
+| 0: 0d 00 00 00 03 0f d6 00 0f f4 0f e9 0f d6 00 00 ................
+| 4048: 00 00 00 00 00 00 11 04 02 2b 69 6e 74 65 67 72 .........+integr
+| 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb
+| 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 5d 69 71 a5 uild....opti]iq.
+| end crash-41234e232809e7.db
+.testctrl prng_seed 1 db
+}]} {}
+
+do_catchsql_test 68.1 {
+ PRAGMA reverse_unordered_selects=ON;
+ INSERT INTO t1(t1) SELECT x FROM t2;
+} {1 {database disk image is malformed}}
+
+
sqlite3_fts5_may_be_corrupt 0
finish_test
diff --git a/ext/fts5/test/fts5integrity.test b/ext/fts5/test/fts5integrity.test
index 25c727730..72cdeb3e3 100644
--- a/ext/fts5/test/fts5integrity.test
+++ b/ext/fts5/test/fts5integrity.test
@@ -210,4 +210,49 @@ foreach {tn pgsz} {
} {1000}
}
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 7.0 {
+ PRAGMA encoding = 'UTF-16';
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0);
+ INSERT INTO vt0 VALUES (x'46f0');
+ SELECT quote(c0) FROM vt0;
+} {X'46F0'}
+do_execsql_test 7.1 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+do_execsql_test 7.2 {
+ INSERT INTO vt0(vt0) VALUES('rebuild');
+}
+do_execsql_test 7.3 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+do_execsql_test 7.4 {
+ UPDATE vt0 SET c0='';
+}
+do_execsql_test 7.5 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+#-------------------------------------------------------------------------
+# Ticket 7a458c2a5f4
+#
+reset_db
+do_execsql_test 8.0 {
+ PRAGMA locking_mode = EXCLUSIVE;
+ PRAGMA journal_mode = PERSIST;
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0);
+} {exclusive persist}
+do_execsql_test 8.1 {
+ PRAGMA data_version
+} {1}
+do_execsql_test 8.2 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+ PRAGMA data_version;
+} {1}
+do_execsql_test 8.1 {
+ INSERT INTO vt0(vt0, rank) VALUES('usermerge', 2);
+}
+
finish_test
diff --git a/ext/fts5/test/fts5misc.test b/ext/fts5/test/fts5misc.test
index e2f4b2d09..9abc92b23 100644
--- a/ext/fts5/test/fts5misc.test
+++ b/ext/fts5/test/fts5misc.test
@@ -250,6 +250,78 @@ do_execsql_test 9.2 {
-4764623217061966105 8324454597464624651
}
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 10.0 {
+ CREATE VIRTUAL TABLE vt1 USING fts5(c1, c2, prefix = 1, tokenize = "ascii");
+ INSERT INTO vt1 VALUES (x'e4', '䔬');
+}
+
+do_execsql_test 10.1 {
+ SELECT quote(CAST(c1 AS blob)), quote(CAST(c2 AS blob)) FROM vt1
+} {X'E4' X'E494AC'}
+
+do_execsql_test 10.2 {
+ INSERT INTO vt1(vt1) VALUES('integrity-check');
+}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 11.0 {
+ CREATE VIRTUAL TABLE vt0 USING fts5(
+ c0, prefix = 71, tokenize = "porter ascii", prefix = 9
+ );
+} {}
+do_execsql_test 11.1 {
+ BEGIN;
+ INSERT INTO vt0(c0) VALUES (x'e8');
+}
+do_execsql_test 11.2 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+#-------------------------------------------------------------------------
+# Ticket [752fdbf6]
+#
+reset_db
+do_execsql_test 11.0 {
+ PRAGMA encoding = 'UTF-16';
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0, c1);
+ INSERT INTO vt0(vt0, rank) VALUES('pgsz', '37');
+ INSERT INTO vt0(c0, c1) VALUES (0.66077, 1957391816);
+}
+do_execsql_test 11.1 {
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+}
+
+#-------------------------------------------------------------------------
+# Ticket [7c0e06b16]
+#
+do_execsql_test 12.0 {
+ CREATE TABLE t1(a, b, rank);
+ INSERT INTO t1 VALUES('a', 'hello', '');
+ INSERT INTO t1 VALUES('b', 'world', '');
+
+ CREATE VIRTUAL TABLE ft USING fts5(a);
+ INSERT INTO ft VALUES('b');
+ INSERT INTO ft VALUES('y');
+
+ CREATE TABLE t2(x, y, ft);
+ INSERT INTO t2 VALUES(1, 2, 'x');
+ INSERT INTO t2 VALUES(3, 4, 'b');
+}
+
+do_execsql_test 12.1 {
+ SELECT * FROM t1 NATURAL JOIN ft WHERE ft MATCH('b')
+} {b world {}}
+do_execsql_test 12.2 {
+ SELECT * FROM ft NATURAL JOIN t1 WHERE ft MATCH('b')
+} {b world {}}
+do_execsql_test 12.3 {
+ SELECT * FROM t2 JOIN ft USING (ft)
+} {3 4 b b}
finish_test
diff --git a/ext/fts5/test/fts5savepoint.test b/ext/fts5/test/fts5savepoint.test
new file mode 100644
index 000000000..e431f9f5f
--- /dev/null
+++ b/ext/fts5/test/fts5savepoint.test
@@ -0,0 +1,85 @@
+# 2019 Dec 26
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5savepoint
+
+# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(c);
+ BEGIN;
+ SAVEPOINT one;
+ INSERT INTO ft VALUES('a');
+ SAVEPOINT two;
+ INSERT INTO ft VALUES('b');
+ RELEASE two;
+ SAVEPOINT four;
+ INSERT INTO ft VALUES('c');
+ RELEASE four;
+ SAVEPOINT three;
+ INSERT INTO ft VALUES('d');
+ ROLLBACK TO three;
+ COMMIT;
+ SELECT * FROM ft
+} {a b c}
+
+reset_db
+do_catchsql_test 2.0 {
+ CREATE VIRTUAL TABLE ft1 USING fts5(c);
+ CREATE VIRTUAL TABLE ft2 USING fts5(c);
+ DROP TABLE ft2_idx;
+ BEGIN;
+ INSERT INTO ft2 VALUES('a');
+ INSERT INTO ft1 VALUES('a');
+ SAVEPOINT two;
+ INSERT INTO ft1 VALUES('b');
+ COMMIT;
+} {1 {SQL logic error}}
+
+reset_db
+ifcapable fts3 {
+ do_execsql_test 3.0 {
+ CREATE VIRTUAL TABLE vt0 USING fts5(c0);
+ CREATE VIRTUAL TABLE vt1 USING fts4(c0);
+ INSERT INTO vt1(c0) VALUES(0);
+ }
+
+ do_execsql_test 3.1 {
+ BEGIN;
+ UPDATE vt1 SET c0 = 0;
+ INSERT INTO vt1(c0) VALUES (0), (0);
+ UPDATE vt0 SET c0 = 0;
+ INSERT INTO vt1(c0) VALUES (0);
+ UPDATE vt1 SET c0 = 0;
+ INSERT INTO vt1(vt1) VALUES('automerge=1');
+ UPDATE vt1 SET c0 = 0;
+ }
+
+ do_catchsql_test 3.2 {
+ DROP TABLE vt1;
+ } {1 {SQL logic error}}
+
+ do_execsql_test 3.3 {
+ SAVEPOINT x;
+ INSERT INTO vt0 VALUES('x');
+ COMMIT;
+ INSERT INTO vt0(vt0) VALUES('integrity-check');
+ }
+}
+
+finish_test
+
diff --git a/ext/misc/regexp.c b/ext/misc/regexp.c
index 3359109ab..a97290511 100644
--- a/ext/misc/regexp.c
+++ b/ext/misc/regexp.c
@@ -156,7 +156,7 @@ static unsigned re_next_char(ReInput *p){
&& (p->z[p->i+1]&0xc0)==0x80 ){
c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
p->i += 2;
- if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
+ if( c<=0x7ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
}else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
&& (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
diff --git a/ext/misc/zipfile.c b/ext/misc/zipfile.c
index 0d66f6a6f..326228337 100644
--- a/ext/misc/zipfile.c
+++ b/ext/misc/zipfile.c
@@ -999,7 +999,6 @@ static int zipfileDeflate(
int res;
str.next_out = aOut;
str.avail_out = nAlloc;
- deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
res = deflate(&str, Z_FINISH);
if( res==Z_STREAM_END ){
*ppOut = aOut;
@@ -1434,8 +1433,8 @@ static int zipfileGetMode(
** identical, ignoring any trailing '/' character in either path. */
static int zipfileComparePath(const char *zA, const char *zB, int nB){
int nA = (int)strlen(zA);
- if( zA[nA-1]=='/' ) nA--;
- if( zB[nB-1]=='/' ) nB--;
+ if( nA>0 && zA[nA-1]=='/' ) nA--;
+ if( nB>0 && zB[nB-1]=='/' ) nB--;
if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
return 1;
}
@@ -1619,6 +1618,7 @@ static int zipfileUpdate(
if( rc==SQLITE_OK ){
zPath = (const char*)sqlite3_value_text(apVal[2]);
+ if( zPath==0 ) zPath = "";
nPath = (int)strlen(zPath);
mTime = zipfileGetTime(apVal[4]);
}
@@ -1628,11 +1628,15 @@ static int zipfileUpdate(
** '/'. This appears to be required for compatibility with info-zip
** (the unzip command on unix). It does not create directories
** otherwise. */
- if( zPath[nPath-1]!='/' ){
+ if( nPath<=0 || zPath[nPath-1]!='/' ){
zFree = sqlite3_mprintf("%s/", zPath);
- if( zFree==0 ){ rc = SQLITE_NOMEM; }
zPath = (const char*)zFree;
- nPath++;
+ if( zFree==0 ){
+ rc = SQLITE_NOMEM;
+ nPath = 0;
+ }else{
+ nPath = (int)strlen(zPath);
+ }
}
}
@@ -2025,19 +2029,19 @@ void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
** at the end of the path. Or, if this is not a directory and the path
** ends in '/' it is an error. */
if( bIsDir==0 ){
- if( zName[nName-1]=='/' ){
+ if( nName>0 && zName[nName-1]=='/' ){
zErr = sqlite3_mprintf("non-directory name must not end with /");
rc = SQLITE_ERROR;
goto zipfile_step_out;
}
}else{
- if( zName[nName-1]!='/' ){
+ if( nName==0 || zName[nName-1]!='/' ){
zName = zFree = sqlite3_mprintf("%s/", zName);
- nName++;
if( zName==0 ){
rc = SQLITE_NOMEM;
goto zipfile_step_out;
}
+ nName = (int)strlen(zName);
}else{
while( nName>1 && zName[nName-2]=='/' ) nName--;
}
diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c
index 5c2ae9545..b2e23b165 100644
--- a/ext/rbu/sqlite3rbu.c
+++ b/ext/rbu/sqlite3rbu.c
@@ -4959,7 +4959,7 @@ static const char *rbuMainToWal(const char *zName, int flags){
}else{
while( *z==0 ) z++;
}
- z += (n + 8 + 1);
+ z += (n + 8 + 2);
return z;
}
diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c
index fa58838a3..312f337b1 100644
--- a/ext/rtree/geopoly.c
+++ b/ext/rtree/geopoly.c
@@ -1345,17 +1345,11 @@ static int geopolyFilter(
RtreeNode *pRoot = 0;
int rc = SQLITE_OK;
int iCell = 0;
- sqlite3_stmt *pStmt;
rtreeReference(pRtree);
/* Reset the cursor to the same state as rtreeOpen() leaves it in. */
- freeCursorConstraints(pCsr);
- sqlite3_free(pCsr->aPoint);
- pStmt = pCsr->pReadAux;
- memset(pCsr, 0, sizeof(RtreeCursor));
- pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
- pCsr->pReadAux = pStmt;
+ resetCursor(pCsr);
pCsr->iStrategy = idxNum;
if( idxNum==1 ){
diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c
index b4d15f6cb..1eef1a1b5 100644
--- a/ext/rtree/rtree.c
+++ b/ext/rtree/rtree.c
@@ -1065,9 +1065,12 @@ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
/*
-** Free the RtreeCursor.aConstraint[] array and its contents.
+** Reset a cursor back to its initial state.
*/
-static void freeCursorConstraints(RtreeCursor *pCsr){
+static void resetCursor(RtreeCursor *pCsr){
+ Rtree *pRtree = (Rtree *)(pCsr->base.pVtab);
+ int ii;
+ sqlite3_stmt *pStmt;
if( pCsr->aConstraint ){
int i; /* Used to iterate through constraint array */
for(i=0; i<pCsr->nConstraint; i++){
@@ -1080,6 +1083,13 @@ static void freeCursorConstraints(RtreeCursor *pCsr){
sqlite3_free(pCsr->aConstraint);
pCsr->aConstraint = 0;
}
+ for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
+ sqlite3_free(pCsr->aPoint);
+ pStmt = pCsr->pReadAux;
+ memset(pCsr, 0, sizeof(RtreeCursor));
+ pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
+ pCsr->pReadAux = pStmt;
+
}
/*
@@ -1087,13 +1097,10 @@ static void freeCursorConstraints(RtreeCursor *pCsr){
*/
static int rtreeClose(sqlite3_vtab_cursor *cur){
Rtree *pRtree = (Rtree *)(cur->pVtab);
- int ii;
RtreeCursor *pCsr = (RtreeCursor *)cur;
assert( pRtree->nCursor>0 );
- freeCursorConstraints(pCsr);
+ resetCursor(pCsr);
sqlite3_finalize(pCsr->pReadAux);
- sqlite3_free(pCsr->aPoint);
- for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
sqlite3_free(pCsr);
pRtree->nCursor--;
nodeBlobReset(pRtree);
@@ -1799,17 +1806,11 @@ static int rtreeFilter(
int ii;
int rc = SQLITE_OK;
int iCell = 0;
- sqlite3_stmt *pStmt;
rtreeReference(pRtree);
/* Reset the cursor to the same state as rtreeOpen() leaves it in. */
- freeCursorConstraints(pCsr);
- sqlite3_free(pCsr->aPoint);
- pStmt = pCsr->pReadAux;
- memset(pCsr, 0, sizeof(RtreeCursor));
- pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
- pCsr->pReadAux = pStmt;
+ resetCursor(pCsr);
pCsr->iStrategy = idxNum;
if( idxNum==1 ){