/ Check-in [2fe579e7]
Login

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

Overview
Comment:Add some missing comments and fix some other issues in fts3 code.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | fts3-refactor
Files: files | file ages | folders
SHA1:2fe579e778b75fbf503c02e01e5424c1926f2b49
User & Date: dan 2009-11-18 15:35:59
Context
2009-11-19
00:15
Fix problems introduced into fts3 as part of the refactoring. check-in: fa0998e1 user: dan tags: fts3-refactor
2009-11-18
15:35
Add some missing comments and fix some other issues in fts3 code. check-in: 2fe579e7 user: dan tags: fts3-refactor
2009-11-17
12:52
Improvements to the way fts3 reads the full-text index. check-in: 45c051e7 user: dan tags: fts3-refactor
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3.c.

   891    891         }
   892    892       }
   893    893     }
   894    894     return rc;
   895    895   }
   896    896   
   897    897   
   898         -/* TODO(shess) If we pushed LeafReader to the top of the file, or to
   899         -** another file, term_select() could be pushed above
   900         -** docListOfTerm().
   901         -*/
   902         -/*
   903         -** Read a single block from the %_segments table.
   904         -*/
   905         -static int fts3ReadBlock(
   906         -  Fts3Table *p,
   907         -  sqlite3_int64 iBlock,
   908         -  char const **pzBlock,
   909         -  int *pnBlock
   910         -){
   911         -  sqlite3_stmt *pStmt;
   912         -  int rc = sqlite3Fts3SqlStmt(p, FTS3_SQL_GET_BLOCK, &pStmt);
   913         -  if( rc!=SQLITE_OK ) return rc;
   914         -  sqlite3_reset(pStmt);
   915         -
   916         -  sqlite3_bind_int64(pStmt, 1, iBlock);
   917         -  rc = sqlite3_step(pStmt); 
   918         -  if( rc!=SQLITE_ROW ){
   919         -    return SQLITE_CORRUPT;
   920         -  }
   921         -
   922         -  *pnBlock = sqlite3_column_bytes(pStmt, 0);
   923         -  *pzBlock = (char *)sqlite3_column_blob(pStmt, 0);
   924         -  if( !*pzBlock ){
   925         -    return SQLITE_NOMEM;
   926         -  }
   927         -  return SQLITE_OK;
   928         -}
   929         -
   930    898   /*
   931    899   ** The buffer pointed to by argument zNode (size nNode bytes) contains the
   932    900   ** root node of a b-tree segment. The segment is guaranteed to be at least
   933    901   ** one level high (i.e. the root node is not also a leaf). If successful,
   934    902   ** this function locates the leaf node of the segment that may contain the 
   935    903   ** term specified by arguments zTerm and nTerm and writes its block number 
   936    904   ** to *piLeaf.
................................................................................
  1009    977       */
  1010    978       if( iHeight==1 ){
  1011    979         *piLeaf = iChild;
  1012    980         break;
  1013    981       }
  1014    982   
  1015    983       /* Descend to interior node iChild. */
  1016         -    rc = fts3ReadBlock(p, iChild, &zCsr, &nBlock);
          984  +    rc = sqlite3Fts3ReadBlock(p, iChild, &zCsr, &nBlock);
  1017    985       if( rc!=SQLITE_OK ) break;
  1018    986       zEnd = &zCsr[nBlock];
  1019    987     }
  1020    988     sqlite3_free(zBuffer);
  1021    989     return rc;
  1022    990   }
  1023    991   
................................................................................
  1520   1488     ** searches, this is always a single leaf. For prefix searches, this
  1521   1489     ** may be a contiguous block of leaves.
  1522   1490     **
  1523   1491     ** The code in this loop does not actually load any leaves into memory
  1524   1492     ** (unless the root node happens to be a leaf). It simply examines the
  1525   1493     ** b-tree structure to determine which leaves need to be inspected.
  1526   1494     */
  1527         -  rc = sqlite3Fts3SqlStmt(p, FTS3_SQL_GET_ALL_SEGDIRS, &pStmt);
         1495  +  rc = sqlite3Fts3AllSegdirs(p, &pStmt);
  1528   1496     while( rc==SQLITE_OK && SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
  1529   1497       Fts3SegReader *pNew = 0;
  1530   1498       int nRoot = sqlite3_column_bytes(pStmt, 4);
  1531   1499       char const *zRoot = sqlite3_column_blob(pStmt, 4);
  1532   1500       if( sqlite3_column_int64(pStmt, 1)==0 ){
  1533   1501         /* The entire segment is stored on the root node (which must be a
  1534   1502         ** leaf). Do not bother inspecting any data in this case, just

Changes to ext/fts3/fts3Int.h.

   170    170                           sqlite3_vtab **, char **);
   171    171   
   172    172   /* fts3_write.c */
   173    173   int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
   174    174   int sqlite3Fts3PendingTermsFlush(Fts3Table *);
   175    175   void sqlite3Fts3PendingTermsClear(Fts3Table *);
   176    176   int sqlite3Fts3Optimize(Fts3Table *);
          177  +int sqlite3Fts3SegReaderNew(Fts3Table *,int, sqlite3_int64,
          178  +  sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
          179  +void sqlite3Fts3SegReaderFree(Fts3SegReader *);
          180  +int sqlite3Fts3SegReaderIterate(
          181  +  Fts3Table *, Fts3SegReader **, int, Fts3SegFilter *,
          182  +  int (*)(Fts3Table *, void *, char *, int, char *, int),  void *
          183  +);
          184  +int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char const**, int*);
          185  +int sqlite3Fts3AllSegdirs(Fts3Table*, sqlite3_stmt **);
   177    186   
   178    187   /* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
   179    188   #define FTS3_SEGMENT_REQUIRE_POS   0x00000001
   180    189   #define FTS3_SEGMENT_IGNORE_EMPTY  0x00000002
   181    190   #define FTS3_SEGMENT_COLUMN_FILTER 0x00000004
   182    191   #define FTS3_SEGMENT_PREFIX        0x00000008
   183    192   
          193  +/* Type passed as 4th argument to SegmentReaderIterate() */
   184    194   struct Fts3SegFilter {
   185    195     const char *zTerm;
   186    196     int nTerm;
   187    197     int iCol;
   188    198     int flags;
   189    199   };
   190    200   
   191         -int sqlite3Fts3SegReaderNew(Fts3Table *,int, sqlite3_int64,
   192         -  sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
   193         -void sqlite3Fts3SegReaderFree(Fts3SegReader *);
   194         -
   195         -int sqlite3Fts3SegReaderIterate(
   196         -  Fts3Table *, Fts3SegReader **, int, Fts3SegFilter *,
   197         -  int (*)(Fts3Table *, void *, char *, int, char *, int),  void *
   198         -);
   199         -
   200    201   /* fts3.c */
   201    202   int sqlite3Fts3PutVarint(char *, sqlite3_int64);
   202    203   int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
   203    204   int sqlite3Fts3GetVarint32(const char *, int *);
   204    205   int sqlite3Fts3VarintLen(sqlite3_uint64);
   205    206   void sqlite3Fts3Dequote(char *);
   206    207   
   207         -/* Valid arguments for the second argument to sqlite3Fts3SqlStmt() */
   208         -#define FTS3_SQL_GET_ALL_SEGDIRS 11
   209         -#define FTS3_SQL_GET_BLOCK 17
   210         -int sqlite3Fts3SqlStmt(Fts3Table *, int, sqlite3_stmt **);
   211         -
   212    208   /* fts3_tokenizer.c */
   213    209   const char *sqlite3Fts3NextToken(const char *, int *);
   214    210   int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *);
   215    211   int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, 
   216    212     const char *, sqlite3_tokenizer **, const char **, char **
   217    213   );
   218    214   

Changes to ext/fts3/fts3_write.c.

    25     25   #define INTERIOR_MAX 2048         /* Soft limit for segment node size */
    26     26   #define LEAF_MAX 2048             /* Soft limit for segment leaf size */
    27     27   
    28     28   typedef struct PendingList PendingList;
    29     29   typedef struct SegmentNode SegmentNode;
    30     30   typedef struct SegmentWriter SegmentWriter;
    31     31   
           32  +/*
           33  +** Data structure used while accumulating terms in the pending-terms hash
           34  +** table. The hash table entry maps from term (a string) to a malloced
           35  +** instance of this structure.
           36  +*/
    32     37   struct PendingList {
    33     38     int nData;
    34     39     char *aData;
    35     40     int nSpace;
    36     41     sqlite3_int64 iLastDocid;
    37     42     sqlite3_int64 iLastCol;
    38     43     sqlite3_int64 iLastPos;
    39     44   };
    40     45   
    41     46   /*
    42         -** fts3SegReaderNew()
    43         -** fts3SegReaderNext()
    44         -** sqlite3Fts3SegReaderFree()
           47  +** An instance of this structure is used to iterate through the terms on
           48  +** a contiguous set of segment b-tree leaf nodes. Although the details of
           49  +** this structure are only manipulated by code in this file, opaque handles
           50  +** of type Fts3SegReader* are also used by code in fts3.c to iterate through
           51  +** terms when querying the full-text index. See functions:
           52  +**
           53  +**   sqlite3Fts3SegReaderNew()
           54  +**   sqlite3Fts3SegReaderFree()
           55  +**   sqlite3Fts3SegReaderIterate()
    45     56   */
    46     57   struct Fts3SegReader {
    47     58     int iIdx;                       /* Index within level */
    48     59     sqlite3_int64 iStartBlock;
    49     60     sqlite3_int64 iEndBlock;
    50     61     sqlite3_stmt *pStmt;            /* SQL Statement to access leaf nodes */
    51     62     char *aNode;                    /* Pointer to node data (or NULL) */
................................................................................
    64     75   
    65     76     /* The following variables are used to iterate through the current doclist */
    66     77     char *pOffsetList;
    67     78     sqlite3_int64 iDocid;
    68     79   };
    69     80   
    70     81   /*
    71         -** fts3LeafAdd()
    72         -** fts3LeafWrite()
    73         -** fts3LeafFree()
           82  +** An instance of this structure is used to create a segment b-tree in the
           83  +** database. The internal details of this type are only accessed by the
           84  +** following functions:
           85  +**
           86  +**   fts3SegWriterAdd()
           87  +**   fts3SegWriterFlush()
           88  +**   fts3SegWriterFree()
    74     89   */
    75     90   struct SegmentWriter {
    76     91     SegmentNode *pTree;             /* Pointer to interior tree structure */
    77     92     sqlite3_int64 iFirst;           /* First slot in %_segments written */
    78     93     sqlite3_int64 iFree;            /* Next free slot in %_segments */
    79     94     char *zTerm;                    /* Pointer to previous term buffer */
    80     95     int nTerm;                      /* Number of bytes in zTerm */
................................................................................
    84     99     int nData;                      /* Bytes of data in aData */
    85    100     char *aData;                    /* Pointer to block from malloc() */
    86    101   };
    87    102   
    88    103   /*
    89    104   ** Type SegmentNode is used by the following three functions to create
    90    105   ** the interior part of the segment b+-tree structures (everything except
    91         -** the leaf nodes. These functions and type are only ever used by code
    92         -** within the fts3LeafXXX() family of functions described above.
          106  +** the leaf nodes). These functions and type are only ever used by code
          107  +** within the fts3SegWriterXXX() family of functions described above.
    93    108   **
    94    109   **   fts3NodeAddTerm()
    95    110   **   fts3NodeWrite()
    96    111   **   fts3NodeFree()
    97    112   */
    98    113   struct SegmentNode {
    99    114     SegmentNode *pParent;           /* Parent node (or NULL for root node) */
................................................................................
   105    120     int nMalloc;                    /* Size of malloc'd buffer at zMalloc */
   106    121     char *zMalloc;                  /* Malloc'd space (possibly) used for zTerm */
   107    122     int nData;                      /* Bytes of valid data so far */
   108    123     char *aData;                    /* Node data */
   109    124   };
   110    125   
   111    126   /*
   112         -** This is a comparison function used as a qsort() callback when sorting
   113         -** an array of pending terms by term.
          127  +** Valid values for the second argument to fts3SqlStmt().
   114    128   */
   115         -static int qsortCompare(const void *lhs, const void *rhs){
   116         -  char *z1 = fts3HashKey(*(Fts3HashElem **)lhs);
   117         -  char *z2 = fts3HashKey(*(Fts3HashElem **)rhs);
   118         -  int n1 = fts3HashKeysize(*(Fts3HashElem **)lhs);
   119         -  int n2 = fts3HashKeysize(*(Fts3HashElem **)rhs);
   120         -
   121         -  int n = (n1<n2 ? n1 : n2);
   122         -  int c = memcmp(z1, z2, n);
   123         -  if( c==0 ){
   124         -    c = n1 - n2;
   125         -  }
   126         -  return c;
   127         -}
   128         -
   129    129   #define SQL_DELETE_CONTENT             0
   130    130   #define SQL_IS_EMPTY                   1
   131    131   #define SQL_DELETE_ALL_CONTENT         2 
   132    132   #define SQL_DELETE_ALL_SEGMENTS        3
   133    133   #define SQL_DELETE_ALL_SEGDIR          4
   134    134   #define SQL_SELECT_CONTENT_BY_ROWID    5
   135    135   #define SQL_NEXT_SEGMENT_INDEX         6
   136    136   #define SQL_INSERT_SEGMENTS            7
   137    137   #define SQL_NEXT_SEGMENTS_ID           8
   138    138   #define SQL_INSERT_SEGDIR              9
   139         -
   140    139   #define SQL_SELECT_LEVEL              10
   141    140   #define SQL_SELECT_ALL_LEVEL          11
   142    141   #define SQL_SELECT_LEVEL_COUNT        12
   143    142   #define SQL_SELECT_SEGDIR_COUNT_MAX   13
   144         -
   145    143   #define SQL_DELETE_SEGDIR_BY_LEVEL    14
   146    144   #define SQL_DELETE_SEGMENTS_RANGE     15
   147    145   #define SQL_CONTENT_INSERT            16
          146  +#define SQL_GET_BLOCK                 17
   148    147   
   149    148   static int fts3SqlStmt(
   150    149     Fts3Table *p, 
   151    150     int eStmt, 
   152    151     sqlite3_stmt **pp, 
   153    152     sqlite3_value **apVal
   154    153   ){
................................................................................
   203    202         rc = sqlite3_bind_value(pStmt, i+1, apVal[i]);
   204    203       }
   205    204     }
   206    205     *pp = pStmt;
   207    206     return rc;
   208    207   }
   209    208   
   210         -int sqlite3Fts3SqlStmt(Fts3Table *p, int eStmt, sqlite3_stmt **ppStmt){
   211         -  return fts3SqlStmt(p, eStmt, ppStmt, 0);
          209  +/*
          210  +** Read a single block from the %_segments table. If the specified block
          211  +** does not exist, return SQLITE_CORRUPT. If some other error (malloc, IO 
          212  +** etc.) occurs, return the appropriate SQLite error code.
          213  +**
          214  +** Otherwise, if successful, set *pzBlock to point to a buffer containing
          215  +** the block read from the database, and *pnBlock to the size of the read
          216  +** block in bytes.
          217  +**
          218  +** WARNING: The returned buffer is only valid until the next call to 
          219  +** sqlite3Fts3ReadBlock().
          220  +*/
          221  +int sqlite3Fts3ReadBlock(
          222  +  Fts3Table *p,
          223  +  sqlite3_int64 iBlock,
          224  +  char const **pzBlock,
          225  +  int *pnBlock
          226  +){
          227  +  sqlite3_stmt *pStmt;
          228  +  int rc = fts3SqlStmt(p, SQL_GET_BLOCK, &pStmt, 0);
          229  +  if( rc!=SQLITE_OK ) return rc;
          230  +  sqlite3_reset(pStmt);
          231  +
          232  +  sqlite3_bind_int64(pStmt, 1, iBlock);
          233  +  rc = sqlite3_step(pStmt); 
          234  +  if( rc!=SQLITE_ROW ){
          235  +    return SQLITE_CORRUPT;
          236  +  }
          237  +
          238  +  *pnBlock = sqlite3_column_bytes(pStmt, 0);
          239  +  *pzBlock = (char *)sqlite3_column_blob(pStmt, 0);
          240  +  if( !*pzBlock ){
          241  +    return SQLITE_NOMEM;
          242  +  }
          243  +  return SQLITE_OK;
   212    244   }
          245  +
          246  +/*
          247  +** Set *ppStmt to a statement handle that may be used to iterate through
          248  +** all rows in the %_segdir table, from oldest to newest. If successful,
          249  +** return SQLITE_OK. If an error occurs while preparing the statement, 
          250  +** return an SQLite error code.
          251  +**
          252  +** There is only ever one instance of this SQL statement compiled for
          253  +** each FTS3 table.
          254  +*/
          255  +int sqlite3Fts3AllSegdirs(Fts3Table *p, sqlite3_stmt **ppStmt){
          256  +  return fts3SqlStmt(p, SQL_SELECT_ALL_LEVEL, ppStmt, 0);
          257  +}
          258  +
   213    259   
   214    260   static int fts3SqlExec(Fts3Table *p, int eStmt, sqlite3_value **apVal){
   215    261     sqlite3_stmt *pStmt;
   216    262     int rc = fts3SqlStmt(p, eStmt, &pStmt, apVal); 
   217    263     if( rc==SQLITE_OK ){
   218    264       sqlite3_step(pStmt);
   219    265       rc = sqlite3_reset(pStmt);
................................................................................
  1187   1233         sqlite3_free(p->zMalloc);
  1188   1234         sqlite3_free(p);
  1189   1235         p = pRight;
  1190   1236       }
  1191   1237     }
  1192   1238   }
  1193   1239   
  1194         -static int fts3LeafAdd(
         1240  +static int fts3SegWriterAdd(
  1195   1241     Fts3Table *p,                   /* Virtual table handle */
  1196   1242     SegmentWriter **ppWriter,       /* IN/OUT: SegmentWriter handle */ 
  1197   1243     int isCopyTerm,                 /* True if buffer zTerm must be copied */
  1198   1244     const char *zTerm,              /* Pointer to buffer containing term */
  1199   1245     int nTerm,                      /* Size of term in bytes */
  1200   1246     const char *aDoclist,           /* Pointer to buffer containing doclist */
  1201   1247     int nDoclist                    /* Size of doclist in bytes */
................................................................................
  1319   1365       pWriter->zTerm = (char *)zTerm;
  1320   1366     }
  1321   1367     pWriter->nTerm = nTerm;
  1322   1368   
  1323   1369     return SQLITE_OK;
  1324   1370   }
  1325   1371   
  1326         -static int fts3LeafWrite(
         1372  +static int fts3SegWriterFlush(
  1327   1373     Fts3Table *p, 
  1328   1374     SegmentWriter *pWriter,
  1329   1375     int iLevel,
  1330   1376     int iIdx
  1331   1377   ){
  1332   1378     int rc;
  1333   1379     if( pWriter->pTree ){
................................................................................
  1348   1394       /* The entire tree fits on the root node. Write it to the segdir table. */
  1349   1395       rc = fts3WriteSegdir(
  1350   1396           p, iLevel, iIdx, 0, 0, 0, pWriter->aData, pWriter->nData);
  1351   1397     }
  1352   1398     return rc;
  1353   1399   }
  1354   1400   
  1355         -static void fts3LeafFree(SegmentWriter *pWriter){
         1401  +static void fts3SegWriterFree(SegmentWriter *pWriter){
  1356   1402     if( pWriter ){
  1357   1403       sqlite3_free(pWriter->aData);
  1358   1404       sqlite3_free(pWriter->zMalloc);
  1359   1405       fts3NodeFree(pWriter->pTree);
  1360   1406       sqlite3_free(pWriter);
  1361   1407     }
  1362   1408   }
................................................................................
  1484   1530     void *pContext,
  1485   1531     char *zTerm,
  1486   1532     int nTerm,
  1487   1533     char *aDoclist,
  1488   1534     int nDoclist
  1489   1535   ){
  1490   1536     SegmentWriter **ppW = (SegmentWriter **)pContext;
  1491         -  return fts3LeafAdd(p, ppW, 1, zTerm, nTerm, aDoclist, nDoclist);
         1537  +  return fts3SegWriterAdd(p, ppW, 1, zTerm, nTerm, aDoclist, nDoclist);
  1492   1538   }
  1493   1539   
  1494   1540   int sqlite3Fts3SegReaderIterate(
  1495   1541     Fts3Table *p,                   /* Virtual table handle */
  1496   1542     Fts3SegReader **apSegment,      /* Array of Fts3SegReader objects */
  1497   1543     int nSegment,                   /* Size of apSegment array */
  1498   1544     Fts3SegFilter *pFilter,         /* Restrictions on range of iteration */
................................................................................
  1513   1559     ** for, then advance each segment iterator until it points to a term of
  1514   1560     ** equal or greater value than the specified term. This prevents many
  1515   1561     ** unnecessary merge/sort operations for the case where single segment
  1516   1562     ** b-tree leaf nodes contain more than one term.
  1517   1563     */
  1518   1564     if( pFilter->zTerm ){
  1519   1565       int nTerm = pFilter->nTerm;
  1520         -    char *zTerm = pFilter->zTerm;
         1566  +    const char *zTerm = pFilter->zTerm;
  1521   1567       for(i=0; i<nSegment; i++){
  1522   1568         Fts3SegReader *pSeg = apSegment[i];
  1523   1569         while( fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 ){
  1524   1570           rc = fts3SegReaderNext(pSeg);
  1525   1571           if( rc!=SQLITE_OK ) goto finished;
  1526   1572         }
  1527   1573       }
................................................................................
  1722   1768     rc = sqlite3Fts3SegReaderIterate(p, apSegment, nSegment,
  1723   1769         &filter, fts3MergeCallback, (void *)&pWriter
  1724   1770     );
  1725   1771     if( rc!=SQLITE_OK ) goto finished;
  1726   1772   
  1727   1773     rc = fts3DeleteSegdir(p, iLevel, apSegment, nSegment);
  1728   1774     if( rc==SQLITE_OK ){
  1729         -    rc = fts3LeafWrite(p, pWriter, iNewLevel, iIdx);
         1775  +    rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx);
  1730   1776     }
  1731   1777   
  1732   1778    finished:
  1733         -  fts3LeafFree(pWriter);
         1779  +  fts3SegWriterFree(pWriter);
  1734   1780     if( apSegment ){
  1735   1781       for(i=0; i<nSegment; i++){
  1736   1782         sqlite3Fts3SegReaderFree(apSegment[i]);
  1737   1783       }
  1738   1784       sqlite3_free(apSegment);
  1739   1785     }
  1740   1786     sqlite3_reset(pStmt);
  1741   1787     return rc;
  1742   1788   }
         1789  +
         1790  +/*
         1791  +** This is a comparison function used as a qsort() callback when sorting
         1792  +** an array of pending terms by term. This occurs as part of flushing
         1793  +** the contents of the pending-terms hash table to the database.
         1794  +*/
         1795  +static int qsortCompare(const void *lhs, const void *rhs){
         1796  +  char *z1 = fts3HashKey(*(Fts3HashElem **)lhs);
         1797  +  char *z2 = fts3HashKey(*(Fts3HashElem **)rhs);
         1798  +  int n1 = fts3HashKeysize(*(Fts3HashElem **)lhs);
         1799  +  int n2 = fts3HashKeysize(*(Fts3HashElem **)rhs);
         1800  +
         1801  +  int n = (n1<n2 ? n1 : n2);
         1802  +  int c = memcmp(z1, z2, n);
         1803  +  if( c==0 ){
         1804  +    c = n1 - n2;
         1805  +  }
         1806  +  return c;
         1807  +}
         1808  +
  1743   1809   
  1744   1810   /* 
  1745   1811   ** Flush the contents of pendingTerms to a level 0 segment.
  1746   1812   */
  1747   1813   int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
  1748   1814     Fts3HashElem *pElem;
  1749   1815     int idx, rc, i;
................................................................................
  1787   1853   
  1788   1854   
  1789   1855     /* Write the segment tree into the database. */
  1790   1856     for(i=0; rc==SQLITE_OK && i<nElem; i++){
  1791   1857       const char *z = fts3HashKey(apElem[i]);
  1792   1858       int n = fts3HashKeysize(apElem[i]);
  1793   1859       PendingList *pList = fts3HashData(apElem[i]);
  1794         -    rc = fts3LeafAdd(p, &pWriter, 0, z, n, pList->aData, pList->nData+1);
         1860  +    rc = fts3SegWriterAdd(p, &pWriter, 0, z, n, pList->aData, pList->nData+1);
  1795   1861     }
  1796   1862     if( rc==SQLITE_OK ){
  1797         -    rc = fts3LeafWrite(p, pWriter, 0, idx);
         1863  +    rc = fts3SegWriterFlush(p, pWriter, 0, idx);
  1798   1864     }
  1799   1865   
  1800   1866     /* Free all allocated resources before returning */
  1801         -  fts3LeafFree(pWriter);
         1867  +  fts3SegWriterFree(pWriter);
  1802   1868     sqlite3_free(apElem);
  1803   1869     sqlite3Fts3PendingTermsClear(p);
  1804   1870     return rc;
  1805   1871   }
  1806   1872   
  1807   1873   /*
  1808   1874   ** This function does the work for the xUpdate method of FTS3 virtual