5dcf5d
From 959187c0035564df5b5a597a3b1ff6c59c49d8e1 Mon Sep 17 00:00:00 2001
5dcf5d
From: Ondrej Dubaj <odubaj@redhat.com>
5dcf5d
Date: Fri, 3 Jan 2020 13:13:18 +0100
5dcf5d
Subject: [PATCH] More improvements to shadow table corruption detection in
5dcf5d
 FTS3.
5dcf5d
5dcf5d
---
5dcf5d
 ext/fts3/fts3.c       |  4 ++++
5dcf5d
 ext/fts3/fts3Int.h    | 16 ++++++++++++++++
5dcf5d
 ext/fts3/fts3_write.c | 12 ++++++++++--
5dcf5d
 3 files changed, 30 insertions(+), 2 deletions(-)
5dcf5d
5dcf5d
diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c
5dcf5d
index c00a13f..2a61d10 100644
5dcf5d
--- a/ext/fts3/fts3.c
5dcf5d
+++ b/ext/fts3/fts3.c
5dcf5d
@@ -1355,6 +1355,10 @@ static int fts3InitVtab(
5dcf5d
   fts3DatabasePageSize(&rc, p);
5dcf5d
   p->nNodeSize = p->nPgsz-35;
5dcf5d
 
5dcf5d
+#if defined(SQLITE_DEBUG)||defined(SQLITE_TEST)
5dcf5d
+  p->nMergeCount = FTS3_MERGE_COUNT;
5dcf5d
+#endif
5dcf5d
+
5dcf5d
   /* Declare the table schema to SQLite. */
5dcf5d
   fts3DeclareVtab(&rc, p);
5dcf5d
 
5dcf5d
diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h
5dcf5d
index b19064c..bd0edfe 100644
5dcf5d
--- a/ext/fts3/fts3Int.h
5dcf5d
+++ b/ext/fts3/fts3Int.h
5dcf5d
@@ -254,8 +254,24 @@ struct Fts3Table {
5dcf5d
   int inTransaction;     /* True after xBegin but before xCommit/xRollback */
5dcf5d
   int mxSavepoint;       /* Largest valid xSavepoint integer */
5dcf5d
 #endif
5dcf5d
+
5dcf5d
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
5dcf5d
+  /* True to disable the incremental doclist optimization. This is controled
5dcf5d
+  ** by special insert command 'test-no-incr-doclist'.  */
5dcf5d
+  int bNoIncrDoclist;
5dcf5d
+
5dcf5d
+  /* Number of segments in a level */
5dcf5d
+  int nMergeCount;
5dcf5d
+#endif
5dcf5d
 };
5dcf5d
 
5dcf5d
+/* Macro to find the number of segments to merge */
5dcf5d
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
5dcf5d
+# define MergeCount(P) ((P)->nMergeCount)
5dcf5d
+#else
5dcf5d
+# define MergeCount(P) FTS3_MERGE_COUNT
5dcf5d
+#endif
5dcf5d
+
5dcf5d
 /*
5dcf5d
 ** When the core wants to read from the virtual table, it creates a
5dcf5d
 ** virtual table cursor (an instance of the following structure) using
5dcf5d
diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c
5dcf5d
index 269d1dd..a557aba 100644
5dcf5d
--- a/ext/fts3/fts3_write.c
5dcf5d
+++ b/ext/fts3/fts3_write.c
5dcf5d
@@ -1130,7 +1130,7 @@ static int fts3AllocateSegdirIdx(
5dcf5d
     ** segment and allocate (newly freed) index 0 at level iLevel. Otherwise,
5dcf5d
     ** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext.
5dcf5d
     */
5dcf5d
-    if( iNext>=FTS3_MERGE_COUNT ){
5dcf5d
+    if( iNext>=MergeCount(p) ){
5dcf5d
       fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel));
5dcf5d
       rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel);
5dcf5d
       *piIdx = 0;
5dcf5d
@@ -4002,6 +4002,10 @@ static int fts3IncrmergeLoad(
5dcf5d
       int i;
5dcf5d
       int nHeight = (int)aRoot[0];
5dcf5d
       NodeWriter *pNode;
5dcf5d
+      if( nHeight<1 || nHeight>FTS_MAX_APPENDABLE_HEIGHT ){
5dcf5d
+        sqlite3_reset(pSelect);
5dcf5d
+        return FTS_CORRUPT_VTAB;
5dcf5d
+      }
5dcf5d
 
5dcf5d
       pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT;
5dcf5d
       pWriter->iStart = iStart;
5dcf5d
@@ -4728,7 +4732,7 @@ static int fts3DoIncrmerge(
5dcf5d
   const char *zParam              /* Nul-terminated string containing "A,B" */
5dcf5d
 ){
5dcf5d
   int rc;
5dcf5d
-  int nMin = (FTS3_MERGE_COUNT / 2);
5dcf5d
+  int nMin = (MergeCount(p) / 2);
5dcf5d
   int nMerge = 0;
5dcf5d
   const char *z = zParam;
5dcf5d
 
5dcf5d
@@ -5049,6 +5053,10 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
5dcf5d
   }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
5dcf5d
     p->nMaxPendingData = atoi(&zVal[11]);
5dcf5d
     rc = SQLITE_OK;
5dcf5d
+  }else if( nVal>11 && 0==sqlite3_strnicmp(zVal,"mergecount=",11) ){
5dcf5d
+    int v = atoi(&zVal[11]);
5dcf5d
+    if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v;
5dcf5d
+    rc = SQLITE_OK;
5dcf5d
 #endif
5dcf5d
   }else{
5dcf5d
     rc = SQLITE_ERROR;
5dcf5d
-- 
5dcf5d
2.19.1
5dcf5d