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 |