| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2 ** 2014 May 31 | 2 ** 2014 May 31 | 
| 3 ** | 3 ** | 
| 4 ** The author disclaims copyright to this source code.  In place of | 4 ** The author disclaims copyright to this source code.  In place of | 
| 5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: | 
| 6 ** | 6 ** | 
| 7 **    May you do good and not evil. | 7 **    May you do good and not evil. | 
| 8 **    May you find forgiveness for yourself and forgive others. | 8 **    May you find forgiveness for yourself and forgive others. | 
| 9 **    May you share freely, never taking more than you give. | 9 **    May you share freely, never taking more than you give. | 
| 10 ** | 10 ** | 
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 138     }else{ | 138     }else{ | 
| 139       rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0); | 139       rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0); | 
| 140       sqlite3_free(zSql); | 140       sqlite3_free(zSql); | 
| 141       if( rc!=SQLITE_OK && pzErrMsg ){ | 141       if( rc!=SQLITE_OK && pzErrMsg ){ | 
| 142         *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); | 142         *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); | 
| 143       } | 143       } | 
| 144     } | 144     } | 
| 145   } | 145   } | 
| 146 | 146 | 
| 147   *ppStmt = p->aStmt[eStmt]; | 147   *ppStmt = p->aStmt[eStmt]; | 
|  | 148   sqlite3_reset(*ppStmt); | 
| 148   return rc; | 149   return rc; | 
| 149 } | 150 } | 
| 150 | 151 | 
| 151 | 152 | 
| 152 static int fts5ExecPrintf( | 153 static int fts5ExecPrintf( | 
| 153   sqlite3 *db, | 154   sqlite3 *db, | 
| 154   char **pzErr, | 155   char **pzErr, | 
| 155   const char *zFormat, | 156   const char *zFormat, | 
| 156   ... | 157   ... | 
| 157 ){ | 158 ){ | 
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 239   Fts5Config *pConfig,            /* FTS5 configuration */ | 240   Fts5Config *pConfig,            /* FTS5 configuration */ | 
| 240   const char *zPost,              /* Shadow table to create (e.g. "content") */ | 241   const char *zPost,              /* Shadow table to create (e.g. "content") */ | 
| 241   const char *zDefn,              /* Columns etc. for shadow table */ | 242   const char *zDefn,              /* Columns etc. for shadow table */ | 
| 242   int bWithout,                   /* True for without rowid */ | 243   int bWithout,                   /* True for without rowid */ | 
| 243   char **pzErr                    /* OUT: Error message */ | 244   char **pzErr                    /* OUT: Error message */ | 
| 244 ){ | 245 ){ | 
| 245   int rc; | 246   int rc; | 
| 246   char *zErr = 0; | 247   char *zErr = 0; | 
| 247 | 248 | 
| 248   rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s", | 249   rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s", | 
| 249       pConfig->zDb, pConfig->zName, zPost, zDefn, bWithout?" WITHOUT ROWID":"" | 250       pConfig->zDb, pConfig->zName, zPost, zDefn, | 
|  | 251 #ifndef SQLITE_FTS5_NO_WITHOUT_ROWID | 
|  | 252       bWithout?" WITHOUT ROWID": | 
|  | 253 #endif | 
|  | 254       "" | 
| 250   ); | 255   ); | 
| 251   if( zErr ){ | 256   if( zErr ){ | 
| 252     *pzErr = sqlite3_mprintf( | 257     *pzErr = sqlite3_mprintf( | 
| 253         "fts5: error creating shadow table %q_%s: %s", | 258         "fts5: error creating shadow table %q_%s: %s", | 
| 254         pConfig->zName, zPost, zErr | 259         pConfig->zName, zPost, zErr | 
| 255     ); | 260     ); | 
| 256     sqlite3_free(zErr); | 261     sqlite3_free(zErr); | 
| 257   } | 262   } | 
| 258 | 263 | 
| 259   return rc; | 264   return rc; | 
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 331 | 336 | 
| 332 /* | 337 /* | 
| 333 ** Close a handle opened by an earlier call to sqlite3Fts5StorageOpen(). | 338 ** Close a handle opened by an earlier call to sqlite3Fts5StorageOpen(). | 
| 334 */ | 339 */ | 
| 335 int sqlite3Fts5StorageClose(Fts5Storage *p){ | 340 int sqlite3Fts5StorageClose(Fts5Storage *p){ | 
| 336   int rc = SQLITE_OK; | 341   int rc = SQLITE_OK; | 
| 337   if( p ){ | 342   if( p ){ | 
| 338     int i; | 343     int i; | 
| 339 | 344 | 
| 340     /* Finalize all SQL statements */ | 345     /* Finalize all SQL statements */ | 
| 341     for(i=0; i<(int)ArraySize(p->aStmt); i++){ | 346     for(i=0; i<ArraySize(p->aStmt); i++){ | 
| 342       sqlite3_finalize(p->aStmt[i]); | 347       sqlite3_finalize(p->aStmt[i]); | 
| 343     } | 348     } | 
| 344 | 349 | 
| 345     sqlite3_free(p); | 350     sqlite3_free(p); | 
| 346   } | 351   } | 
| 347   return rc; | 352   return rc; | 
| 348 } | 353 } | 
| 349 | 354 | 
| 350 typedef struct Fts5InsertCtx Fts5InsertCtx; | 355 typedef struct Fts5InsertCtx Fts5InsertCtx; | 
| 351 struct Fts5InsertCtx { | 356 struct Fts5InsertCtx { | 
| 352   Fts5Storage *pStorage; | 357   Fts5Storage *pStorage; | 
| 353   int iCol; | 358   int iCol; | 
| 354   int szCol;                      /* Size of column value in tokens */ | 359   int szCol;                      /* Size of column value in tokens */ | 
| 355 }; | 360 }; | 
| 356 | 361 | 
| 357 /* | 362 /* | 
| 358 ** Tokenization callback used when inserting tokens into the FTS index. | 363 ** Tokenization callback used when inserting tokens into the FTS index. | 
| 359 */ | 364 */ | 
| 360 static int fts5StorageInsertCallback( | 365 static int fts5StorageInsertCallback( | 
| 361   void *pContext,                 /* Pointer to Fts5InsertCtx object */ | 366   void *pContext,                 /* Pointer to Fts5InsertCtx object */ | 
| 362   int tflags, | 367   int tflags, | 
| 363   const char *pToken,             /* Buffer containing token */ | 368   const char *pToken,             /* Buffer containing token */ | 
| 364   int nToken,                     /* Size of token in bytes */ | 369   int nToken,                     /* Size of token in bytes */ | 
| 365   int iStart,                     /* Start offset of token */ | 370   int iUnused1,                   /* Start offset of token */ | 
| 366   int iEnd                        /* End offset of token */ | 371   int iUnused2                    /* End offset of token */ | 
| 367 ){ | 372 ){ | 
| 368   Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext; | 373   Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext; | 
| 369   Fts5Index *pIdx = pCtx->pStorage->pIndex; | 374   Fts5Index *pIdx = pCtx->pStorage->pIndex; | 
|  | 375   UNUSED_PARAM2(iUnused1, iUnused2); | 
|  | 376   if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; | 
| 370   if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ | 377   if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ | 
| 371     pCtx->szCol++; | 378     pCtx->szCol++; | 
| 372   } | 379   } | 
| 373   return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken); | 380   return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken); | 
| 374 } | 381 } | 
| 375 | 382 | 
| 376 /* | 383 /* | 
| 377 ** If a row with rowid iDel is present in the %_content table, add the | 384 ** If a row with rowid iDel is present in the %_content table, add the | 
| 378 ** delete-markers to the FTS index necessary to delete it. Do not actually | 385 ** delete-markers to the FTS index necessary to delete it. Do not actually | 
| 379 ** remove the %_content row at this time though. | 386 ** remove the %_content row at this time though. | 
| 380 */ | 387 */ | 
| 381 static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){ | 388 static int fts5StorageDeleteFromIndex( | 
|  | 389   Fts5Storage *p, | 
|  | 390   i64 iDel, | 
|  | 391   sqlite3_value **apVal | 
|  | 392 ){ | 
| 382   Fts5Config *pConfig = p->pConfig; | 393   Fts5Config *pConfig = p->pConfig; | 
| 383   sqlite3_stmt *pSeek;            /* SELECT to read row iDel from %_data */ | 394   sqlite3_stmt *pSeek = 0;        /* SELECT to read row iDel from %_data */ | 
| 384   int rc;                         /* Return code */ | 395   int rc;                         /* Return code */ | 
|  | 396   int rc2;                        /* sqlite3_reset() return code */ | 
|  | 397   int iCol; | 
|  | 398   Fts5InsertCtx ctx; | 
| 385 | 399 | 
| 386   rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0); | 400   if( apVal==0 ){ | 
| 387   if( rc==SQLITE_OK ){ | 401     rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0); | 
| 388     int rc2; | 402     if( rc!=SQLITE_OK ) return rc; | 
| 389     sqlite3_bind_int64(pSeek, 1, iDel); | 403     sqlite3_bind_int64(pSeek, 1, iDel); | 
| 390     if( sqlite3_step(pSeek)==SQLITE_ROW ){ | 404     if( sqlite3_step(pSeek)!=SQLITE_ROW ){ | 
| 391       int iCol; | 405       return sqlite3_reset(pSeek); | 
| 392       Fts5InsertCtx ctx; |  | 
| 393       ctx.pStorage = p; |  | 
| 394       ctx.iCol = -1; |  | 
| 395       rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); |  | 
| 396       for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ |  | 
| 397         if( pConfig->abUnindexed[iCol-1] ) continue; |  | 
| 398         ctx.szCol = 0; |  | 
| 399         rc = sqlite3Fts5Tokenize(pConfig, |  | 
| 400             FTS5_TOKENIZE_DOCUMENT, |  | 
| 401             (const char*)sqlite3_column_text(pSeek, iCol), |  | 
| 402             sqlite3_column_bytes(pSeek, iCol), |  | 
| 403             (void*)&ctx, |  | 
| 404             fts5StorageInsertCallback |  | 
| 405         ); |  | 
| 406         p->aTotalSize[iCol-1] -= (i64)ctx.szCol; |  | 
| 407       } |  | 
| 408       p->nTotalRow--; |  | 
| 409     } | 406     } | 
| 410     rc2 = sqlite3_reset(pSeek); |  | 
| 411     if( rc==SQLITE_OK ) rc = rc2; |  | 
| 412   } | 407   } | 
| 413 | 408 | 
|  | 409   ctx.pStorage = p; | 
|  | 410   ctx.iCol = -1; | 
|  | 411   rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); | 
|  | 412   for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ | 
|  | 413     if( pConfig->abUnindexed[iCol-1]==0 ){ | 
|  | 414       const char *zText; | 
|  | 415       int nText; | 
|  | 416       if( pSeek ){ | 
|  | 417         zText = (const char*)sqlite3_column_text(pSeek, iCol); | 
|  | 418         nText = sqlite3_column_bytes(pSeek, iCol); | 
|  | 419       }else{ | 
|  | 420         zText = (const char*)sqlite3_value_text(apVal[iCol-1]); | 
|  | 421         nText = sqlite3_value_bytes(apVal[iCol-1]); | 
|  | 422       } | 
|  | 423       ctx.szCol = 0; | 
|  | 424       rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, | 
|  | 425           zText, nText, (void*)&ctx, fts5StorageInsertCallback | 
|  | 426       ); | 
|  | 427       p->aTotalSize[iCol-1] -= (i64)ctx.szCol; | 
|  | 428     } | 
|  | 429   } | 
|  | 430   p->nTotalRow--; | 
|  | 431 | 
|  | 432   rc2 = sqlite3_reset(pSeek); | 
|  | 433   if( rc==SQLITE_OK ) rc = rc2; | 
| 414   return rc; | 434   return rc; | 
| 415 } | 435 } | 
| 416 | 436 | 
| 417 | 437 | 
| 418 /* | 438 /* | 
| 419 ** Insert a record into the %_docsize table. Specifically, do: | 439 ** Insert a record into the %_docsize table. Specifically, do: | 
| 420 ** | 440 ** | 
| 421 **   INSERT OR REPLACE INTO %_docsize(id, sz) VALUES(iRowid, pBuf); | 441 **   INSERT OR REPLACE INTO %_docsize(id, sz) VALUES(iRowid, pBuf); | 
| 422 ** | 442 ** | 
| 423 ** If there is no %_docsize table (as happens if the columnsize=0 option | 443 ** If there is no %_docsize table (as happens if the columnsize=0 option | 
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 483     rc = sqlite3Fts5IndexSetAverages(p->pIndex, buf.p, buf.n); | 503     rc = sqlite3Fts5IndexSetAverages(p->pIndex, buf.p, buf.n); | 
| 484   } | 504   } | 
| 485   sqlite3_free(buf.p); | 505   sqlite3_free(buf.p); | 
| 486 | 506 | 
| 487   return rc; | 507   return rc; | 
| 488 } | 508 } | 
| 489 | 509 | 
| 490 /* | 510 /* | 
| 491 ** Remove a row from the FTS table. | 511 ** Remove a row from the FTS table. | 
| 492 */ | 512 */ | 
| 493 int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){ | 513 int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){ | 
| 494   Fts5Config *pConfig = p->pConfig; | 514   Fts5Config *pConfig = p->pConfig; | 
| 495   int rc; | 515   int rc; | 
| 496   sqlite3_stmt *pDel = 0; | 516   sqlite3_stmt *pDel = 0; | 
| 497 | 517 | 
|  | 518   assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 ); | 
| 498   rc = fts5StorageLoadTotals(p, 1); | 519   rc = fts5StorageLoadTotals(p, 1); | 
| 499 | 520 | 
| 500   /* Delete the index records */ | 521   /* Delete the index records */ | 
| 501   if( rc==SQLITE_OK ){ | 522   if( rc==SQLITE_OK ){ | 
| 502     rc = fts5StorageDeleteFromIndex(p, iDel); | 523     rc = fts5StorageDeleteFromIndex(p, iDel, apVal); | 
| 503   } | 524   } | 
| 504 | 525 | 
| 505   /* Delete the %_docsize record */ | 526   /* Delete the %_docsize record */ | 
| 506   if( rc==SQLITE_OK && pConfig->bColumnsize ){ | 527   if( rc==SQLITE_OK && pConfig->bColumnsize ){ | 
| 507     rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0); | 528     rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0); | 
| 508     if( rc==SQLITE_OK ){ | 529     if( rc==SQLITE_OK ){ | 
| 509       sqlite3_bind_int64(pDel, 1, iDel); | 530       sqlite3_bind_int64(pDel, 1, iDel); | 
| 510       sqlite3_step(pDel); | 531       sqlite3_step(pDel); | 
| 511       rc = sqlite3_reset(pDel); | 532       rc = sqlite3_reset(pDel); | 
| 512     } | 533     } | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 525   } | 546   } | 
| 526 | 547 | 
| 527   /* Write the averages record */ | 548   /* Write the averages record */ | 
| 528   if( rc==SQLITE_OK ){ | 549   if( rc==SQLITE_OK ){ | 
| 529     rc = fts5StorageSaveTotals(p); | 550     rc = fts5StorageSaveTotals(p); | 
| 530   } | 551   } | 
| 531 | 552 | 
| 532   return rc; | 553   return rc; | 
| 533 } | 554 } | 
| 534 | 555 | 
| 535 int sqlite3Fts5StorageSpecialDelete( |  | 
| 536   Fts5Storage *p, |  | 
| 537   i64 iDel, |  | 
| 538   sqlite3_value **apVal |  | 
| 539 ){ |  | 
| 540   Fts5Config *pConfig = p->pConfig; |  | 
| 541   int rc; |  | 
| 542   sqlite3_stmt *pDel = 0; |  | 
| 543 |  | 
| 544   assert( pConfig->eContent!=FTS5_CONTENT_NORMAL ); |  | 
| 545   rc = fts5StorageLoadTotals(p, 1); |  | 
| 546 |  | 
| 547   /* Delete the index records */ |  | 
| 548   if( rc==SQLITE_OK ){ |  | 
| 549     int iCol; |  | 
| 550     Fts5InsertCtx ctx; |  | 
| 551     ctx.pStorage = p; |  | 
| 552     ctx.iCol = -1; |  | 
| 553 |  | 
| 554     rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); |  | 
| 555     for(iCol=0; rc==SQLITE_OK && iCol<pConfig->nCol; iCol++){ |  | 
| 556       if( pConfig->abUnindexed[iCol] ) continue; |  | 
| 557       ctx.szCol = 0; |  | 
| 558       rc = sqlite3Fts5Tokenize(pConfig, |  | 
| 559         FTS5_TOKENIZE_DOCUMENT, |  | 
| 560         (const char*)sqlite3_value_text(apVal[iCol]), |  | 
| 561         sqlite3_value_bytes(apVal[iCol]), |  | 
| 562         (void*)&ctx, |  | 
| 563         fts5StorageInsertCallback |  | 
| 564       ); |  | 
| 565       p->aTotalSize[iCol] -= (i64)ctx.szCol; |  | 
| 566     } |  | 
| 567     p->nTotalRow--; |  | 
| 568   } |  | 
| 569 |  | 
| 570   /* Delete the %_docsize record */ |  | 
| 571   if( pConfig->bColumnsize ){ |  | 
| 572     if( rc==SQLITE_OK ){ |  | 
| 573       rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0); |  | 
| 574     } |  | 
| 575     if( rc==SQLITE_OK ){ |  | 
| 576       sqlite3_bind_int64(pDel, 1, iDel); |  | 
| 577       sqlite3_step(pDel); |  | 
| 578       rc = sqlite3_reset(pDel); |  | 
| 579     } |  | 
| 580   } |  | 
| 581 |  | 
| 582   /* Write the averages record */ |  | 
| 583   if( rc==SQLITE_OK ){ |  | 
| 584     rc = fts5StorageSaveTotals(p); |  | 
| 585   } |  | 
| 586 |  | 
| 587   return rc; |  | 
| 588 } |  | 
| 589 |  | 
| 590 /* | 556 /* | 
| 591 ** Delete all entries in the FTS5 index. | 557 ** Delete all entries in the FTS5 index. | 
| 592 */ | 558 */ | 
| 593 int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){ | 559 int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){ | 
| 594   Fts5Config *pConfig = p->pConfig; | 560   Fts5Config *pConfig = p->pConfig; | 
| 595   int rc; | 561   int rc; | 
| 596 | 562 | 
| 597   /* Delete the contents of the %_data and %_docsize tables. */ | 563   /* Delete the contents of the %_data and %_docsize tables. */ | 
| 598   rc = fts5ExecPrintf(pConfig->db, 0, | 564   rc = fts5ExecPrintf(pConfig->db, 0, | 
| 599       "DELETE FROM %Q.'%q_data';" | 565       "DELETE FROM %Q.'%q_data';" | 
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 672 } | 638 } | 
| 673 | 639 | 
| 674 int sqlite3Fts5StorageOptimize(Fts5Storage *p){ | 640 int sqlite3Fts5StorageOptimize(Fts5Storage *p){ | 
| 675   return sqlite3Fts5IndexOptimize(p->pIndex); | 641   return sqlite3Fts5IndexOptimize(p->pIndex); | 
| 676 } | 642 } | 
| 677 | 643 | 
| 678 int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){ | 644 int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){ | 
| 679   return sqlite3Fts5IndexMerge(p->pIndex, nMerge); | 645   return sqlite3Fts5IndexMerge(p->pIndex, nMerge); | 
| 680 } | 646 } | 
| 681 | 647 | 
|  | 648 int sqlite3Fts5StorageReset(Fts5Storage *p){ | 
|  | 649   return sqlite3Fts5IndexReset(p->pIndex); | 
|  | 650 } | 
|  | 651 | 
| 682 /* | 652 /* | 
| 683 ** Allocate a new rowid. This is used for "external content" tables when | 653 ** Allocate a new rowid. This is used for "external content" tables when | 
| 684 ** a NULL value is inserted into the rowid column. The new rowid is allocated | 654 ** a NULL value is inserted into the rowid column. The new rowid is allocated | 
| 685 ** by inserting a dummy row into the %_docsize table. The dummy will be | 655 ** by inserting a dummy row into the %_docsize table. The dummy will be | 
| 686 ** overwritten later. | 656 ** overwritten later. | 
| 687 ** | 657 ** | 
| 688 ** If the %_docsize table does not exist, SQLITE_MISMATCH is returned. In | 658 ** If the %_docsize table does not exist, SQLITE_MISMATCH is returned. In | 
| 689 ** this case the user is required to provide a rowid explicitly. | 659 ** this case the user is required to provide a rowid explicitly. | 
| 690 */ | 660 */ | 
| 691 static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){ | 661 static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){ | 
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 818 | 788 | 
| 819 /* | 789 /* | 
| 820 ** Context object used by sqlite3Fts5StorageIntegrity(). | 790 ** Context object used by sqlite3Fts5StorageIntegrity(). | 
| 821 */ | 791 */ | 
| 822 typedef struct Fts5IntegrityCtx Fts5IntegrityCtx; | 792 typedef struct Fts5IntegrityCtx Fts5IntegrityCtx; | 
| 823 struct Fts5IntegrityCtx { | 793 struct Fts5IntegrityCtx { | 
| 824   i64 iRowid; | 794   i64 iRowid; | 
| 825   int iCol; | 795   int iCol; | 
| 826   int szCol; | 796   int szCol; | 
| 827   u64 cksum; | 797   u64 cksum; | 
|  | 798   Fts5Termset *pTermset; | 
| 828   Fts5Config *pConfig; | 799   Fts5Config *pConfig; | 
| 829 }; | 800 }; | 
| 830 | 801 | 
|  | 802 | 
| 831 /* | 803 /* | 
| 832 ** Tokenization callback used by integrity check. | 804 ** Tokenization callback used by integrity check. | 
| 833 */ | 805 */ | 
| 834 static int fts5StorageIntegrityCallback( | 806 static int fts5StorageIntegrityCallback( | 
| 835   void *pContext,                 /* Pointer to Fts5InsertCtx object */ | 807   void *pContext,                 /* Pointer to Fts5IntegrityCtx object */ | 
| 836   int tflags, | 808   int tflags, | 
| 837   const char *pToken,             /* Buffer containing token */ | 809   const char *pToken,             /* Buffer containing token */ | 
| 838   int nToken,                     /* Size of token in bytes */ | 810   int nToken,                     /* Size of token in bytes */ | 
| 839   int iStart,                     /* Start offset of token */ | 811   int iUnused1,                   /* Start offset of token */ | 
| 840   int iEnd                        /* End offset of token */ | 812   int iUnused2                    /* End offset of token */ | 
| 841 ){ | 813 ){ | 
| 842   Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext; | 814   Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext; | 
|  | 815   Fts5Termset *pTermset = pCtx->pTermset; | 
|  | 816   int bPresent; | 
|  | 817   int ii; | 
|  | 818   int rc = SQLITE_OK; | 
|  | 819   int iPos; | 
|  | 820   int iCol; | 
|  | 821 | 
|  | 822   UNUSED_PARAM2(iUnused1, iUnused2); | 
|  | 823   if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; | 
|  | 824 | 
| 843   if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ | 825   if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ | 
| 844     pCtx->szCol++; | 826     pCtx->szCol++; | 
| 845   } | 827   } | 
| 846   pCtx->cksum ^= sqlite3Fts5IndexCksum( | 828 | 
| 847       pCtx->pConfig, pCtx->iRowid, pCtx->iCol, pCtx->szCol-1, pToken, nToken | 829   switch( pCtx->pConfig->eDetail ){ | 
| 848   ); | 830     case FTS5_DETAIL_FULL: | 
| 849   return SQLITE_OK; | 831       iPos = pCtx->szCol-1; | 
|  | 832       iCol = pCtx->iCol; | 
|  | 833       break; | 
|  | 834 | 
|  | 835     case FTS5_DETAIL_COLUMNS: | 
|  | 836       iPos = pCtx->iCol; | 
|  | 837       iCol = 0; | 
|  | 838       break; | 
|  | 839 | 
|  | 840     default: | 
|  | 841       assert( pCtx->pConfig->eDetail==FTS5_DETAIL_NONE ); | 
|  | 842       iPos = 0; | 
|  | 843       iCol = 0; | 
|  | 844       break; | 
|  | 845   } | 
|  | 846 | 
|  | 847   rc = sqlite3Fts5TermsetAdd(pTermset, 0, pToken, nToken, &bPresent); | 
|  | 848   if( rc==SQLITE_OK && bPresent==0 ){ | 
|  | 849     pCtx->cksum ^= sqlite3Fts5IndexEntryCksum( | 
|  | 850         pCtx->iRowid, iCol, iPos, 0, pToken, nToken | 
|  | 851     ); | 
|  | 852   } | 
|  | 853 | 
|  | 854   for(ii=0; rc==SQLITE_OK && ii<pCtx->pConfig->nPrefix; ii++){ | 
|  | 855     const int nChar = pCtx->pConfig->aPrefix[ii]; | 
|  | 856     int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar); | 
|  | 857     if( nByte ){ | 
|  | 858       rc = sqlite3Fts5TermsetAdd(pTermset, ii+1, pToken, nByte, &bPresent); | 
|  | 859       if( bPresent==0 ){ | 
|  | 860         pCtx->cksum ^= sqlite3Fts5IndexEntryCksum( | 
|  | 861             pCtx->iRowid, iCol, iPos, ii+1, pToken, nByte | 
|  | 862         ); | 
|  | 863       } | 
|  | 864     } | 
|  | 865   } | 
|  | 866 | 
|  | 867   return rc; | 
| 850 } | 868 } | 
| 851 | 869 | 
| 852 /* | 870 /* | 
| 853 ** Check that the contents of the FTS index match that of the %_content | 871 ** Check that the contents of the FTS index match that of the %_content | 
| 854 ** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return | 872 ** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return | 
| 855 ** some other SQLite error code if an error occurs while attempting to | 873 ** some other SQLite error code if an error occurs while attempting to | 
| 856 ** determine this. | 874 ** determine this. | 
| 857 */ | 875 */ | 
| 858 int sqlite3Fts5StorageIntegrity(Fts5Storage *p){ | 876 int sqlite3Fts5StorageIntegrity(Fts5Storage *p){ | 
| 859   Fts5Config *pConfig = p->pConfig; | 877   Fts5Config *pConfig = p->pConfig; | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
| 875   rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); | 893   rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); | 
| 876   if( rc==SQLITE_OK ){ | 894   if( rc==SQLITE_OK ){ | 
| 877     int rc2; | 895     int rc2; | 
| 878     while( SQLITE_ROW==sqlite3_step(pScan) ){ | 896     while( SQLITE_ROW==sqlite3_step(pScan) ){ | 
| 879       int i; | 897       int i; | 
| 880       ctx.iRowid = sqlite3_column_int64(pScan, 0); | 898       ctx.iRowid = sqlite3_column_int64(pScan, 0); | 
| 881       ctx.szCol = 0; | 899       ctx.szCol = 0; | 
| 882       if( pConfig->bColumnsize ){ | 900       if( pConfig->bColumnsize ){ | 
| 883         rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize); | 901         rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize); | 
| 884       } | 902       } | 
|  | 903       if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){ | 
|  | 904         rc = sqlite3Fts5TermsetNew(&ctx.pTermset); | 
|  | 905       } | 
| 885       for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){ | 906       for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){ | 
| 886         if( pConfig->abUnindexed[i] ) continue; | 907         if( pConfig->abUnindexed[i] ) continue; | 
| 887         ctx.iCol = i; | 908         ctx.iCol = i; | 
| 888         ctx.szCol = 0; | 909         ctx.szCol = 0; | 
| 889         rc = sqlite3Fts5Tokenize(pConfig, | 910         if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ | 
| 890             FTS5_TOKENIZE_DOCUMENT, | 911           rc = sqlite3Fts5TermsetNew(&ctx.pTermset); | 
| 891             (const char*)sqlite3_column_text(pScan, i+1), | 912         } | 
| 892             sqlite3_column_bytes(pScan, i+1), | 913         if( rc==SQLITE_OK ){ | 
| 893             (void*)&ctx, | 914           rc = sqlite3Fts5Tokenize(pConfig, | 
| 894             fts5StorageIntegrityCallback | 915               FTS5_TOKENIZE_DOCUMENT, | 
| 895         ); | 916               (const char*)sqlite3_column_text(pScan, i+1), | 
| 896         if( pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ | 917               sqlite3_column_bytes(pScan, i+1), | 
|  | 918               (void*)&ctx, | 
|  | 919               fts5StorageIntegrityCallback | 
|  | 920           ); | 
|  | 921         } | 
|  | 922         if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ | 
| 897           rc = FTS5_CORRUPT; | 923           rc = FTS5_CORRUPT; | 
| 898         } | 924         } | 
| 899         aTotalSize[i] += ctx.szCol; | 925         aTotalSize[i] += ctx.szCol; | 
|  | 926         if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ | 
|  | 927           sqlite3Fts5TermsetFree(ctx.pTermset); | 
|  | 928           ctx.pTermset = 0; | 
|  | 929         } | 
| 900       } | 930       } | 
|  | 931       sqlite3Fts5TermsetFree(ctx.pTermset); | 
|  | 932       ctx.pTermset = 0; | 
|  | 933 | 
| 901       if( rc!=SQLITE_OK ) break; | 934       if( rc!=SQLITE_OK ) break; | 
| 902     } | 935     } | 
| 903     rc2 = sqlite3_reset(pScan); | 936     rc2 = sqlite3_reset(pScan); | 
| 904     if( rc==SQLITE_OK ) rc = rc2; | 937     if( rc==SQLITE_OK ) rc = rc2; | 
| 905   } | 938   } | 
| 906 | 939 | 
| 907   /* Test that the "totals" (sometimes called "averages") record looks Ok */ | 940   /* Test that the "totals" (sometimes called "averages") record looks Ok */ | 
| 908   if( rc==SQLITE_OK ){ | 941   if( rc==SQLITE_OK ){ | 
| 909     int i; | 942     int i; | 
| 910     rc = fts5StorageLoadTotals(p, 0); | 943     rc = fts5StorageLoadTotals(p, 0); | 
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1092   } | 1125   } | 
| 1093   if( rc==SQLITE_OK && pVal ){ | 1126   if( rc==SQLITE_OK && pVal ){ | 
| 1094     int iNew = p->pConfig->iCookie + 1; | 1127     int iNew = p->pConfig->iCookie + 1; | 
| 1095     rc = sqlite3Fts5IndexSetCookie(p->pIndex, iNew); | 1128     rc = sqlite3Fts5IndexSetCookie(p->pIndex, iNew); | 
| 1096     if( rc==SQLITE_OK ){ | 1129     if( rc==SQLITE_OK ){ | 
| 1097       p->pConfig->iCookie = iNew; | 1130       p->pConfig->iCookie = iNew; | 
| 1098     } | 1131     } | 
| 1099   } | 1132   } | 
| 1100   return rc; | 1133   return rc; | 
| 1101 } | 1134 } | 
| 1102 |  | 
| 1103 |  | 
| OLD | NEW | 
|---|