]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add tests for incremental merge code.
authordan <dan@noemail.net>
Wed, 14 Mar 2012 20:01:52 +0000 (20:01 +0000)
committerdan <dan@noemail.net>
Wed, 14 Mar 2012 20:01:52 +0000 (20:01 +0000)
FossilOrigin-Name: 570473729d6561d81e6e5f8884fd18487008636e

ext/fts3/fts3Int.h
ext/fts3/fts3_write.c
manifest
manifest.uuid
test/fts3_common.tcl
test/fts4merge.test
test/fts4merge2.test [new file with mode: 0644]
test/permutations.test

index b34ca63052c304f12b9027fd3727d9f4e9f3207d..1cd14d304a65d943c3b887a8e817c324bff459cb 100644 (file)
@@ -124,7 +124,7 @@ extern const sqlite3_api_routines *sqlite3_api;
 # define NEVER(X)  (0)
 #else
 # define ALWAYS(x) (x)
-# define NEVER(X)  (x)
+# define NEVER(x)  (x)
 #endif
 
 /*
index 35da283df34fe56eb444b54a56f5c6f71467bf29..08f07c10b2f58d4e5b1e3e95f5d1d047b0acaaa5 100644 (file)
@@ -3272,10 +3272,16 @@ typedef struct LayerWriter LayerWriter;
 typedef struct Blob Blob;
 typedef struct NodeReader NodeReader;
 
+/*
+** An instance of the following structure is used as a dynamic buffer
+** to build up nodes or other blobs of data in.
+**
+** The function blobGrowBuffer() is used to extend the allocation.
+*/
 struct Blob {
-  char *a;
-  int n;
-  int nAlloc;
+  char *a;                        /* Pointer to allocation */
+  int n;                          /* Number of valid bytes of data in a[] */
+  int nAlloc;                     /* Allocated size of a[] (nAlloc>=n) */
 };
 
 struct LayerWriter {
@@ -3405,7 +3411,7 @@ static int fts3IncrmergePush(
   int iLayer;
 
   assert( nTerm>0 );
-  for(iLayer=1; iLayer<FTS_MAX_APPENDABLE_HEIGHT; iLayer++){
+  for(iLayer=1; ALWAYS(iLayer<FTS_MAX_APPENDABLE_HEIGHT); iLayer++){
     sqlite3_int64 iNextPtr = 0;
     LayerWriter *pLayer = &pWriter->aLayer[iLayer];
     int rc = SQLITE_OK;
@@ -3565,9 +3571,12 @@ static void fts3IncrmergeRelease(
 
   /* Find the root node */
   for(iRoot=FTS_MAX_APPENDABLE_HEIGHT-1; iRoot>=0; iRoot--){
-    if( pWriter->aLayer[iRoot].block.n>0 ) break;
-    assert( pWriter->aLayer[iRoot].block.nAlloc==0 );
-    assert( pWriter->aLayer[iRoot].key.nAlloc==0 );
+    LayerWriter *pLayer = &pWriter->aLayer[iRoot];
+    if( pLayer->block.n>0 ) break;
+    assert( *pRc || pLayer->block.nAlloc==0 );
+    assert( *pRc || pLayer->key.nAlloc==0 );
+    sqlite3_free(pLayer->block.a);
+    sqlite3_free(pLayer->key.a);
   }
 
   /* Empty output segment. This is a no-op. */
@@ -3628,22 +3637,20 @@ static int fts3TermCmp(
 }
 
 
-static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pRc){
+static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){
   int bRes = 0;
-  if( *pRc==SQLITE_OK ){
-    sqlite3_stmt *pCheck = 0;
-    int rc;
+  sqlite3_stmt *pCheck = 0;
+  int rc;
 
-    rc = fts3SqlStmt(p, SQL_SEGMENT_IS_APPENDABLE, &pCheck, 0);
-    if( rc==SQLITE_OK ){
-      sqlite3_bind_int64(pCheck, 1, iEnd);
-      if( SQLITE_ROW==sqlite3_step(pCheck) ) bRes = 1;
-      rc = sqlite3_reset(pCheck);
-    }
-    *pRc = rc;
+  rc = fts3SqlStmt(p, SQL_SEGMENT_IS_APPENDABLE, &pCheck, 0);
+  if( rc==SQLITE_OK ){
+    sqlite3_bind_int64(pCheck, 1, iEnd);
+    if( SQLITE_ROW==sqlite3_step(pCheck) ) bRes = 1;
+    rc = sqlite3_reset(pCheck);
   }
   
-  return bRes;
+  *pbRes = bRes;
+  return rc;
 }
 
 /*
@@ -3682,16 +3689,14 @@ static int fts3IncrmergeLoad(
     }
 
     /* Check for the zero-length marker in the %_segments table */
-    bAppendable = fts3IsAppendable(p, iEnd, &rc);
+    rc = fts3IsAppendable(p, iEnd, &bAppendable);
 
     /* Check that zKey/nKey is larger than the largest key the candidate */
     if( rc==SQLITE_OK && bAppendable ){
-      char *aLeaf = (char *)aRoot;
-      int nLeaf = nRoot;
+      char *aLeaf = 0;
+      int nLeaf = 0;
 
-      if( aRoot[0] ){
-        rc = sqlite3Fts3ReadBlock(p, iLeafEnd, &aLeaf, &nLeaf, 0);
-      }
+      rc = sqlite3Fts3ReadBlock(p, iLeafEnd, &aLeaf, &nLeaf, 0);
       if( rc==SQLITE_OK ){
         NodeReader reader;
         for(rc = nodeReaderInit(&reader, aLeaf, nLeaf);
@@ -3705,7 +3710,7 @@ static int fts3IncrmergeLoad(
         }
         nodeReaderRelease(&reader);
       }
-      if( aLeaf!=aRoot ) sqlite3_free(aLeaf);
+      sqlite3_free(aLeaf);
     }
 
     if( rc==SQLITE_OK && bAppendable ){
@@ -3866,9 +3871,8 @@ static int fts3IncrmergeWriter(
   /* Insert the marker in the %_segments table to make sure nobody tries
   ** to steal the space just allocated. This is also used to identify 
   ** appendable segments.  */
-  if( rc==SQLITE_OK ){
-    rc = fts3WriteSegment(p, pWriter->iEnd, 0, 0);
-  }
+  rc = fts3WriteSegment(p, pWriter->iEnd, 0, 0);
+  if( rc!=SQLITE_OK ) return rc;
 
   pWriter->iAbsLevel = iAbsLevel;
   pWriter->nLeafEst = nLeafEst;
@@ -4010,6 +4014,7 @@ static int fts3TruncateNode(
         pNew, &prev, reader.term.a, reader.term.n,
         reader.aDoclist, reader.nDoclist
     );
+    if( rc!=SQLITE_OK ) break;
   }
   if( bStarted==0 ){
     fts3StartNode(pNew, (int)aNode[0], reader.iChild);
@@ -4029,68 +4034,66 @@ static int fts3TruncateSegment(
   const char *zTerm,              /* Remove terms smaller than this */
   int nTerm                       /* Number of bytes in buffer zTerm */
 ){
-  int rc;                         /* Return code */
+  int rc = SQLITE_OK;             /* Return code */
   Blob root = {0,0,0};            /* New root page image */
   Blob block = {0,0,0};           /* Buffer used for any other block */
-
+  sqlite3_int64 iBlock = 0;       /* Block id */
+  sqlite3_int64 iNewStart = 0;    /* New value for iStartBlock */
+  sqlite3_int64 iOldStart = 0;    /* Old value for iStartBlock */
+  int rc2;                        /* sqlite3_reset() return code */
   sqlite3_stmt *pFetch = 0;       /* Statement used to fetch segdir */
 
-  rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pFetch, 0);
-  if( rc==SQLITE_OK ){
-    sqlite3_int64 iBlock = 0;     /* Block id */
-    sqlite3_int64 iNewStart = 0;
-    sqlite3_int64 iOldStart = 0;
-    int rc2;                      /* sqlite3_reset() return code */
-
-    sqlite3_bind_int64(pFetch, 1, iAbsLevel);
-    sqlite3_bind_int(pFetch, 2, iIdx);
-    if( SQLITE_ROW==sqlite3_step(pFetch) ){
-      const char *aRoot = sqlite3_column_blob(pFetch, 4);
-      int nRoot = sqlite3_column_bytes(pFetch, 4);
-      iOldStart = sqlite3_column_int64(pFetch, 1);
-      rc = fts3TruncateNode(aRoot, nRoot, &root, zTerm, nTerm, &iBlock);
-    }
-    rc2 = sqlite3_reset(pFetch);
-    if( rc==SQLITE_OK ) rc = rc2;
+  assert( p->aStmt[SQL_SELECT_SEGDIR] );
+  pFetch = p->aStmt[SQL_SELECT_SEGDIR];
 
-    while( rc==SQLITE_OK && iBlock ){
-      char *aBlock = 0;
-      int nBlock = 0;
-      iNewStart = iBlock;
+  sqlite3_bind_int64(pFetch, 1, iAbsLevel);
+  sqlite3_bind_int(pFetch, 2, iIdx);
+  if( SQLITE_ROW==sqlite3_step(pFetch) ){
+    const char *aRoot = sqlite3_column_blob(pFetch, 4);
+    int nRoot = sqlite3_column_bytes(pFetch, 4);
+    iOldStart = sqlite3_column_int64(pFetch, 1);
+    rc = fts3TruncateNode(aRoot, nRoot, &root, zTerm, nTerm, &iBlock);
+  }
+  rc2 = sqlite3_reset(pFetch);
+  if( rc==SQLITE_OK ) rc = rc2;
 
-      rc = sqlite3Fts3ReadBlock(p, iBlock, &aBlock, &nBlock, 0);
-      if( rc==SQLITE_OK ){
-        rc = fts3TruncateNode(aBlock, nBlock, &block, zTerm, nTerm, &iBlock);
-      }
-      if( rc==SQLITE_OK ){
-        rc = fts3WriteSegment(p, iNewStart, block.a, block.n);
-      }
-      sqlite3_free(aBlock);
+  while( rc==SQLITE_OK && iBlock ){
+    char *aBlock = 0;
+    int nBlock = 0;
+    iNewStart = iBlock;
+
+    rc = sqlite3Fts3ReadBlock(p, iBlock, &aBlock, &nBlock, 0);
+    if( rc==SQLITE_OK ){
+      rc = fts3TruncateNode(aBlock, nBlock, &block, zTerm, nTerm, &iBlock);
+    }
+    if( rc==SQLITE_OK ){
+      rc = fts3WriteSegment(p, iNewStart, block.a, block.n);
     }
+    sqlite3_free(aBlock);
+  }
 
-    /* Variable iNewStart now contains the first valid leaf node. */
-    if( rc==SQLITE_OK && iNewStart ){
-      sqlite3_stmt *pDel = 0;
-      rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDel, 0);
-      if( rc==SQLITE_OK ){
-        sqlite3_bind_int64(pDel, 1, iOldStart);
-        sqlite3_bind_int64(pDel, 2, iNewStart-1);
-        sqlite3_step(pDel);
-        rc = sqlite3_reset(pDel);
-      }
+  /* Variable iNewStart now contains the first valid leaf node. */
+  if( rc==SQLITE_OK && iNewStart ){
+    sqlite3_stmt *pDel = 0;
+    rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDel, 0);
+    if( rc==SQLITE_OK ){
+      sqlite3_bind_int64(pDel, 1, iOldStart);
+      sqlite3_bind_int64(pDel, 2, iNewStart-1);
+      sqlite3_step(pDel);
+      rc = sqlite3_reset(pDel);
     }
+  }
 
+  if( rc==SQLITE_OK ){
+    sqlite3_stmt *pChomp = 0;
+    rc = fts3SqlStmt(p, SQL_CHOMP_SEGDIR, &pChomp, 0);
     if( rc==SQLITE_OK ){
-      sqlite3_stmt *pChomp = 0;
-      rc = fts3SqlStmt(p, SQL_CHOMP_SEGDIR, &pChomp, 0);
-      if( rc==SQLITE_OK ){
-        sqlite3_bind_int64(pChomp, 1, iNewStart);
-        sqlite3_bind_blob(pChomp, 2, root.a, root.n, SQLITE_STATIC);
-        sqlite3_bind_int64(pChomp, 3, iAbsLevel);
-        sqlite3_bind_int(pChomp, 4, iIdx);
-        sqlite3_step(pChomp);
-        rc = sqlite3_reset(pChomp);
-      }
+      sqlite3_bind_int64(pChomp, 1, iNewStart);
+      sqlite3_bind_blob(pChomp, 2, root.a, root.n, SQLITE_STATIC);
+      sqlite3_bind_int64(pChomp, 3, iAbsLevel);
+      sqlite3_bind_int(pChomp, 4, iIdx);
+      sqlite3_step(pChomp);
+      rc = sqlite3_reset(pChomp);
     }
   }
 
@@ -4122,7 +4125,7 @@ static int fts3IncrmergeChomp(
        || (pCsr->apSegment[1]->iIdx==0 && pCsr->apSegment[0]->iIdx==1) 
   );
 
-  for(i=1; i>=0; i--){
+  for(i=1; i>=0 && rc==SQLITE_OK; i--){
     Fts3SegReader *pSeg = pCsr->apSegment[0];
     if( pSeg->iIdx!=i ) pSeg = pCsr->apSegment[1];
     assert( pSeg->iIdx==i );
@@ -4149,10 +4152,10 @@ static int fts3IncrmergeChomp(
 /*
 ** Attempt an incremental merge that writes nMerge leaf pages.
 **
-** Incremental merges happen two segments at a time.  The two
+** Incremental merges happen two segments at a time. The two
 ** segments to be merged are the two oldest segments (the ones with
 ** the smallest index) in the highest level that has at least
-** nMin segments.  Multiple segment pair merges might occur in
+** nMin segments. Multiple segment pair merges might occur in
 ** an attempt to write the quota of nMerge leaf pages.
 */
 static int fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
@@ -4178,8 +4181,7 @@ static int fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
       return sqlite3_reset(pFindLevel);
     }
     iAbsLevel = sqlite3_column_int64(pFindLevel, 0);
-    rc = sqlite3_reset(pFindLevel);
-    if( rc!=SQLITE_OK ) return rc;
+    sqlite3_reset(pFindLevel);
 
     /* Allocate space for the cursor, filter and writer objects */
     pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc);
@@ -4195,6 +4197,8 @@ static int fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
 
     if( rc==SQLITE_OK ){
       rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter);
+    }
+    if( rc==SQLITE_OK ){
       if( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr)) ){
         rc = fts3IncrmergeWriter(p, iAbsLevel, pCsr->zTerm,pCsr->nTerm,pWriter);
         if( rc==SQLITE_OK ){
@@ -4230,7 +4234,10 @@ static int fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
 ** written for the merge, and the minimum number of segments on a level
 ** before it will be selected for a merge, respectively.
 */
-static int fts3DoIncrmerge(Fts3Table *p, const char *zParam){
+static int fts3DoIncrmerge(
+  Fts3Table *p,                   /* FTS3 table handle */
+  const char *zParam              /* Nul-terminated string containing "A,B" */
+){
   int rc;
   int nMin = (FTS3_MERGE_COUNT / 2);
   int nMerge = 0;
@@ -4252,11 +4259,12 @@ static int fts3DoIncrmerge(Fts3Table *p, const char *zParam){
     }
   }
 
-  if( z[0]!='\0' ) return SQLITE_ERROR;
-  if( nMin<2 ) nMin = 2;
-
-  rc = fts3Incrmerge(p, nMerge, nMin);
-  sqlite3Fts3SegmentsClose(p);
+  if( z[0]!='\0' || nMin<2 ){
+    rc = SQLITE_ERROR;
+  }else{
+    rc = fts3Incrmerge(p, nMerge, nMin);
+    sqlite3Fts3SegmentsClose(p);
+  }
   return rc;
 }
 
@@ -4476,7 +4484,7 @@ static int fts3DeleteByRowid(
 ** tables. The schema of the virtual table being:
 **
 **     CREATE TABLE <table name>( 
-**       <user COLUMns>,
+**       <user columns>,
 **       <table name> HIDDEN, 
 **       docid HIDDEN, 
 **       <langid> HIDDEN
index 2ce91db0a4485664246b0fbff1d80340ed9ed710..06d7ae13cee7c829100cac68ed631df55a7e5809 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Avoid\sallocating\sa\slarge\sobject\son\sthe\sstack\sin\sthe\sincremental\smerge\scode.\sUse\ssqlite3_malloc()\sinstead.
-D 2012-03-14T12:17:40.405
+C Add\stests\sfor\sincremental\smerge\scode.
+D 2012-03-14T20:01:52.250
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 3f79a373e57c3b92dabf76f40b065e719d31ac34
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -65,7 +65,7 @@ F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
 F ext/fts3/fts3.c 806632fd0020eed966ab82ea25fe09f1a4c86907
 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
-F ext/fts3/fts3Int.h cc8991daf660b926ef77a004fe92b97adaf10d97
+F ext/fts3/fts3Int.h 1da6d2af6b079cdd74cd2350761182dedb8bd892
 F ext/fts3/fts3_aux.c 72de4cb43db7bfc2f68fbda04b7d8095ae9a6239
 F ext/fts3/fts3_expr.c dbc7ba4c3a6061adde0f38ed8e9b349568299551
 F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
@@ -78,7 +78,7 @@ F ext/fts3/fts3_test.c 6b7cc68aef4efb084e1449f7d20c4b20d3bdf6b4
 F ext/fts3/fts3_tokenizer.c 3da7254a9881f7e270ab28e2004e0d22b3212bce
 F ext/fts3/fts3_tokenizer.h 66dec98e365854b6cd2d54f1a96bb6d428fc5a68
 F ext/fts3/fts3_tokenizer1.c 0dde8f307b8045565cf63797ba9acfaff1c50c68
-F ext/fts3/fts3_write.c 772b8c32b93c60b85b60c635de2ff5b3f49fd779
+F ext/fts3/fts3_write.c 355121666034ece7d2472caa3f322d0cb61b0f0d
 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
@@ -448,7 +448,7 @@ F test/fts2q.test b2fbbe038b7a31a52a6079b215e71226d8c6a682
 F test/fts2r.test b154c30b63061d8725e320fba1a39e2201cadd5e
 F test/fts2token.test d8070b241a15ff13592a9ae4a8b7c171af6f445a
 F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654
-F test/fts3_common.tcl 91c29230c428443e6552add9b18cf94a3dc23074
+F test/fts3_common.tcl 1b2e522476236a018c1a4b8ae4f7599ce29b7be0
 F test/fts3aa.test 909d5f530d30a8e36b9328d67285eae6537c79c0
 F test/fts3ab.test 09aeaa162aee6513d9ff336b6932211008b9d1f9
 F test/fts3ac.test 636ed7486043055d4f126a0e385f2d5a82ebbf63
@@ -497,7 +497,8 @@ F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659
 F test/fts4aa.test 6e7f90420b837b2c685f3bcbe84c868492d40a68
 F test/fts4content.test 17b2360f7d1a9a7e5aa8022783f5c5731b6dfd4f
 F test/fts4langid.test fabdd5a8db0fa00292e0704809f566e3fb6dba3a
-F test/fts4merge.test 3af8fa8fd9f27a9eb402b9ae399aa53fbaae8481
+F test/fts4merge.test d841f283bf9557d549afde513fe38d0b48adc4f7
+F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
 F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca
 F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
 F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
@@ -636,7 +637,7 @@ F test/pageropt.test 9191867ed19a2b3db6c42d1b36b6fbc657cd1ab0
 F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
-F test/permutations.test 2b5a1b64a8e5114757457fbce9010387d1fe7682
+F test/permutations.test 0ab1e7748de5d29c4c648ba5ce3b983ab80653d1
 F test/pragma.test f11c59ec935a52edb4d3d5676d456588121fcefa
 F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947
 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
@@ -993,7 +994,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
-P f97b12e0955c4c29f9c31a186d72d87f7407782e
-R 86bb2bcb41aa5bde569f19117ae756eb
+P 36ae510de45be44efd34cff242d02fb21b7419ac
+R 326f29ae3378aab5424c0bd2deaa1142
 U dan
-Z da9e601d088fda8ad57ce1fc3070902a
+Z 9fe983241614f7794efd59c0386308c4
index 137182d9b7ffa27ac80a8006fa1e318bd1554594..9cec3849f5321cbd99170febe0c6df1a1e564f71 100644 (file)
@@ -1 +1 @@
-36ae510de45be44efd34cff242d02fb21b7419ac
\ No newline at end of file
+570473729d6561d81e6e5f8884fd18487008636e
\ No newline at end of file
index 23a8cfca67cdd79801123a692b217d96bb8555a1..6c9c2fcec9452bbe360ddbc51eaadc3b8805125b 100644 (file)
 # to use Tcl.
 #
 
+
+#-------------------------------------------------------------------------
+# USAGE: fts3_build_db_1 N
+#
+# Build a sample FTS table in the database opened by database connection 
+# [db]. The name of the new table is "t1".
+#
+proc fts3_build_db_1 {n} {
+
+  if {$n > 10000} {error "n must be <= 10000"}
+
+  db eval { CREATE VIRTUAL TABLE t1 USING fts4(x, y) }
+
+  set xwords [list zero one two three four five six seven eight nine ten]
+  set ywords [list alpha beta gamma delta epsilon zeta eta theta iota kappa]
+
+  for {set i 0} {$i < $n} {incr i} {
+    set x ""
+    set y ""
+
+    set x [list]
+    lappend x [lindex $xwords [expr ($i / 1000) % 10]]
+    lappend x [lindex $xwords [expr ($i / 100)  % 10]]
+    lappend x [lindex $xwords [expr ($i / 10)   % 10]]
+    lappend x [lindex $xwords [expr ($i / 1)   % 10]]
+
+    set y [list]
+    lappend y [lindex $ywords [expr ($i / 1000) % 10]]
+    lappend y [lindex $ywords [expr ($i / 100)  % 10]]
+    lappend y [lindex $ywords [expr ($i / 10)   % 10]]
+    lappend y [lindex $ywords [expr ($i / 1)   % 10]]
+
+    db eval { INSERT INTO t1(docid, x, y) VALUES($i, $x, $y) }
+  }
+}
+
+#-------------------------------------------------------------------------
+# USAGE: fts3_build_db_2 N
+#
+# Build a sample FTS table in the database opened by database connection 
+# [db]. The name of the new table is "t2".
+#
+proc fts3_build_db_2 {n} {
+
+  if {$n > 100000} {error "n must be <= 100000"}
+
+  db eval { CREATE VIRTUAL TABLE t2 USING fts4 }
+
+  set chars [list a b c d e f g h  i j k l m n o p  q r s t u v w x  y z ""]
+
+  for {set i 0} {$i < $n} {incr i} {
+    set word ""
+    set n [llength $chars]
+    append word [lindex $chars [expr {($i / 1)   % $n}]]
+    append word [lindex $chars [expr {($i / $n)  % $n}]]
+    append word [lindex $chars [expr {($i / ($n*$n)) % $n}]]
+
+    db eval { INSERT INTO t2(docid, content) VALUES($i, $word) }
+  }
+}
+
 #-------------------------------------------------------------------------
 # USAGE: fts3_integrity_check TBL
 #
@@ -98,7 +159,7 @@ proc fts3_integrity_check {tbl} {
           set es "Error at docid=$iDoc col=$iCol pos=$pos. Index is missing"
           lappend errors $es
         } else {
-          if {$C($iDoc,$iCol,$pos) != "$term"} {
+          if {[string compare $C($iDoc,$iCol,$pos) $term]} {
             set    es "Error at docid=$iDoc col=$iCol pos=$pos. Index "
             append es "has \"$C($iDoc,$iCol,$pos)\", document has \"$term\""
             lappend errors $es
index 805a78cf979d776646dfc9dcba758db3ddee54ef..a5995921f34133309843d8942177544deb90cee1 100644 (file)
@@ -23,35 +23,6 @@ ifcapable !fts3 {
   return
 }
 
-proc fts3_build_db_1 {n} {
-
-  if {$n > 10000} {error "n must be <= 10000"}
-
-  db eval { CREATE VIRTUAL TABLE t1 USING fts4(x, y) }
-
-  set xwords [list zero one two three four five six seven eight nine ten]
-  set ywords [list alpha beta gamma delta epsilon zeta eta theta iota kappa]
-
-  for {set i 0} {$i < $n} {incr i} {
-    set x ""
-    set y ""
-
-    set x [list]
-    lappend x [lindex $xwords [expr ($i / 1000) % 10]]
-    lappend x [lindex $xwords [expr ($i / 100)  % 10]]
-    lappend x [lindex $xwords [expr ($i / 10)   % 10]]
-    lappend x [lindex $xwords [expr ($i / 1)   % 10]]
-
-    set y [list]
-    lappend y [lindex $ywords [expr ($i / 1000) % 10]]
-    lappend y [lindex $ywords [expr ($i / 100)  % 10]]
-    lappend y [lindex $ywords [expr ($i / 10)   % 10]]
-    lappend y [lindex $ywords [expr ($i / 1)   % 10]]
-
-    db eval { INSERT INTO t1(docid, x, y) VALUES($i, $x, $y) }
-  }
-}
-
 #-------------------------------------------------------------------------
 # Test cases 1.*
 #
@@ -98,6 +69,57 @@ do_execsql_test 1.5 {
   3 {0 1 2}
 }
 
+#-------------------------------------------------------------------------
+# Test cases 2.* test that errors in the xxx part of the 'merge=xxx' are
+# handled correctly.
+#
+do_execsql_test 2.0 { CREATE VIRTUAL TABLE t2 USING fts4 }
+
+foreach {tn arg} {
+  1   {merge=abc}
+  2   {merge=%%%}
+  3   {merge=,}
+  4   {merge=5,}
+  5   {merge=6,%}
+  6   {merge=6,six}
+  7   {merge=6,1}
+  8   {merge=6,0}
+} {
+  do_catchsql_test 2.$tn { 
+    INSERT INTO t2(t2) VALUES($arg);
+  } {1 {SQL logic error or missing database}}
+}
+
+#-------------------------------------------------------------------------
+# Test cases 3.*
+#
+do_test 3.0 { 
+  reset_db
+  execsql { PRAGMA page_size = 512 }
+  fts3_build_db_2 30040 
+} {}
+do_test 3.1 { fts3_integrity_check t2 } {ok}
+
+do_execsql_test 3.2 { 
+  SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level 
+} {
+  0 {0 1 2 3 4 5 6 7} 
+  1 {0 1 2 3 4} 
+  2 {0 1 2 3 4} 
+  3 {0 1 2 3 4 5 6}
+}
+
+do_execsql_test 3.3 { 
+  INSERT INTO t2(t2) VALUES('merge=1000000,2');
+  SELECT level, group_concat(idx, ' ') FROM t2_segdir GROUP BY level 
+} {
+  0 {0 1} 
+  1 {0 1} 
+  2 0 
+  3 {0 1}  
+  4 {0 1} 
+  5 0
+}
 
 finish_test
 
diff --git a/test/fts4merge2.test b/test/fts4merge2.test
new file mode 100644 (file)
index 0000000..308b692
--- /dev/null
@@ -0,0 +1,38 @@
+
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/fts3_common.tcl
+source $testdir/malloc_common.tcl
+set ::testprefix fts4merge2
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts3 {
+  finish_test
+  return
+}
+
+do_test 1.0 {
+  fts3_build_db_1 1000
+  faultsim_save_and_close
+} {}
+
+do_faultsim_test 1.1 -faults oom-* -prep {
+  faultsim_restore_and_reopen
+} -body {
+  execsql { INSERT INTO t1(t1) VALUES('merge=32,4') }
+} -test {
+  faultsim_test_result {0 {}} 
+}
+
+do_faultsim_test 1.2 -faults oom-t* -prep {
+  if {$iFail<100} {set iFail 803}
+  faultsim_restore_and_reopen
+} -body {
+  execsql { INSERT INTO t1(t1) VALUES('merge=1,2') }
+  execsql { INSERT INTO t1(t1) VALUES('merge=1,2') }
+} -test {
+  faultsim_test_result {0 {}} 
+}
+
+finish_test
index 26c1b2a5145e9ba447d995d2163132251d919d44..6f66e85e94702796d351829090c879a4b0f0ea7e 100644 (file)
@@ -184,7 +184,7 @@ test_suite "fts3" -prefix "" -description {
   fts3aux1.test fts3comp1.test fts3auto.test
   fts4aa.test fts4content.test
   fts3conf.test fts3prefix.test fts3fault2.test fts3corrupt.test
-  fts3corrupt2.test fts3first.test fts4langid.test
+  fts3corrupt2.test fts3first.test fts4langid.test fts4merge.test
 }