]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Further tests for fts5.
authordan <dan@noemail.net>
Mon, 27 Apr 2015 11:31:56 +0000 (11:31 +0000)
committerdan <dan@noemail.net>
Mon, 27 Apr 2015 11:31:56 +0000 (11:31 +0000)
FossilOrigin-Name: ffeb3ef3cfec3681b72bb28cfa612aa15e07887d

ext/fts5/fts5.c
ext/fts5/fts5Int.h
ext/fts5/fts5_index.c
ext/fts5/fts5_storage.c
ext/fts5/test/fts5fault2.test
ext/fts5/test/fts5fault3.test [new file with mode: 0644]
ext/fts5/test/fts5merge.test [new file with mode: 0644]
manifest
manifest.uuid

index f8450aab152d2dbb0b26e7e9f8c1eff407c9b710..baa51f4a33ba33dae850ff92f9be40bad89d95a4 100644 (file)
@@ -1055,7 +1055,7 @@ static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){
 static int fts5SpecialInsert(
   Fts5Table *pTab,                /* Fts5 table object */
   sqlite3_value *pCmd,            /* Value inserted into special column */
-  sqlite3_value *pVal             /* Value inserted into rowid column */
+  sqlite3_value *pVal             /* Value inserted into rank column */
 ){
   Fts5Config *pConfig = pTab->pConfig;
   const char *z = (const char*)sqlite3_value_text(pCmd);
@@ -1083,6 +1083,9 @@ static int fts5SpecialInsert(
     }
   }else if( 0==sqlite3_stricmp("optimize", z) ){
     rc = sqlite3Fts5StorageOptimize(pTab->pStorage);
+  }else if( 0==sqlite3_stricmp("merge", z) ){
+    int nMerge = sqlite3_value_int(pVal);
+    rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge);
   }else if( 0==sqlite3_stricmp("integrity-check", z) ){
     rc = sqlite3Fts5StorageIntegrity(pTab->pStorage);
   }else{
index 1e08bd68e04964d92631e556c2c4c07f10290099..c553fac5b8643b44348c250d8380b1ae59c230f8 100644 (file)
@@ -360,6 +360,7 @@ int sqlite3Fts5IndexReads(Fts5Index *p);
 
 int sqlite3Fts5IndexReinit(Fts5Index *p);
 int sqlite3Fts5IndexOptimize(Fts5Index *p);
+int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
 
 int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
 
@@ -459,6 +460,7 @@ int sqlite3Fts5StorageSpecialDelete(Fts5Storage *p, i64 iDel, sqlite3_value**);
 int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);
 int sqlite3Fts5StorageRebuild(Fts5Storage *p);
 int sqlite3Fts5StorageOptimize(Fts5Storage *p);
+int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
 
 /*
 ** End of interface to code in fts5_storage.c.
index 748dd27a7e7217916384df151aac136e770f3457..6990225cae6c9a2065ec1582fcbef9c5130ea0ff 100644 (file)
@@ -823,16 +823,20 @@ static Fts5Data *fts5DataReadOrBuffer(
       /* This call may return SQLITE_ABORT if there has been a savepoint
       ** rollback since it was last used. In this case a new blob handle
       ** is required.  */
-      rc = sqlite3_blob_reopen(p->pReader, iRowid);
-      if( rc==SQLITE_ABORT ){
+      sqlite3_blob *pBlob = p->pReader;
+      p->pReader = 0;
+      rc = sqlite3_blob_reopen(pBlob, iRowid);
+      assert( p->pReader==0 );
+      p->pReader = pBlob;
+      if( rc!=SQLITE_OK ){
         fts5CloseReader(p);
-        rc = SQLITE_OK;
       }
+      if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
     }
 
     /* If the blob handle is not yet open, open and seek it. Otherwise, use
     ** the blob_reopen() API to reseek the existing blob handle.  */
-    if( p->pReader==0 ){
+    if( p->pReader==0 && rc==SQLITE_OK ){
       Fts5Config *pConfig = p->pConfig;
       rc = sqlite3_blob_open(pConfig->db, 
           pConfig->zDb, p->zDataTbl, "block", iRowid, 0, &p->pReader
@@ -2770,7 +2774,6 @@ static void fts5ChunkIterRelease(Fts5ChunkIter *pIter){
 ** returned in this case.
 */
 static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
-  int i;
   u32 iSegid = 0;
 
   if( p->rc==SQLITE_OK ){
@@ -3227,11 +3230,11 @@ static void fts5WriteInitForAppend(
   pWriter->iIdx = iIdx;
   pWriter->iSegid = pSeg->iSegid;
   pWriter->aWriter = (Fts5PageWriter*)fts5IdxMalloc(p, nByte);
-  pWriter->nWriter = pSeg->nHeight;
 
   if( p->rc==SQLITE_OK ){
     int pgno = 1;
     int i;
+    pWriter->nWriter = pSeg->nHeight;
     pWriter->aWriter[0].pgno = pSeg->pgnoLast+1;
     for(i=pSeg->nHeight-1; i>0; i--){
       i64 iRowid = FTS5_SEGMENT_ROWID(pWriter->iIdx, pWriter->iSegid, i, pgno);
@@ -3250,7 +3253,7 @@ static void fts5WriteInitForAppend(
     if( pSeg->nHeight==1 ){
       pWriter->nEmpty = pSeg->pgnoLast-1;
     }
-    assert( (pgno+pWriter->nEmpty)==pSeg->pgnoLast );
+    assert( p->rc!=SQLITE_OK || (pgno+pWriter->nEmpty)==pSeg->pgnoLast );
     pWriter->bFirstTermInPage = 1;
     assert( pWriter->aWriter[0].term.n==0 );
   }
@@ -3351,7 +3354,6 @@ static void fts5IndexMergeLevel(
     fts5WriteInit(p, &writer, iIdx, iSegid);
 
     /* Add the new segment to the output level */
-    if( iLvl+1==pStruct->nLevel ) pStruct->nLevel++;
     pSeg = &pLvlOut->aSeg[pLvlOut->nSeg];
     pLvlOut->nSeg++;
     pSeg->pgnoFirst = 1;
@@ -3447,6 +3449,59 @@ fflush(stdout);
   if( pnRem ) *pnRem -= writer.nLeafWritten;
 }
 
+/*
+** Do up to nPg pages of automerge work on index iIdx.
+*/
+static void fts5IndexMerge(
+  Fts5Index *p,                   /* FTS5 backend object */
+  int iIdx,                       /* Index to work on */
+  Fts5Structure **ppStruct,       /* IN/OUT: Current structure of index */
+  int nPg                         /* Pages of work to do */
+){
+  int nRem = nPg;
+  Fts5Structure *pStruct = *ppStruct;
+  while( nRem>0 && p->rc==SQLITE_OK ){
+    int iLvl;                   /* To iterate through levels */
+    int iBestLvl = 0;           /* Level offering the most input segments */
+    int nBest = 0;              /* Number of input segments on best level */
+
+    /* Set iBestLvl to the level to read input segments from. */
+    assert( pStruct->nLevel>0 );
+    for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+      Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
+      if( pLvl->nMerge ){
+        if( pLvl->nMerge>nBest ){
+          iBestLvl = iLvl;
+          nBest = pLvl->nMerge;
+        }
+        break;
+      }
+      if( pLvl->nSeg>nBest ){
+        nBest = pLvl->nSeg;
+        iBestLvl = iLvl;
+      }
+    }
+
+    /* If nBest is still 0, then the index must be empty. */
+#ifdef SQLITE_DEBUG
+    for(iLvl=0; nBest==0 && iLvl<pStruct->nLevel; iLvl++){
+      assert( pStruct->aLevel[iLvl].nSeg==0 );
+    }
+#endif
+
+    if( nBest<p->pConfig->nAutomerge 
+        && pStruct->aLevel[iBestLvl].nMerge==0 
+      ){
+      break;
+    }
+    fts5IndexMergeLevel(p, iIdx, &pStruct, iBestLvl, &nRem);
+    if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
+      fts5StructurePromote(p, iBestLvl+1, pStruct);
+    }
+  }
+  *ppStruct = pStruct;
+}
+
 /*
 ** A total of nLeaf leaf pages of data has just been flushed to a level-0
 ** segments in index iIdx with structure pStruct. This function updates the
@@ -3456,13 +3511,13 @@ fflush(stdout);
 ** If an error occurs, set the Fts5Index.rc error code. If an error has 
 ** already occurred, this function is a no-op.
 */
-static void fts5IndexWork(
+static void fts5IndexAutomerge(
   Fts5Index *p,                   /* FTS5 backend object */
   int iIdx,                       /* Index to work on */
   Fts5Structure **ppStruct,       /* IN/OUT: Current structure of index */
   int nLeaf                       /* Number of output leaves just written */
 ){
-  if( p->rc==SQLITE_OK ){
+  if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 ){
     Fts5Structure *pStruct = *ppStruct;
     i64 nWrite;                   /* Initial value of write-counter */
     int nWork;                    /* Number of work-quanta to perform */
@@ -3474,62 +3529,21 @@ static void fts5IndexWork(
     pStruct->nWriteCounter += nLeaf;
     nRem = p->nWorkUnit * nWork * pStruct->nLevel;
 
-    while( nRem>0 ){
-      int iLvl;                   /* To iterate through levels */
-      int iBestLvl = 0;           /* Level offering the most input segments */
-      int nBest = 0;              /* Number of input segments on best level */
-
-      /* Set iBestLvl to the level to read input segments from. */
-      assert( pStruct->nLevel>0 );
-      for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
-        Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
-        if( pLvl->nMerge ){
-          if( pLvl->nMerge>nBest ){
-            iBestLvl = iLvl;
-            nBest = pLvl->nMerge;
-          }
-          break;
-        }
-        if( pLvl->nSeg>nBest ){
-          nBest = pLvl->nSeg;
-          iBestLvl = iLvl;
-        }
-      }
-
-      /* If nBest is still 0, then the index must be empty. */
-#ifdef SQLITE_DEBUG
-      for(iLvl=0; nBest==0 && iLvl<pStruct->nLevel; iLvl++){
-        assert( pStruct->aLevel[iLvl].nSeg==0 );
-      }
-#endif
-
-      if( nBest<p->pConfig->nAutomerge 
-       && pStruct->aLevel[iBestLvl].nMerge==0 
-      ){
-        break;
-      }
-      fts5IndexMergeLevel(p, iIdx, &pStruct, iBestLvl, &nRem);
-      assert( nRem==0 || p->rc==SQLITE_OK );
-      if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
-        fts5StructurePromote(p, iBestLvl+1, pStruct);
-      }
-      *ppStruct = pStruct;
-    }
-
+    fts5IndexMerge(p, iIdx, ppStruct, nRem);
   }
 }
 
-static void fts5IndexCrisisMerge(
+static void fts5IndexCrisismerge(
   Fts5Index *p,                   /* FTS5 backend object */
   int iIdx,                       /* Index to work on */
   Fts5Structure **ppStruct        /* IN/OUT: Current structure of index */
 ){
+  const int nCrisis = p->pConfig->nCrisisMerge;
   Fts5Structure *pStruct = *ppStruct;
   int iLvl = 0;
-  while( p->rc==SQLITE_OK 
-      && iLvl<pStruct->nLevel
-      && pStruct->aLevel[iLvl].nSeg>=p->pConfig->nCrisisMerge 
-  ){
+
+  assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 );
+  while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
     fts5IndexMergeLevel(p, iIdx, &pStruct, iLvl, 0);
     fts5StructurePromote(p, iLvl+1, pStruct);
     iLvl++;
@@ -3744,8 +3758,8 @@ static void fts5FlushOneHash(Fts5Index *p, int iHash, int *pnLeaf){
   }
 
 
-  if( p->pConfig->nAutomerge>0 ) fts5IndexWork(p, iHash, &pStruct, pgnoLast);
-  fts5IndexCrisisMerge(p, iHash, &pStruct);
+  fts5IndexAutomerge(p, iHash, &pStruct, pgnoLast);
+  fts5IndexCrisismerge(p, iHash, &pStruct);
   fts5StructureWrite(p, iHash, pStruct);
   fts5StructureRelease(pStruct);
 }
@@ -3759,7 +3773,7 @@ static void fts5IndexFlush(Fts5Index *p){
   int nLeaf = 0;                  /* Number of leaves written */
 
   /* If an error has already occured this call is a no-op. */
-  if( p->rc!=SQLITE_OK || p->nPendingData==0 ) return;
+  if( p->nPendingData==0 ) return;
   assert( p->apHash );
 
   /* Flush the terms and each prefix index to disk */
@@ -3774,6 +3788,7 @@ int sqlite3Fts5IndexOptimize(Fts5Index *p){
   Fts5Config *pConfig = p->pConfig;
   int i;
 
+  assert( p->rc==SQLITE_OK );
   fts5IndexFlush(p);
   for(i=0; i<=pConfig->nPrefix; i++){
     Fts5Structure *pStruct = fts5StructureRead(p, i);
@@ -3828,6 +3843,16 @@ int sqlite3Fts5IndexOptimize(Fts5Index *p){
   return fts5IndexReturn(p); 
 }
 
+int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
+  Fts5Structure *pStruct;
+
+  pStruct = fts5StructureRead(p, 0);
+  fts5IndexMerge(p, 0, &pStruct, nMerge);
+  fts5StructureWrite(p, 0, pStruct);
+  fts5StructureRelease(pStruct);
+
+  return fts5IndexReturn(p);
+}
 
 
 /*
@@ -4122,6 +4147,7 @@ int sqlite3Fts5IndexBeginWrite(Fts5Index *p, i64 iRowid){
   }
 
   if( iRowid<=p->iWriteRowid || (p->nPendingData > p->nMaxPendingData) ){
+    assert( p->rc==SQLITE_OK );
     fts5IndexFlush(p);
   }
   p->iWriteRowid = iRowid;
@@ -4703,6 +4729,8 @@ static void fts5IndexIntegrityCheckSegment(
 ){
   Fts5BtreeIter iter;             /* Used to iterate through b-tree hierarchy */
 
+  if( pSeg->pgnoFirst==0 && pSeg->pgnoLast==0 ) return;
+
   /* Iterate through the b-tree hierarchy.  */
   for(fts5BtreeIterInit(p, iIdx, pSeg, &iter);
       p->rc==SQLITE_OK && iter.bEof==0;
index 33eda7c3e7dfa6020ec839e93c61efba877321e8..866e6b75c70ecace96b4267bdd209954f611a583 100644 (file)
@@ -596,6 +596,10 @@ int sqlite3Fts5StorageOptimize(Fts5Storage *p){
   return sqlite3Fts5IndexOptimize(p->pIndex);
 }
 
+int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){
+  return sqlite3Fts5IndexMerge(p->pIndex, nMerge);
+}
+
 /*
 ** Allocate a new rowid. This is used for "external content" tables when
 ** a NULL value is inserted into the rowid column. The new rowid is allocated
index 36d29f8a9447a8b439c247ea3fddfe11ad6c1f02..fe1d205ec8761c6fee71f4607d2038451e8458c2 100644 (file)
@@ -22,8 +22,6 @@ ifcapable !fts5 {
   return
 }
 
-if 0 {
-
 set doc [string trim [string repeat "x y z " 200]]
 do_execsql_test 1.0 {
   CREATE TABLE t1(a INTEGER PRIMARY KEY, x);
@@ -75,8 +73,6 @@ do_faultsim_test 2.1 -faults oom-trans* -prep {
   catchsql { ROLLBACK }
 }
 
-}
-
 #-------------------------------------------------------------------------
 # OOM within an 'optimize' operation that writes multiple pages to disk.
 #
diff --git a/ext/fts5/test/fts5fault3.test b/ext/fts5/test/fts5fault3.test
new file mode 100644 (file)
index 0000000..4d438d7
--- /dev/null
@@ -0,0 +1,87 @@
+# 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 is focused on OOM errors.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+source $testdir/malloc_common.tcl
+set testprefix fts5fault3
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts5 {
+  finish_test
+  return
+}
+
+#-------------------------------------------------------------------------
+# An OOM while resuming a partially completed segment merge.
+#
+db func rnddoc fts5_rnddoc 
+do_test 1.0 {
+  expr srand(0)
+  execsql {
+    CREATE VIRTUAL TABLE xx USING fts5(x);
+    INSERT INTO xx(xx, rank) VALUES('pgsz', 32);
+    INSERT INTO xx(xx, rank) VALUES('automerge', 16);
+  }
+  for {set i 0} {$i < 10} {incr i} {
+    execsql {
+      BEGIN;
+        INSERT INTO xx(x) VALUES(rnddoc(20));
+        INSERT INTO xx(x) VALUES(rnddoc(20));
+        INSERT INTO xx(x) VALUES(rnddoc(20));
+      COMMIT
+    }
+  }
+
+  execsql {
+    INSERT INTO xx(xx, rank) VALUES('automerge', 2);
+    INSERT INTO xx(xx, rank) VALUES('merge', 50);
+  }
+} {}
+faultsim_save_and_close
+
+do_faultsim_test 1 -faults oom-* -prep {
+  faultsim_restore_and_reopen
+} -body {
+  execsql { INSERT INTO xx(xx, rank) VALUES('merge', 1) }
+} -test {
+  faultsim_test_result [list 0 {}]
+}
+
+#-------------------------------------------------------------------------
+# An OOM while flushing an unusually large term to disk.
+#
+reset_db
+do_execsql_test 2.0 {
+  CREATE VIRTUAL TABLE xx USING fts5(x);
+  INSERT INTO xx(xx, rank) VALUES('pgsz', 32);
+}
+faultsim_save_and_close
+
+set    doc "a long term abcdefghijklmnopqrstuvwxyz "
+append doc "and then abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz "
+append doc [string repeat "abcdefghijklmnopqrstuvwxyz" 10]
+
+do_faultsim_test 2 -faults oom-* -prep {
+  faultsim_restore_and_reopen
+} -body {
+  execsql { INSERT INTO xx(x) VALUES ($::doc) }
+} -test {
+  faultsim_test_result [list 0 {}]
+}
+
+
+
+
+finish_test
+
diff --git a/ext/fts5/test/fts5merge.test b/ext/fts5/test/fts5merge.test
new file mode 100644 (file)
index 0000000..1c048be
--- /dev/null
@@ -0,0 +1,139 @@
+# 2014 Dec 20
+#
+# 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 that focus on incremental merges of segments.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5merge
+
+db func repeat [list string repeat]
+
+#-------------------------------------------------------------------------
+# Create an fts index so that:
+#
+#   * the index consists of two top-level segments
+#   * each segment contains records related to $nRowPerSeg rows
+#   * all rows consist of tokens "x" and "y" only.
+#
+# Then run ('merge', 1) until everything is completely merged.
+#
+proc do_merge1_test {testname nRowPerSeg} {
+  set ::nRowPerSeg [expr $nRowPerSeg]
+  do_execsql_test $testname.0 {
+    DROP TABLE IF EXISTS x8;
+    CREATE VIRTUAL TABLE x8 USING fts5(i);
+    INSERT INTO x8(x8, rank) VALUES('pgsz', 32);
+
+    WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg)
+      INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii;
+
+    WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg)
+      INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii;
+
+    INSERT INTO x8(x8, rank) VALUES('automerge', 2);
+  }
+
+  for {set tn 1} {[lindex [fts5_level_segs x8] 0]>0} {incr tn} {
+    do_execsql_test $testname.$tn {
+      INSERT INTO x8(x8, rank) VALUES('merge', 1);
+      INSERT INTO x8(x8) VALUES('integrity-check');
+    }
+    if {$tn>5} break
+  }
+
+  do_test $testname.x [list expr "$tn < 5"] 1
+}
+
+do_merge1_test 1.1   1
+do_merge1_test 1.2   2
+do_merge1_test 1.3   3
+do_merge1_test 1.4   4
+do_merge1_test 1.5  10
+do_merge1_test 1.6  20
+do_merge1_test 1.7 100
+
+#-------------------------------------------------------------------------
+#
+proc do_merge2_test {testname nRow} {
+  db func rnddoc fts5_rnddoc
+
+  do_execsql_test $testname.0 {
+    DROP TABLE IF EXISTS x8;
+    CREATE VIRTUAL TABLE x8 USING fts5(i);
+    INSERT INTO x8(x8, rank) VALUES('pgsz', 32);
+  }
+
+  set ::nRow $nRow
+  do_test $testname.1 {
+    for {set i 0} {$i < $::nRow} {incr i} {
+      execsql { INSERT INTO x8 VALUES( rnddoc(($i%16) + 5) ) }
+      while {[not_merged x8]} {
+        execsql {
+          INSERT INTO x8(x8, rank) VALUES('automerge', 2);
+          INSERT INTO x8(x8, rank) VALUES('merge', 1);
+          INSERT INTO x8(x8, rank) VALUES('automerge', 16);
+          INSERT INTO x8(x8) VALUES('integrity-check');
+        }
+      }
+    }
+  } {}
+}
+proc not_merged {tbl} {
+  set segs [fts5_level_segs $tbl]
+  foreach s $segs { if {$s>1} { return 1 } }
+  return 0
+}
+
+do_merge2_test 2.1    5
+do_merge2_test 2.2   10
+do_merge2_test 2.3   20
+
+#-------------------------------------------------------------------------
+# Test that an auto-merge will complete any merge that has already been
+# started, even if the number of input segments is less than the current
+# value of the 'automerge' configuration parameter.
+#
+db func rnddoc fts5_rnddoc
+
+do_execsql_test 3.1 {
+  DROP TABLE IF EXISTS x8;
+  CREATE VIRTUAL TABLE x8 USING fts5(i);
+  INSERT INTO x8(x8, rank) VALUES('pgsz', 32);
+  INSERT INTO x8 VALUES(rnddoc(100));
+  INSERT INTO x8 VALUES(rnddoc(100));
+}
+do_test 3.2 {
+  execsql {
+    INSERT INTO x8(x8, rank) VALUES('automerge', 4);
+    INSERT INTO x8(x8, rank) VALUES('merge', 1);
+  }
+  fts5_level_segs x8
+} {2}
+
+do_test 3.3 {
+  execsql {
+    INSERT INTO x8(x8, rank) VALUES('automerge', 2);
+    INSERT INTO x8(x8, rank) VALUES('merge', 1);
+  }
+  fts5_level_segs x8
+} {2 1}
+
+do_test 3.4 {
+  execsql { INSERT INTO x8(x8, rank) VALUES('automerge', 4) }
+  while {[not_merged x8]} {
+    execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1) }
+  }
+  fts5_level_segs x8
+} {0 1}
+
+finish_test
+
index 2c3dcdd1ca94cacc829c42a46f2f0177ced106f6..3e37056c0331dbbd59aa6b704ee919348d0e9255 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Improve\scoverage\sof\sfts5_index.c\sslightly.
-D 2015-04-25T20:29:46.707
+C Further\stests\sfor\sfts5.
+D 2015-04-27T11:31:56.573
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 31b38b9da2e4b36f54a013bd71a5c3f6e45ca78f
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -104,16 +104,16 @@ F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
 F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
 F ext/fts3/unicode/mkunicode.tcl 159c1194da0bc72f51b3c2eb71022568006dc5ad
 F ext/fts5/extract_api_docs.tcl 55a6d648d516f35d9a1e580ac00de27154e1904a
-F ext/fts5/fts5.c 1eb8ca073be5222c43e4eee5408764c2cbb4200b
+F ext/fts5/fts5.c 3383b8a44766c68bda812b68ce74684c6b87787f
 F ext/fts5/fts5.h 24a2cc35b5e76eec57b37ba48c12d9d2cb522b3a
-F ext/fts5/fts5Int.h 803fd2fc03e3799a38ebb404f2f1309ded5d3e8b
+F ext/fts5/fts5Int.h 7dc902e195e00c5820b85d71c2476500c2cf9027
 F ext/fts5/fts5_aux.c fcea18b1a2a3f95a498b52aba2983557d7678a22
 F ext/fts5/fts5_buffer.c 3ba56cc6824c9f7b1e0695159e0a9c636f6b4a23
 F ext/fts5/fts5_config.c 43fcf838d3a3390d1245e3d5e651fa5cc1df575b
 F ext/fts5/fts5_expr.c 05da381ab26031243266069302c6eb4094b2c5dd
 F ext/fts5/fts5_hash.c 3cb5a3d04dd2030eb0ac8d544711dfd37c0e6529
-F ext/fts5/fts5_index.c 699b716f1b84ef78da9ccee25a8b6fe020cff32a
-F ext/fts5/fts5_storage.c b3a4cbbcd197fe587789398e51a631f92fc9196c
+F ext/fts5/fts5_index.c 5f969f5b6f5e022c9c62973dd6e4e82e1d5f3f30
+F ext/fts5/fts5_storage.c 87f85986a6d07391f4e0ddfa9799dbecc40fa165
 F ext/fts5/fts5_tcl.c 10bf0eb678d34c1bfdcfaf653d2e6dd92afa8b38
 F ext/fts5/fts5_tokenize.c c07f2c2f749282c1dbbf46bde1f6d7095c740b8b
 F ext/fts5/fts5_unicode2.c f74f53316377068812a1fa5a37819e6b8124631d
@@ -141,8 +141,10 @@ F ext/fts5/test/fts5dlidx.test 748a84ceb74a4154725096a26dfa854260b0182f
 F ext/fts5/test/fts5ea.test 04695560a444fcc00c3c4f27783bdcfbf71f030c
 F ext/fts5/test/fts5eb.test 728a1f23f263548f5c29b29dfb851b5f2dbe723e
 F ext/fts5/test/fts5fault1.test ed71717a479bef32d05f02d9c48691011d160d4d
-F ext/fts5/test/fts5fault2.test 0476720b3fcbb3f30c26da4cc8bda4f020d3e408
+F ext/fts5/test/fts5fault2.test 37c325cb3e6e27c74c122bb49673b4ae0862df33
+F ext/fts5/test/fts5fault3.test f8935b92976ae645d43205562fdbb0c8511dd049
 F ext/fts5/test/fts5full.test 0924bdca5416a242103239ace79c6f5aa34bab8d
+F ext/fts5/test/fts5merge.test 453a0717881aa7784885217b2040f3f275caff03
 F ext/fts5/test/fts5near.test 3f9f64e16cac82725d03d4e04c661090f0b3b947
 F ext/fts5/test/fts5optimize.test 0028c90a7817d3e576d1148fc8dff17d89054e54
 F ext/fts5/test/fts5porter.test 50322599823cb8080a99f0ec0c39f7d0c12bcb5e
@@ -1305,7 +1307,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P e748651c940eae2389fe826cf5c25f1166a5e611
-R 0f1e32978d2225a38a865fc7c17144a3
+P e5aaa01306597ffd2475dcb83ae889393f68d315
+R 328723993a482062ac5cfa3f373fa969
 U dan
-Z 504cb23846c7efd7bba629c51f43c91a
+Z dd82cb2122e4379a606aef38aa888497
index 4145bd78fef0badf6caf2a8136c476e40680ba49..02c02a50418bcbe5722d0c1554cc92ab15d64cec 100644 (file)
@@ -1 +1 @@
-e5aaa01306597ffd2475dcb83ae889393f68d315
\ No newline at end of file
+ffeb3ef3cfec3681b72bb28cfa612aa15e07887d
\ No newline at end of file