SQLite

Check-in [a3b50e4f80]
Login

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

Overview
Comment:Fix a bug triggered by optimizing an FTS3 table when there are no segments on disk but pending terms in the hash table.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a3b50e4f80ca2dacc1f72435b8c72d55ffdb64e7
User & Date: dan 2009-12-29 10:32:37.000
Context
2009-12-29
23:39
Within the special new.* and old.* tables of a trigger, recognize all the original table names even if those names overload the "rowid", "oid", or "_rowid_" special names. Ticket [34d2ae1c6d0]. (check-in: 1a0e5fa9f0 user: drh tags: trunk)
10:32
Fix a bug triggered by optimizing an FTS3 table when there are no segments on disk but pending terms in the hash table. (check-in: a3b50e4f80 user: dan tags: trunk)
2009-12-24
16:00
Immediately purge entries from the column cache when the associated register undergoes an affinity change. Ticket [eb5548a849]. Enhance the SQLITE_TESTCTRL_OPTIMIZATIONS setting of sqlite3_test_control so that it can disable the column cache for testing purposes, in an effort to prevent future problems of a similar nature to this one. (check-in: ea4e57e1c1 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/fts3/fts3.c.
2046
2047
2048
2049
2050
2051
2052



2053
2054
2055
2056
2057
2058

2059
2060
2061
2062
2063
2064
2065
**
** The first integer in each data is the number of hits that the simple
** query has in the current column.
**
** If the GLOBALCOUNT flag is set, then this is followed by the total
** number of hits the simple query has in the current column of *all*
** selected rows.



**
** If the POSITIONLIST flag is set, then this is followed by <local-count>
** integers - the positions of each of the hits for the current column/query.
*/
#define FTS3_MATCHINFO_GLOBALCOUNT  0x00000001
#define FTS3_MATCHINFO_POSITIONLIST 0x00000002


typedef struct MatchInfo MatchInfo;
struct MatchInfo {
  int rc;                         /* Return code. SQLITE_OK if no error */
  sqlite3_int64 iDocid;           /* Docid of entry to return data for */
  Fts3Table *pTab;                /* FTS3 Virtual table */
  int flags;                      /* Output flags (see above) */







>
>
>






>







2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
**
** The first integer in each data is the number of hits that the simple
** query has in the current column.
**
** If the GLOBALCOUNT flag is set, then this is followed by the total
** number of hits the simple query has in the current column of *all*
** selected rows.
**
** If the PHRASELENGTH flag is set, this is followed by the number of
** tokens in the phrase.
**
** If the POSITIONLIST flag is set, then this is followed by <local-count>
** integers - the positions of each of the hits for the current column/query.
*/
#define FTS3_MATCHINFO_GLOBALCOUNT  0x00000001
#define FTS3_MATCHINFO_POSITIONLIST 0x00000002
#define FTS3_MATCHINFO_PHRASELENGTH 0x00000004

typedef struct MatchInfo MatchInfo;
struct MatchInfo {
  int rc;                         /* Return code. SQLITE_OK if no error */
  sqlite3_int64 iDocid;           /* Docid of entry to return data for */
  Fts3Table *pTab;                /* FTS3 Virtual table */
  int flags;                      /* Output flags (see above) */
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111

2112
2113
2114
2115
2116
2117
2118
  sqlite3_context *pCtx,
  Fts3Expr *pExpr,
  MatchInfo *pInfo
){
  int eType = pExpr->eType;
  if( eType==FTSQUERY_NOT || pInfo->rc ){
    return;
  }else if( eType!=FTSQUERY_PHRASE && eType!=FTSQUERY_NEAR ){
    assert( pExpr->pLeft && pExpr->pRight );
    fts3ExprMatchInfo(pCtx, pExpr->pLeft, pInfo);
    if( pInfo->rc==SQLITE_OK ){
      fts3ExprMatchInfo(pCtx, pExpr->pRight, pInfo);
    }
  }else{

    Fts3Table *pTab = pInfo->pTab;

    /* If it is not loaded already, load the doclist for this simple query
    ** from the FTS3 full-text index. 
    */
    if( pExpr->isLoaded==0 ){
      pInfo->rc = evalFts3Expr(pTab,pExpr,&pExpr->aDoclist,&pExpr->nDoclist,1);







|






>







2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
  sqlite3_context *pCtx,
  Fts3Expr *pExpr,
  MatchInfo *pInfo
){
  int eType = pExpr->eType;
  if( eType==FTSQUERY_NOT || pInfo->rc ){
    return;
  }else if( eType!=FTSQUERY_PHRASE ){
    assert( pExpr->pLeft && pExpr->pRight );
    fts3ExprMatchInfo(pCtx, pExpr->pLeft, pInfo);
    if( pInfo->rc==SQLITE_OK ){
      fts3ExprMatchInfo(pCtx, pExpr->pRight, pInfo);
    }
  }else{
    int nPhrase = pExpr->pPhrase->nToken;
    Fts3Table *pTab = pInfo->pTab;

    /* If it is not loaded already, load the doclist for this simple query
    ** from the FTS3 full-text index. 
    */
    if( pExpr->isLoaded==0 ){
      pInfo->rc = evalFts3Expr(pTab,pExpr,&pExpr->aDoclist,&pExpr->nDoclist,1);
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185




2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
              memset(pExpr->aHist, 0, nByte);

              /* Scan the entire doclist to populate Fts3Expr.aHist[]. */ 
              while( pCsr<pEnd ){
                while( *pCsr++ & 0x80 );
                while( *pCsr ){
                  sqlite3_int64 iCol = 0;
                  if( *pCsr==0x01 ) pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
                  pExpr->aHist[iCol] += fts3ColumnlistCount(&pCsr);
                }
                pCsr++;
              }
            }

            fts3MatchInfoAppend(pInfo, pExpr->aHist[i]);
          }





          if( i==0 ){
            if( *pExpr->pCurrent==0x01 ) continue;
          }else{
            sqlite3_int64 iCol;
            char *pList = pExpr->pCurrent;
            if( *pList==0x00 ) continue;
            pList++;
            pList += sqlite3Fts3GetVarint(pList, &iCol);
            if( iCol!=i ) continue;
            pExpr->pCurrent = pList;
          }

          if( pInfo->flags&FTS3_MATCHINFO_POSITIONLIST ){
            int nLocal = 0;
            sqlite3_int64 iOffset = 0;
            char *pList = pExpr->pCurrent;
            while( *pList&0xFE ){
              fts3GetDeltaVarint(&pList, &iOffset); iOffset -= 2;
              fts3MatchInfoAppend(pInfo, iOffset);
              nLocal++;
            }
            pExpr->pCurrent = pList;
            pInfo->aOut[iLocalOff] = nLocal;
          }else{
            pInfo->aOut[iLocalOff] = fts3ColumnlistCount(&pExpr->pCurrent);
          }







|








>
>
>
>



















|







2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
              memset(pExpr->aHist, 0, nByte);

              /* Scan the entire doclist to populate Fts3Expr.aHist[]. */ 
              while( pCsr<pEnd ){
                while( *pCsr++ & 0x80 );
                while( *pCsr ){
                  sqlite3_int64 iCol = 0;
                  if( *pCsr==0x01 ) pCsr += sqlite3Fts3GetVarint(++pCsr, &iCol);
                  pExpr->aHist[iCol] += fts3ColumnlistCount(&pCsr);
                }
                pCsr++;
              }
            }

            fts3MatchInfoAppend(pInfo, pExpr->aHist[i]);
          }

          if( pInfo->flags&FTS3_MATCHINFO_PHRASELENGTH ){
            fts3MatchInfoAppend(pInfo, nPhrase);
          }

          if( i==0 ){
            if( *pExpr->pCurrent==0x01 ) continue;
          }else{
            sqlite3_int64 iCol;
            char *pList = pExpr->pCurrent;
            if( *pList==0x00 ) continue;
            pList++;
            pList += sqlite3Fts3GetVarint(pList, &iCol);
            if( iCol!=i ) continue;
            pExpr->pCurrent = pList;
          }

          if( pInfo->flags&FTS3_MATCHINFO_POSITIONLIST ){
            int nLocal = 0;
            sqlite3_int64 iOffset = 0;
            char *pList = pExpr->pCurrent;
            while( *pList&0xFE ){
              fts3GetDeltaVarint(&pList, &iOffset); iOffset -= 2;
              fts3MatchInfoAppend(pInfo, iOffset+1-nPhrase);
              nLocal++;
            }
            pExpr->pCurrent = pList;
            pInfo->aOut[iLocalOff] = nLocal;
          }else{
            pInfo->aOut[iLocalOff] = fts3ColumnlistCount(&pExpr->pCurrent);
          }
2363
2364
2365
2366
2367
2368
2369

2370
2371
2372
2373
2374
2375
2376
  if( nVal==2 ){
    int i;
    const unsigned char *zFlags = sqlite3_value_text(apVal[1]);
    for(i=0; zFlags[i]; i++){
      switch( zFlags[i] ){
        case 'g': flags |= FTS3_MATCHINFO_GLOBALCOUNT; break;
        case 'p': flags |= FTS3_MATCHINFO_POSITIONLIST; break;

        default: {
          char zErr[18];
          memcpy(zErr, "Unknown flag: \"%c\"", 18);
          zErr[16] = (char)zFlags[i];
          sqlite3_result_error(pContext, zErr, -1);
          return;
        }







>







2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
  if( nVal==2 ){
    int i;
    const unsigned char *zFlags = sqlite3_value_text(apVal[1]);
    for(i=0; zFlags[i]; i++){
      switch( zFlags[i] ){
        case 'g': flags |= FTS3_MATCHINFO_GLOBALCOUNT; break;
        case 'p': flags |= FTS3_MATCHINFO_POSITIONLIST; break;
        case 'n': flags |= FTS3_MATCHINFO_PHRASELENGTH; break;
        default: {
          char zErr[18];
          memcpy(zErr, "Unknown flag: \"%c\"", 18);
          zErr[16] = (char)zFlags[i];
          sqlite3_result_error(pContext, zErr, -1);
          return;
        }
Changes to ext/fts3/fts3_write.c.
2224
2225
2226
2227
2228
2229
2230
2231
2232

2233
2234
2235
2236
2237
2238
2239
  const char *zVal = (const char *)sqlite3_value_text(pVal);
  int nVal = sqlite3_value_bytes(pVal);

  if( !zVal ){
    return SQLITE_NOMEM;
  }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){
    rc = fts3SegmentMerge(p, -1);
    if( rc==SQLITE_DONE || rc==SQLITE_OK ){
      rc = SQLITE_OK;

      sqlite3Fts3PendingTermsClear(p);
    }
#ifdef SQLITE_TEST
  }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
    p->nNodeSize = atoi(&zVal[9]);
    rc = SQLITE_OK;
  }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){







|

>







2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
  const char *zVal = (const char *)sqlite3_value_text(pVal);
  int nVal = sqlite3_value_bytes(pVal);

  if( !zVal ){
    return SQLITE_NOMEM;
  }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){
    rc = fts3SegmentMerge(p, -1);
    if( rc==SQLITE_DONE ){
      rc = SQLITE_OK;
    }else{
      sqlite3Fts3PendingTermsClear(p);
    }
#ifdef SQLITE_TEST
  }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
    p->nNodeSize = atoi(&zVal[9]);
    rc = SQLITE_OK;
  }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){