/ Check-in [1c68687a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge auto-incr-merge with incr-merge branch.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | fts4-incr-merge
Files: files | file ages | folders
SHA1:1c68687ab6d05b100191663820e7d82377d52445
User & Date: dan 2012-03-24 14:45:59
Context
2012-03-24
16:11
Remove the Fts3Table.mxLevel variable. check-in: 67a0cffc user: dan tags: fts4-incr-merge
14:45
Merge auto-incr-merge with incr-merge branch. check-in: 1c68687a user: dan tags: fts4-incr-merge
14:45
Modify the way the number of leaves written and the maximum relative level are calculated in the auto-incr-merge code. Closed-Leaf check-in: 0d841c95 user: dan tags: fts4-auto-incr-merge
2012-03-23
18:26
Fix a spurious SQLITE_CONSTRAINT error that may be returned by an incr-merge operation. check-in: ed7c17ea user: dan tags: fts4-incr-merge
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3.c.

  1272   1272     p->nPendingData = 0;
  1273   1273     p->azColumn = (char **)&p[1];
  1274   1274     p->pTokenizer = pTokenizer;
  1275   1275     p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
  1276   1276     p->bHasDocsize = (isFts4 && bNoDocsize==0);
  1277   1277     p->bHasStat = isFts4;
  1278   1278     p->bDescIdx = bDescIdx;
         1279  +  p->bAutoincrmerge = 0xff;   /* 0xff means setting unknown */
  1279   1280     p->zContentTbl = zContent;
  1280   1281     p->zLanguageid = zLanguageid;
  1281   1282     zContent = 0;
  1282   1283     zLanguageid = 0;
  1283   1284     TESTONLY( p->inTransaction = -1 );
  1284   1285     TESTONLY( p->mxSavepoint = -1 );
  1285   1286   
................................................................................
  3098   3099   }
  3099   3100   
  3100   3101   /*
  3101   3102   ** Implementation of xSync() method. Flush the contents of the pending-terms
  3102   3103   ** hash-table to the database.
  3103   3104   */
  3104   3105   static int fts3SyncMethod(sqlite3_vtab *pVtab){
  3105         -  int rc = sqlite3Fts3PendingTermsFlush((Fts3Table *)pVtab);
  3106         -  sqlite3Fts3SegmentsClose((Fts3Table *)pVtab);
         3106  +  const int nMinMerge = 64;       /* Minimum amount of incr-merge work to do */
         3107  +  Fts3Table *p = (Fts3Table*)pVtab;
         3108  +  int rc = sqlite3Fts3PendingTermsFlush(p);
         3109  +
         3110  +  if( rc==SQLITE_OK && p->bAutoincrmerge==1 && p->nLeafAdd>(nMinMerge/16) ){
         3111  +    int mxLevel = 0;              /* Maximum relative level value in db */
         3112  +    int A;                        /* Incr-merge parameter A */
         3113  +
         3114  +    rc = sqlite3Fts3MaxLevel(p, &mxLevel);
         3115  +    assert( rc==SQLITE_OK || mxLevel==0 );
         3116  +    A = p->nLeafAdd * p->mxLevel;
         3117  +    A += (A/2);
         3118  +    if( A>nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, 8);
         3119  +  }
         3120  +  sqlite3Fts3SegmentsClose(p);
  3107   3121     return rc;
  3108   3122   }
  3109   3123   
  3110   3124   /*
  3111   3125   ** Implementation of xBegin() method. This is a no-op.
  3112   3126   */
  3113   3127   static int fts3BeginMethod(sqlite3_vtab *pVtab){
................................................................................
  3114   3128     TESTONLY( Fts3Table *p = (Fts3Table*)pVtab );
  3115   3129     UNUSED_PARAMETER(pVtab);
  3116   3130     assert( p->pSegments==0 );
  3117   3131     assert( p->nPendingData==0 );
  3118   3132     assert( p->inTransaction!=1 );
  3119   3133     TESTONLY( p->inTransaction = 1 );
  3120   3134     TESTONLY( p->mxSavepoint = -1; );
         3135  +  p->nLeafAdd = 0;
  3121   3136     return SQLITE_OK;
  3122   3137   }
  3123   3138   
  3124   3139   /*
  3125   3140   ** Implementation of xCommit() method. This is a no-op. The contents of
  3126   3141   ** the pending-terms hash-table have already been flushed into the database
  3127   3142   ** by fts3SyncMethod().

Changes to ext/fts3/fts3Int.h.

   192    192     const char *zDb;                /* logical database name */
   193    193     const char *zName;              /* virtual table name */
   194    194     int nColumn;                    /* number of named columns in virtual table */
   195    195     char **azColumn;                /* column names.  malloced */
   196    196     sqlite3_tokenizer *pTokenizer;  /* tokenizer for inserts and queries */
   197    197     char *zContentTbl;              /* content=xxx option, or NULL */
   198    198     char *zLanguageid;              /* languageid=xxx option, or NULL */
          199  +  u8 bAutoincrmerge;              /* True if automerge=1 */
          200  +  int mxLevel;                    /* Maximum level seen on this transaction */
          201  +  u32 nLeafAdd;                   /* Number of leaf blocks added this trans */
   199    202   
   200    203     /* Precompiled statements used by the implementation. Each of these 
   201    204     ** statements is run and reset within a single virtual table API call. 
   202    205     */
   203         -  sqlite3_stmt *aStmt[36];
          206  +  sqlite3_stmt *aStmt[37];
   204    207   
   205    208     char *zReadExprlist;
   206    209     char *zWriteExprlist;
   207    210   
   208    211     int nNodeSize;                  /* Soft limit for node size */
   209    212     u8 bHasStat;                    /* True if %_stat table exists */
   210    213     u8 bHasDocsize;                 /* True if %_docsize table exists */
................................................................................
   424    427   int sqlite3Fts3SelectDocsize(Fts3Table *, sqlite3_int64, sqlite3_stmt **);
   425    428   
   426    429   void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *);
   427    430   int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int);
   428    431   int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *);
   429    432   void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *);
   430    433   void sqlite3Fts3SegmentsClose(Fts3Table *);
          434  +int sqlite3Fts3MaxLevel(Fts3Table *, int *);
   431    435   
   432    436   /* Special values interpreted by sqlite3SegReaderCursor() */
   433    437   #define FTS3_SEGCURSOR_PENDING        -1
   434    438   #define FTS3_SEGCURSOR_ALL            -2
   435    439   
   436    440   int sqlite3Fts3SegReaderStart(Fts3Table*, Fts3MultiSegReader*, Fts3SegFilter*);
   437    441   int sqlite3Fts3SegReaderStep(Fts3Table *, Fts3MultiSegReader *);
................................................................................
   474    478   
   475    479     /* Output values. Valid only after Fts3SegReaderStep() returns SQLITE_ROW. */
   476    480     char *zTerm;                    /* Pointer to term buffer */
   477    481     int nTerm;                      /* Size of zTerm in bytes */
   478    482     char *aDoclist;                 /* Pointer to doclist buffer */
   479    483     int nDoclist;                   /* Size of aDoclist[] in bytes */
   480    484   };
          485  +
          486  +int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
   481    487   
   482    488   /* fts3.c */
   483    489   int sqlite3Fts3PutVarint(char *, sqlite3_int64);
   484    490   int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
   485    491   int sqlite3Fts3GetVarint32(const char *, int *);
   486    492   int sqlite3Fts3VarintLen(sqlite3_uint64);
   487    493   void sqlite3Fts3Dequote(char *);

Changes to ext/fts3/fts3_write.c.

    68     68   
    69     69   /*
    70     70   ** The two values that may be meaningfully bound to the :1 parameter in
    71     71   ** statements SQL_REPLACE_STAT and SQL_SELECT_STAT.
    72     72   */
    73     73   #define FTS_STAT_DOCTOTAL      0
    74     74   #define FTS_STAT_INCRMERGEHINT 1
           75  +#define FTS_STAT_AUTOINCRMERGE 2
    75     76   
    76     77   /*
    77     78   ** If FTS_LOG_MERGES is defined, call sqlite3_log() to report each automatic
    78     79   ** and incremental merge operation that takes place. This is used for 
    79     80   ** debugging FTS only, it should not usually be turned on in production
    80     81   ** systems.
    81     82   */
................................................................................
   260    261   #define SQL_MAX_LEAF_NODE_ESTIMATE    29
   261    262   #define SQL_DELETE_SEGDIR_ENTRY       30
   262    263   #define SQL_SHIFT_SEGDIR_ENTRY        31
   263    264   #define SQL_SELECT_SEGDIR             32
   264    265   #define SQL_CHOMP_SEGDIR              33
   265    266   #define SQL_SEGMENT_IS_APPENDABLE     34
   266    267   #define SQL_SELECT_INDEXES            35
          268  +#define SQL_SELECT_MXLEVEL            36
   267    269   
   268    270   /*
   269    271   ** This function is used to obtain an SQLite prepared statement handle
   270    272   ** for the statement identified by the second argument. If successful,
   271    273   ** *pp is set to the requested statement handle and SQLITE_OK returned.
   272    274   ** Otherwise, an SQLite error code is returned and *pp is set to 0.
   273    275   **
................................................................................
   326    328   ** if no level in the FTS index contains more than ? segments, the statement
   327    329   ** returns zero rows.  */
   328    330   /* 28 */ "SELECT level FROM %Q.'%q_segdir' GROUP BY level HAVING count(*)>=?"
   329    331            "  ORDER BY (level %% 1024) DESC LIMIT 1",
   330    332   
   331    333   /* Estimate the upper limit on the number of leaf nodes in a new segment
   332    334   ** created by merging the oldest :2 segments from absolute level :1. See 
   333         -** function fts3Incrmerge() for details.  */
          335  +** function sqlite3Fts3Incrmerge() for details.  */
   334    336   /* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) "
   335    337            "  FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?",
   336    338   
   337    339   /* SQL_DELETE_SEGDIR_ENTRY
   338    340   **   Delete the %_segdir entry on absolute level :1 with index :2.  */
   339    341   /* 30 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?",
   340    342   
................................................................................
   358    360   /* SQL_SEGMENT_IS_APPENDABLE
   359    361   **   Return a single row if the segment with end_block=? is appendable. Or
   360    362   **   no rows otherwise.  */
   361    363   /* 34 */  "SELECT 1 FROM %Q.'%q_segments' WHERE blockid=? AND block IS NULL",
   362    364   
   363    365   /* SQL_SELECT_INDEXES
   364    366   **   Return the list of valid segment indexes for absolute level ?  */
   365         -/* 35 */  "SELECT idx FROM %Q.'%q_segdir' WHERE level=? ORDER BY 1 ASC"
          367  +/* 35 */  "SELECT idx FROM %Q.'%q_segdir' WHERE level=? ORDER BY 1 ASC",
          368  +
          369  +/* SQL_SELECT_MXLEVEL
          370  +**   Return the largest relative level in the FTS index or indexes.  */
          371  +/* 36 */  "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'"
   366    372     };
   367    373     int rc = SQLITE_OK;
   368    374     sqlite3_stmt *pStmt;
   369    375   
   370    376     assert( SizeofArray(azSql)==SizeofArray(p->aStmt) );
   371    377     assert( eStmt<SizeofArray(azSql) && eStmt>=0 );
   372    378     
................................................................................
  1863   1869       sqlite3_bind_int64(pStmt, 1, iBlock);
  1864   1870       sqlite3_bind_blob(pStmt, 2, z, n, SQLITE_STATIC);
  1865   1871       sqlite3_step(pStmt);
  1866   1872       rc = sqlite3_reset(pStmt);
  1867   1873     }
  1868   1874     return rc;
  1869   1875   }
         1876  +
         1877  +/*
         1878  +** Update the Fts3Table.mxLevel field, if appropriate
         1879  +*/
         1880  +static void fts3UpdateMaxLevel(Fts3Table *p, sqlite3_int64 iLevel){
         1881  +  iLevel %= FTS3_SEGDIR_MAXLEVEL;
         1882  +  if( iLevel>p->mxLevel ) p->mxLevel = iLevel;
         1883  +}
         1884  +
         1885  +/*
         1886  +** Find the largest relative level number in the table. If successful, set
         1887  +** *pnMax to this value and return SQLITE_OK. Otherwise, if an error occurs,
         1888  +** set *pnMax to zero and return an SQLite error code.
         1889  +*/
         1890  +int sqlite3Fts3MaxLevel(Fts3Table *p, int *pnMax){
         1891  +  int rc;
         1892  +  int mxLevel = 0;
         1893  +  sqlite3_stmt *pStmt = 0;
         1894  +
         1895  +  rc = fts3SqlStmt(p, SQL_SELECT_MXLEVEL, &pStmt, 0);
         1896  +  if( rc==SQLITE_OK ){
         1897  +    if( SQLITE_ROW==sqlite3_step(pStmt) ){
         1898  +      mxLevel = sqlite3_column_int(pStmt, 0);
         1899  +    }
         1900  +    rc = sqlite3_reset(pStmt);
         1901  +  }
         1902  +  *pnMax = mxLevel;
         1903  +  return rc;
         1904  +}
  1870   1905   
  1871   1906   /* 
  1872   1907   ** Insert a record into the %_segdir table.
  1873   1908   */
  1874   1909   static int fts3WriteSegdir(
  1875   1910     Fts3Table *p,                   /* Virtual table handle */
  1876   1911     sqlite3_int64 iLevel,           /* Value for "level" field (absolute level) */
................................................................................
  1881   1916     char *zRoot,                    /* Blob value for "root" field */
  1882   1917     int nRoot                       /* Number of bytes in buffer zRoot */
  1883   1918   ){
  1884   1919     sqlite3_stmt *pStmt;
  1885   1920     int rc = fts3SqlStmt(p, SQL_INSERT_SEGDIR, &pStmt, 0);
  1886   1921     if( rc==SQLITE_OK ){
  1887   1922       sqlite3_bind_int64(pStmt, 1, iLevel);
         1923  +    fts3UpdateMaxLevel(p, iLevel);
  1888   1924       sqlite3_bind_int(pStmt, 2, iIdx);
  1889   1925       sqlite3_bind_int64(pStmt, 3, iStartBlock);
  1890   1926       sqlite3_bind_int64(pStmt, 4, iLeafEndBlock);
  1891   1927       sqlite3_bind_int64(pStmt, 5, iEndBlock);
  1892   1928       sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC);
  1893   1929       sqlite3_step(pStmt);
  1894   1930       rc = sqlite3_reset(pStmt);
................................................................................
  2180   2216   
  2181   2217     if( nData>0 && nData+nReq>p->nNodeSize ){
  2182   2218       int rc;
  2183   2219   
  2184   2220       /* The current leaf node is full. Write it out to the database. */
  2185   2221       rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
  2186   2222       if( rc!=SQLITE_OK ) return rc;
         2223  +    p->nLeafAdd++;
  2187   2224   
  2188   2225       /* Add the current term to the interior node tree. The term added to
  2189   2226       ** the interior tree must:
  2190   2227       **
  2191   2228       **   a) be greater than the largest term on the leaf node just written
  2192   2229       **      to the database (still available in pWriter->zTerm), and
  2193   2230       **
................................................................................
  2288   2325             p, iLevel, iIdx, pWriter->iFirst, iLastLeaf, iLast, zRoot, nRoot);
  2289   2326       }
  2290   2327     }else{
  2291   2328       /* The entire tree fits on the root node. Write it to the segdir table. */
  2292   2329       rc = fts3WriteSegdir(
  2293   2330           p, iLevel, iIdx, 0, 0, 0, pWriter->aData, pWriter->nData);
  2294   2331     }
         2332  +  p->nLeafAdd++;
  2295   2333     return rc;
  2296   2334   }
  2297   2335   
  2298   2336   /*
  2299   2337   ** Release all memory held by the SegmentWriter object passed as the 
  2300   2338   ** first argument.
  2301   2339   */
................................................................................
  2365   2403     if( rc!=SQLITE_OK ) return rc;
  2366   2404     sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
  2367   2405     sqlite3_bind_int64(pStmt, 2, 
  2368   2406         getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
  2369   2407     );
  2370   2408     if( SQLITE_ROW==sqlite3_step(pStmt) ){
  2371   2409       *pnMax = sqlite3_column_int64(pStmt, 0);
         2410  +    fts3UpdateMaxLevel(p, *pnMax);
  2372   2411     }
  2373   2412     return sqlite3_reset(pStmt);
  2374   2413   }
  2375   2414   
  2376   2415   /*
  2377   2416   ** Delete all entries in the %_segments table associated with the segment
  2378   2417   ** opened with seg-reader pSeg. This function does not affect the contents
................................................................................
  2995   3034   
  2996   3035   /* 
  2997   3036   ** Flush the contents of pendingTerms to level 0 segments.
  2998   3037   */
  2999   3038   int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
  3000   3039     int rc = SQLITE_OK;
  3001   3040     int i;
         3041  +        
  3002   3042     for(i=0; rc==SQLITE_OK && i<p->nIndex; i++){
  3003   3043       rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING);
  3004   3044       if( rc==SQLITE_DONE ) rc = SQLITE_OK;
  3005   3045     }
  3006   3046     sqlite3Fts3PendingTermsClear(p);
         3047  +
         3048  +  /* Determine the auto-incr-merge setting if unknown.  If enabled,
         3049  +  ** estimate the number of leaf blocks of content to be written
         3050  +  */
         3051  +  if( rc==SQLITE_OK && p->bHasStat
         3052  +   && p->bAutoincrmerge==0xff && p->nLeafAdd>0
         3053  +  ){
         3054  +    sqlite3_stmt *pStmt = 0;
         3055  +    rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0);
         3056  +    if( rc==SQLITE_OK ){
         3057  +      sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
         3058  +      rc = sqlite3_step(pStmt);
         3059  +      p->bAutoincrmerge = (rc==SQLITE_ROW && sqlite3_column_int(pStmt, 0));
         3060  +      rc = sqlite3_reset(pStmt);
         3061  +    }
         3062  +  }
  3007   3063     return rc;
  3008   3064   }
  3009   3065   
  3010   3066   /*
  3011   3067   ** Encode N integers as varints into a blob.
  3012   3068   */
  3013   3069   static void fts3EncodeIntArray(
................................................................................
  4468   4524   **
  4469   4525   ** Incremental merges happen nMin segments at a time. The two
  4470   4526   ** segments to be merged are the nMin oldest segments (the ones with
  4471   4527   ** the smallest indexes) in the highest level that contains at least
  4472   4528   ** nMin segments. Multiple merges might occur in an attempt to write the 
  4473   4529   ** quota of nMerge leaf blocks.
  4474   4530   */
  4475         -static int fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
         4531  +int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
  4476   4532     int rc;                         /* Return code */
  4477   4533     int nRem = nMerge;              /* Number of leaf pages yet to  be written */
  4478   4534     int bUseHint = 1;               /* True if hint has not yet been attempted */
  4479   4535     sqlite3_int64 iHintAbsLevel = 0;/* Hint level */
  4480   4536     int nHintSeg = 0;               /* Hint number of segments */
  4481   4537     int nSeg = 0;                   /* Number of input segments */
  4482   4538     sqlite3_int64 iAbsLevel = 0;    /* Absolute level number to work on */
................................................................................
  4573   4629     /* Write the hint values into the %_stat table for the next incr-merger */
  4574   4630     if( rc==SQLITE_OK && (iAbsLevel!=iHintAbsLevel || nHintSeg!=nSeg) ){
  4575   4631       rc = fts3IncrmergeHintStore(p, iAbsLevel, nSeg);
  4576   4632     }
  4577   4633   
  4578   4634     return rc;
  4579   4635   }
         4636  +
         4637  +/*
         4638  +** Convert the text beginning at *pz into an integer and return
         4639  +** its value.  Advance *pz to point to the first character past
         4640  +** the integer.
         4641  +*/
         4642  +static int fts3Getint(const char **pz){
         4643  +  const char *z = *pz;
         4644  +  int i = 0;
         4645  +  while( (*z)>='0' && (*z)<='9' ) i = 10*i + *(z++) - '0';
         4646  +  *pz = z;
         4647  +  return i;
         4648  +}
  4580   4649   
  4581   4650   /*
  4582   4651   ** Process statements of the form:
  4583   4652   **
  4584   4653   **    INSERT INTO table(table) VALUES('merge=A,B');
  4585   4654   **
  4586   4655   ** A and B are integers that decode to be the number of leaf pages
................................................................................
  4593   4662   ){
  4594   4663     int rc;
  4595   4664     int nMin = (FTS3_MERGE_COUNT / 2);
  4596   4665     int nMerge = 0;
  4597   4666     const char *z = zParam;
  4598   4667   
  4599   4668     /* Read the first integer value */
  4600         -  for(z=zParam; z[0]>='0' && z[0]<='9'; z++){
  4601         -    nMerge = nMerge * 10 + (z[0] - '0');
  4602         -  }
         4669  +  nMerge = fts3Getint(&z);
  4603   4670   
  4604   4671     /* If the first integer value is followed by a ',',  read the second
  4605   4672     ** integer value. */
  4606   4673     if( z[0]==',' && z[1]!='\0' ){
  4607   4674       z++;
  4608         -    nMin = 0;
  4609         -    while( z[0]>='0' && z[0]<='9' ){
  4610         -      nMin = nMin * 10 + (z[0] - '0');
  4611         -      z++;
  4612         -    }
         4675  +    nMin = fts3Getint(&z);
  4613   4676     }
  4614   4677   
  4615   4678     if( z[0]!='\0' || nMin<2 ){
  4616   4679       rc = SQLITE_ERROR;
  4617   4680     }else{
  4618         -    rc = fts3Incrmerge(p, nMerge, nMin);
         4681  +    rc = sqlite3Fts3Incrmerge(p, nMerge, nMin);
  4619   4682       sqlite3Fts3SegmentsClose(p);
  4620   4683     }
  4621   4684     return rc;
  4622   4685   }
         4686  +
         4687  +/*
         4688  +** Process statements of the form:
         4689  +**
         4690  +**    INSERT INTO table(table) VALUES('automerge=X');
         4691  +**
         4692  +** where X is an integer.  X==0 means to turn automerge off.  X!=0 means
         4693  +** turn it on.  The setting is persistent.
         4694  +*/
         4695  +static int fts3DoAutoincrmerge(
         4696  +  Fts3Table *p,                   /* FTS3 table handle */
         4697  +  const char *zParam              /* Nul-terminated string containing boolean */
         4698  +){
         4699  +  int rc;
         4700  +  sqlite3_stmt *pStmt = 0;
         4701  +  p->bAutoincrmerge = fts3Getint(&zParam)!=0;
         4702  +  rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0);
         4703  +  if( rc ) return rc;;
         4704  +  sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
         4705  +  sqlite3_bind_int(pStmt, 2, p->bAutoincrmerge);
         4706  +  sqlite3_step(pStmt);
         4707  +  rc = sqlite3_reset(pStmt);
         4708  +  return rc;
         4709  +}
         4710  +
  4623   4711   
  4624   4712   /*
  4625   4713   ** Handle a 'special' INSERT of the form:
  4626   4714   **
  4627   4715   **   "INSERT INTO tbl(tbl) VALUES(<expr>)"
  4628   4716   **
  4629   4717   ** Argument pVal contains the result of <expr>. Currently the only 
................................................................................
  4638   4726       return SQLITE_NOMEM;
  4639   4727     }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){
  4640   4728       rc = fts3DoOptimize(p, 0);
  4641   4729     }else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){
  4642   4730       rc = fts3DoRebuild(p);
  4643   4731     }else if( nVal>6 && 0==sqlite3_strnicmp(zVal, "merge=", 6) ){
  4644   4732       rc = fts3DoIncrmerge(p, &zVal[6]);
         4733  +  }else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){
         4734  +    rc = fts3DoAutoincrmerge(p, &zVal[10]);
  4645   4735   #ifdef SQLITE_TEST
  4646   4736     }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
  4647   4737       p->nNodeSize = atoi(&zVal[9]);
  4648   4738       rc = SQLITE_OK;
  4649   4739     }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
  4650   4740       p->nMaxPendingData = atoi(&zVal[11]);
  4651   4741       rc = SQLITE_OK;

Changes to test/bc_common.tcl.

    13     13     }
    14     14     foreach file [glob -nocomplain $pattern] {
    15     15       if {[file executable $file] && [file isfile $file]} {lappend binaries $file}
    16     16     }
    17     17   
    18     18     if {[llength $binaries]==0} {
    19     19       puts "WARNING: No historical binaries to test against."
    20         -    puts "WARNING: Omitting backwards-compatibility tests $zFile"
           20  +    puts "WARNING: Omitting backwards-compatibility tests"
    21     21     }
    22     22   
    23     23     foreach bin $binaries {
    24     24       puts -nonewline "Testing against $bin - "
    25     25       flush stdout
    26     26       puts "version [get_version $bin]"
    27     27     }
................................................................................
    66     66   }
    67     67   
    68     68   proc do_all_bc_test {script} {
    69     69     foreach bin $::BC(binaries) {
    70     70       uplevel [list do_bc_test $bin $script]
    71     71     }
    72     72   }
    73         -
    74         -
    75         -
    76         -