| OLD | NEW |
| 1 /* | 1 /* |
| 2 ** 2014 Jun 09 | 2 ** 2014 Jun 09 |
| 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 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 #define FTS5_BI_ROWID_LE 0x0008 /* rowid <= ? */ | 213 #define FTS5_BI_ROWID_LE 0x0008 /* rowid <= ? */ |
| 214 #define FTS5_BI_ROWID_GE 0x0010 /* rowid >= ? */ | 214 #define FTS5_BI_ROWID_GE 0x0010 /* rowid >= ? */ |
| 215 | 215 |
| 216 #define FTS5_BI_ORDER_RANK 0x0020 | 216 #define FTS5_BI_ORDER_RANK 0x0020 |
| 217 #define FTS5_BI_ORDER_ROWID 0x0040 | 217 #define FTS5_BI_ORDER_ROWID 0x0040 |
| 218 #define FTS5_BI_ORDER_DESC 0x0080 | 218 #define FTS5_BI_ORDER_DESC 0x0080 |
| 219 | 219 |
| 220 /* | 220 /* |
| 221 ** Values for Fts5Cursor.csrflags | 221 ** Values for Fts5Cursor.csrflags |
| 222 */ | 222 */ |
| 223 #define FTS5CSR_REQUIRE_CONTENT 0x01 | 223 #define FTS5CSR_EOF 0x01 |
| 224 #define FTS5CSR_REQUIRE_DOCSIZE 0x02 | 224 #define FTS5CSR_REQUIRE_CONTENT 0x02 |
| 225 #define FTS5CSR_REQUIRE_INST 0x04 | 225 #define FTS5CSR_REQUIRE_DOCSIZE 0x04 |
| 226 #define FTS5CSR_EOF 0x08 | 226 #define FTS5CSR_REQUIRE_INST 0x08 |
| 227 #define FTS5CSR_FREE_ZRANK 0x10 | 227 #define FTS5CSR_FREE_ZRANK 0x10 |
| 228 #define FTS5CSR_REQUIRE_RESEEK 0x20 | 228 #define FTS5CSR_REQUIRE_RESEEK 0x20 |
| 229 #define FTS5CSR_REQUIRE_POSLIST 0x40 |
| 229 | 230 |
| 230 #define BitFlagAllTest(x,y) (((x) & (y))==(y)) | 231 #define BitFlagAllTest(x,y) (((x) & (y))==(y)) |
| 231 #define BitFlagTest(x,y) (((x) & (y))!=0) | 232 #define BitFlagTest(x,y) (((x) & (y))!=0) |
| 232 | 233 |
| 233 | 234 |
| 234 /* | 235 /* |
| 235 ** Macros to Set(), Clear() and Test() cursor flags. | 236 ** Macros to Set(), Clear() and Test() cursor flags. |
| 236 */ | 237 */ |
| 237 #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag)) | 238 #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag)) |
| 238 #define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag)) | 239 #define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag)) |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 | 531 |
| 531 int aColMap[3]; | 532 int aColMap[3]; |
| 532 aColMap[0] = -1; | 533 aColMap[0] = -1; |
| 533 aColMap[1] = pConfig->nCol; | 534 aColMap[1] = pConfig->nCol; |
| 534 aColMap[2] = pConfig->nCol+1; | 535 aColMap[2] = pConfig->nCol+1; |
| 535 | 536 |
| 536 /* Set idxFlags flags for all WHERE clause terms that will be used. */ | 537 /* Set idxFlags flags for all WHERE clause terms that will be used. */ |
| 537 for(i=0; i<pInfo->nConstraint; i++){ | 538 for(i=0; i<pInfo->nConstraint; i++){ |
| 538 struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; | 539 struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; |
| 539 int j; | 540 int j; |
| 540 for(j=0; j<(int)ArraySize(aConstraint); j++){ | 541 for(j=0; j<ArraySize(aConstraint); j++){ |
| 541 struct Constraint *pC = &aConstraint[j]; | 542 struct Constraint *pC = &aConstraint[j]; |
| 542 if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){ | 543 if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){ |
| 543 if( p->usable ){ | 544 if( p->usable ){ |
| 544 pC->iConsIndex = i; | 545 pC->iConsIndex = i; |
| 545 idxFlags |= pC->fts5op; | 546 idxFlags |= pC->fts5op; |
| 546 }else if( j==0 ){ | 547 }else if( j==0 ){ |
| 547 /* As there exists an unusable MATCH constraint this is an | 548 /* As there exists an unusable MATCH constraint this is an |
| 548 ** unusable plan. Set a prohibitively high cost. */ | 549 ** unusable plan. Set a prohibitively high cost. */ |
| 549 pInfo->estimatedCost = 1e50; | 550 pInfo->estimatedCost = 1e50; |
| 550 return SQLITE_OK; | 551 return SQLITE_OK; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 577 }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ | 578 }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ |
| 578 pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0; | 579 pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0; |
| 579 }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ | 580 }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ |
| 580 pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0; | 581 pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0; |
| 581 }else{ | 582 }else{ |
| 582 pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0; | 583 pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0; |
| 583 } | 584 } |
| 584 | 585 |
| 585 /* Assign argvIndex values to each constraint in use. */ | 586 /* Assign argvIndex values to each constraint in use. */ |
| 586 iNext = 1; | 587 iNext = 1; |
| 587 for(i=0; i<(int)ArraySize(aConstraint); i++){ | 588 for(i=0; i<ArraySize(aConstraint); i++){ |
| 588 struct Constraint *pC = &aConstraint[i]; | 589 struct Constraint *pC = &aConstraint[i]; |
| 589 if( pC->iConsIndex>=0 ){ | 590 if( pC->iConsIndex>=0 ){ |
| 590 pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++; | 591 pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++; |
| 591 pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit; | 592 pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit; |
| 592 } | 593 } |
| 593 } | 594 } |
| 594 | 595 |
| 595 pInfo->idxNum = idxFlags; | 596 pInfo->idxNum = idxFlags; |
| 596 return SQLITE_OK; | 597 return SQLITE_OK; |
| 597 } | 598 } |
| 598 | 599 |
| 600 static int fts5NewTransaction(Fts5Table *pTab){ |
| 601 Fts5Cursor *pCsr; |
| 602 for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ |
| 603 if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK; |
| 604 } |
| 605 return sqlite3Fts5StorageReset(pTab->pStorage); |
| 606 } |
| 607 |
| 599 /* | 608 /* |
| 600 ** Implementation of xOpen method. | 609 ** Implementation of xOpen method. |
| 601 */ | 610 */ |
| 602 static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ | 611 static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ |
| 603 Fts5Table *pTab = (Fts5Table*)pVTab; | 612 Fts5Table *pTab = (Fts5Table*)pVTab; |
| 604 Fts5Config *pConfig = pTab->pConfig; | 613 Fts5Config *pConfig = pTab->pConfig; |
| 605 Fts5Cursor *pCsr; /* New cursor object */ | 614 Fts5Cursor *pCsr = 0; /* New cursor object */ |
| 606 int nByte; /* Bytes of space to allocate */ | 615 int nByte; /* Bytes of space to allocate */ |
| 607 int rc = SQLITE_OK; /* Return code */ | 616 int rc; /* Return code */ |
| 608 | 617 |
| 609 nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int); | 618 rc = fts5NewTransaction(pTab); |
| 610 pCsr = (Fts5Cursor*)sqlite3_malloc(nByte); | 619 if( rc==SQLITE_OK ){ |
| 611 if( pCsr ){ | 620 nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int); |
| 612 Fts5Global *pGlobal = pTab->pGlobal; | 621 pCsr = (Fts5Cursor*)sqlite3_malloc(nByte); |
| 613 memset(pCsr, 0, nByte); | 622 if( pCsr ){ |
| 614 pCsr->aColumnSize = (int*)&pCsr[1]; | 623 Fts5Global *pGlobal = pTab->pGlobal; |
| 615 pCsr->pNext = pGlobal->pCsr; | 624 memset(pCsr, 0, nByte); |
| 616 pGlobal->pCsr = pCsr; | 625 pCsr->aColumnSize = (int*)&pCsr[1]; |
| 617 pCsr->iCsrId = ++pGlobal->iNextId; | 626 pCsr->pNext = pGlobal->pCsr; |
| 618 }else{ | 627 pGlobal->pCsr = pCsr; |
| 619 rc = SQLITE_NOMEM; | 628 pCsr->iCsrId = ++pGlobal->iNextId; |
| 629 }else{ |
| 630 rc = SQLITE_NOMEM; |
| 631 } |
| 620 } | 632 } |
| 621 *ppCsr = (sqlite3_vtab_cursor*)pCsr; | 633 *ppCsr = (sqlite3_vtab_cursor*)pCsr; |
| 622 return rc; | 634 return rc; |
| 623 } | 635 } |
| 624 | 636 |
| 625 static int fts5StmtType(Fts5Cursor *pCsr){ | 637 static int fts5StmtType(Fts5Cursor *pCsr){ |
| 626 if( pCsr->ePlan==FTS5_PLAN_SCAN ){ | 638 if( pCsr->ePlan==FTS5_PLAN_SCAN ){ |
| 627 return (pCsr->bDesc) ? FTS5_STMT_SCAN_DESC : FTS5_STMT_SCAN_ASC; | 639 return (pCsr->bDesc) ? FTS5_STMT_SCAN_DESC : FTS5_STMT_SCAN_ASC; |
| 628 } | 640 } |
| 629 return FTS5_STMT_LOOKUP; | 641 return FTS5_STMT_LOOKUP; |
| 630 } | 642 } |
| 631 | 643 |
| 632 /* | 644 /* |
| 633 ** This function is called after the cursor passed as the only argument | 645 ** This function is called after the cursor passed as the only argument |
| 634 ** is moved to point at a different row. It clears all cached data | 646 ** is moved to point at a different row. It clears all cached data |
| 635 ** specific to the previous row stored by the cursor object. | 647 ** specific to the previous row stored by the cursor object. |
| 636 */ | 648 */ |
| 637 static void fts5CsrNewrow(Fts5Cursor *pCsr){ | 649 static void fts5CsrNewrow(Fts5Cursor *pCsr){ |
| 638 CsrFlagSet(pCsr, | 650 CsrFlagSet(pCsr, |
| 639 FTS5CSR_REQUIRE_CONTENT | 651 FTS5CSR_REQUIRE_CONTENT |
| 640 | FTS5CSR_REQUIRE_DOCSIZE | 652 | FTS5CSR_REQUIRE_DOCSIZE |
| 641 | FTS5CSR_REQUIRE_INST | 653 | FTS5CSR_REQUIRE_INST |
| 654 | FTS5CSR_REQUIRE_POSLIST |
| 642 ); | 655 ); |
| 643 } | 656 } |
| 644 | 657 |
| 645 static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ | 658 static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ |
| 646 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); | 659 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); |
| 647 Fts5Auxdata *pData; | 660 Fts5Auxdata *pData; |
| 648 Fts5Auxdata *pNext; | 661 Fts5Auxdata *pNext; |
| 649 | 662 |
| 650 sqlite3_free(pCsr->aInstIter); | 663 sqlite3_free(pCsr->aInstIter); |
| 651 sqlite3_free(pCsr->aInst); | 664 sqlite3_free(pCsr->aInst); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 714 const u8 *aBlob; | 727 const u8 *aBlob; |
| 715 int nBlob; | 728 int nBlob; |
| 716 int i; | 729 int i; |
| 717 int iOff = 0; | 730 int iOff = 0; |
| 718 rc = SQLITE_OK; | 731 rc = SQLITE_OK; |
| 719 | 732 |
| 720 pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0); | 733 pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0); |
| 721 nBlob = sqlite3_column_bytes(pSorter->pStmt, 1); | 734 nBlob = sqlite3_column_bytes(pSorter->pStmt, 1); |
| 722 aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1); | 735 aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1); |
| 723 | 736 |
| 724 for(i=0; i<(pSorter->nIdx-1); i++){ | 737 /* nBlob==0 in detail=none mode. */ |
| 725 int iVal; | 738 if( nBlob>0 ){ |
| 726 a += fts5GetVarint32(a, iVal); | 739 for(i=0; i<(pSorter->nIdx-1); i++){ |
| 727 iOff += iVal; | 740 int iVal; |
| 728 pSorter->aIdx[i] = iOff; | 741 a += fts5GetVarint32(a, iVal); |
| 742 iOff += iVal; |
| 743 pSorter->aIdx[i] = iOff; |
| 744 } |
| 745 pSorter->aIdx[i] = &aBlob[nBlob] - a; |
| 746 pSorter->aPoslist = a; |
| 729 } | 747 } |
| 730 pSorter->aIdx[i] = &aBlob[nBlob] - a; | |
| 731 | 748 |
| 732 pSorter->aPoslist = a; | |
| 733 fts5CsrNewrow(pCsr); | 749 fts5CsrNewrow(pCsr); |
| 734 } | 750 } |
| 735 | 751 |
| 736 return rc; | 752 return rc; |
| 737 } | 753 } |
| 738 | 754 |
| 739 | 755 |
| 740 /* | 756 /* |
| 741 ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors | 757 ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors |
| 742 ** open on table pTab. | 758 ** open on table pTab. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 766 */ | 782 */ |
| 767 static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ | 783 static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ |
| 768 int rc = SQLITE_OK; | 784 int rc = SQLITE_OK; |
| 769 assert( *pbSkip==0 ); | 785 assert( *pbSkip==0 ); |
| 770 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){ | 786 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){ |
| 771 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); | 787 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); |
| 772 int bDesc = pCsr->bDesc; | 788 int bDesc = pCsr->bDesc; |
| 773 i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr); | 789 i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr); |
| 774 | 790 |
| 775 rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc); | 791 rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc); |
| 776 if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){ | 792 if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){ |
| 777 *pbSkip = 1; | 793 *pbSkip = 1; |
| 778 } | 794 } |
| 779 | 795 |
| 780 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK); | 796 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK); |
| 781 fts5CsrNewrow(pCsr); | 797 fts5CsrNewrow(pCsr); |
| 782 if( sqlite3Fts5ExprEof(pCsr->pExpr) ){ | 798 if( sqlite3Fts5ExprEof(pCsr->pExpr) ){ |
| 783 CsrFlagSet(pCsr, FTS5CSR_EOF); | 799 CsrFlagSet(pCsr, FTS5CSR_EOF); |
| 800 *pbSkip = 1; |
| 784 } | 801 } |
| 785 } | 802 } |
| 786 return rc; | 803 return rc; |
| 787 } | 804 } |
| 788 | 805 |
| 789 | 806 |
| 790 /* | 807 /* |
| 791 ** Advance the cursor to the next row in the table that matches the | 808 ** Advance the cursor to the next row in the table that matches the |
| 792 ** search criteria. | 809 ** search criteria. |
| 793 ** | 810 ** |
| 794 ** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned | 811 ** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned |
| 795 ** even if we reach end-of-file. The fts5EofMethod() will be called | 812 ** even if we reach end-of-file. The fts5EofMethod() will be called |
| 796 ** subsequently to determine whether or not an EOF was hit. | 813 ** subsequently to determine whether or not an EOF was hit. |
| 797 */ | 814 */ |
| 798 static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){ | 815 static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){ |
| 799 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; | 816 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; |
| 800 int rc = SQLITE_OK; | 817 int rc; |
| 801 | 818 |
| 802 assert( (pCsr->ePlan<3)== | 819 assert( (pCsr->ePlan<3)== |
| 803 (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) | 820 (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) |
| 804 ); | 821 ); |
| 822 assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) ); |
| 805 | 823 |
| 806 if( pCsr->ePlan<3 ){ | 824 if( pCsr->ePlan<3 ){ |
| 807 int bSkip = 0; | 825 int bSkip = 0; |
| 808 if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc; | 826 if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc; |
| 809 rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid); | 827 rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid); |
| 810 if( sqlite3Fts5ExprEof(pCsr->pExpr) ){ | 828 CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr)); |
| 811 CsrFlagSet(pCsr, FTS5CSR_EOF); | |
| 812 } | |
| 813 fts5CsrNewrow(pCsr); | 829 fts5CsrNewrow(pCsr); |
| 814 }else{ | 830 }else{ |
| 815 switch( pCsr->ePlan ){ | 831 switch( pCsr->ePlan ){ |
| 816 case FTS5_PLAN_SPECIAL: { | 832 case FTS5_PLAN_SPECIAL: { |
| 817 CsrFlagSet(pCsr, FTS5CSR_EOF); | 833 CsrFlagSet(pCsr, FTS5CSR_EOF); |
| 834 rc = SQLITE_OK; |
| 818 break; | 835 break; |
| 819 } | 836 } |
| 820 | 837 |
| 821 case FTS5_PLAN_SORTED_MATCH: { | 838 case FTS5_PLAN_SORTED_MATCH: { |
| 822 rc = fts5SorterNext(pCsr); | 839 rc = fts5SorterNext(pCsr); |
| 823 break; | 840 break; |
| 824 } | 841 } |
| 825 | 842 |
| 826 default: | 843 default: |
| 827 rc = sqlite3_step(pCsr->pStmt); | 844 rc = sqlite3_step(pCsr->pStmt); |
| 828 if( rc!=SQLITE_ROW ){ | 845 if( rc!=SQLITE_ROW ){ |
| 829 CsrFlagSet(pCsr, FTS5CSR_EOF); | 846 CsrFlagSet(pCsr, FTS5CSR_EOF); |
| 830 rc = sqlite3_reset(pCsr->pStmt); | 847 rc = sqlite3_reset(pCsr->pStmt); |
| 831 }else{ | 848 }else{ |
| 832 rc = SQLITE_OK; | 849 rc = SQLITE_OK; |
| 833 } | 850 } |
| 834 break; | 851 break; |
| 835 } | 852 } |
| 836 } | 853 } |
| 837 | 854 |
| 838 return rc; | 855 return rc; |
| 839 } | 856 } |
| 840 | 857 |
| 841 | 858 |
| 842 static sqlite3_stmt *fts5PrepareStatement( | 859 static int fts5PrepareStatement( |
| 843 int *pRc, | 860 sqlite3_stmt **ppStmt, |
| 844 Fts5Config *pConfig, | 861 Fts5Config *pConfig, |
| 845 const char *zFmt, | 862 const char *zFmt, |
| 846 ... | 863 ... |
| 847 ){ | 864 ){ |
| 848 sqlite3_stmt *pRet = 0; | 865 sqlite3_stmt *pRet = 0; |
| 866 int rc; |
| 867 char *zSql; |
| 849 va_list ap; | 868 va_list ap; |
| 869 |
| 850 va_start(ap, zFmt); | 870 va_start(ap, zFmt); |
| 851 | 871 zSql = sqlite3_vmprintf(zFmt, ap); |
| 852 if( *pRc==SQLITE_OK ){ | 872 if( zSql==0 ){ |
| 853 int rc; | 873 rc = SQLITE_NOMEM; |
| 854 char *zSql = sqlite3_vmprintf(zFmt, ap); | 874 }else{ |
| 855 if( zSql==0 ){ | 875 rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0); |
| 856 rc = SQLITE_NOMEM; | 876 if( rc!=SQLITE_OK ){ |
| 857 }else{ | 877 *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); |
| 858 rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0); | |
| 859 if( rc!=SQLITE_OK ){ | |
| 860 *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); | |
| 861 } | |
| 862 sqlite3_free(zSql); | |
| 863 } | 878 } |
| 864 *pRc = rc; | 879 sqlite3_free(zSql); |
| 865 } | 880 } |
| 866 | 881 |
| 867 va_end(ap); | 882 va_end(ap); |
| 868 return pRet; | 883 *ppStmt = pRet; |
| 884 return rc; |
| 869 } | 885 } |
| 870 | 886 |
| 871 static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ | 887 static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ |
| 872 Fts5Config *pConfig = pTab->pConfig; | 888 Fts5Config *pConfig = pTab->pConfig; |
| 873 Fts5Sorter *pSorter; | 889 Fts5Sorter *pSorter; |
| 874 int nPhrase; | 890 int nPhrase; |
| 875 int nByte; | 891 int nByte; |
| 876 int rc = SQLITE_OK; | 892 int rc; |
| 877 const char *zRank = pCsr->zRank; | 893 const char *zRank = pCsr->zRank; |
| 878 const char *zRankArgs = pCsr->zRankArgs; | 894 const char *zRankArgs = pCsr->zRankArgs; |
| 879 | 895 |
| 880 nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); | 896 nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); |
| 881 nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); | 897 nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); |
| 882 pSorter = (Fts5Sorter*)sqlite3_malloc(nByte); | 898 pSorter = (Fts5Sorter*)sqlite3_malloc(nByte); |
| 883 if( pSorter==0 ) return SQLITE_NOMEM; | 899 if( pSorter==0 ) return SQLITE_NOMEM; |
| 884 memset(pSorter, 0, nByte); | 900 memset(pSorter, 0, nByte); |
| 885 pSorter->nIdx = nPhrase; | 901 pSorter->nIdx = nPhrase; |
| 886 | 902 |
| 887 /* TODO: It would be better to have some system for reusing statement | 903 /* TODO: It would be better to have some system for reusing statement |
| 888 ** handles here, rather than preparing a new one for each query. But that | 904 ** handles here, rather than preparing a new one for each query. But that |
| 889 ** is not possible as SQLite reference counts the virtual table objects. | 905 ** is not possible as SQLite reference counts the virtual table objects. |
| 890 ** And since the statement required here reads from this very virtual | 906 ** And since the statement required here reads from this very virtual |
| 891 ** table, saving it creates a circular reference. | 907 ** table, saving it creates a circular reference. |
| 892 ** | 908 ** |
| 893 ** If SQLite a built-in statement cache, this wouldn't be a problem. */ | 909 ** If SQLite a built-in statement cache, this wouldn't be a problem. */ |
| 894 pSorter->pStmt = fts5PrepareStatement(&rc, pConfig, | 910 rc = fts5PrepareStatement(&pSorter->pStmt, pConfig, |
| 895 "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s", | 911 "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s", |
| 896 pConfig->zDb, pConfig->zName, zRank, pConfig->zName, | 912 pConfig->zDb, pConfig->zName, zRank, pConfig->zName, |
| 897 (zRankArgs ? ", " : ""), | 913 (zRankArgs ? ", " : ""), |
| 898 (zRankArgs ? zRankArgs : ""), | 914 (zRankArgs ? zRankArgs : ""), |
| 899 bDesc ? "DESC" : "ASC" | 915 bDesc ? "DESC" : "ASC" |
| 900 ); | 916 ); |
| 901 | 917 |
| 902 pCsr->pSorter = pSorter; | 918 pCsr->pSorter = pSorter; |
| 903 if( rc==SQLITE_OK ){ | 919 if( rc==SQLITE_OK ){ |
| 904 assert( pTab->pSortCsr==0 ); | 920 assert( pTab->pSortCsr==0 ); |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1084 ** | 1100 ** |
| 1085 ** There are three possible query strategies: | 1101 ** There are three possible query strategies: |
| 1086 ** | 1102 ** |
| 1087 ** 1. Full-text search using a MATCH operator. | 1103 ** 1. Full-text search using a MATCH operator. |
| 1088 ** 2. A by-rowid lookup. | 1104 ** 2. A by-rowid lookup. |
| 1089 ** 3. A full-table scan. | 1105 ** 3. A full-table scan. |
| 1090 */ | 1106 */ |
| 1091 static int fts5FilterMethod( | 1107 static int fts5FilterMethod( |
| 1092 sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ | 1108 sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ |
| 1093 int idxNum, /* Strategy index */ | 1109 int idxNum, /* Strategy index */ |
| 1094 const char *idxStr, /* Unused */ | 1110 const char *zUnused, /* Unused */ |
| 1095 int nVal, /* Number of elements in apVal */ | 1111 int nVal, /* Number of elements in apVal */ |
| 1096 sqlite3_value **apVal /* Arguments for the indexing scheme */ | 1112 sqlite3_value **apVal /* Arguments for the indexing scheme */ |
| 1097 ){ | 1113 ){ |
| 1098 Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); | 1114 Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); |
| 1099 Fts5Config *pConfig = pTab->pConfig; | 1115 Fts5Config *pConfig = pTab->pConfig; |
| 1100 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; | 1116 Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; |
| 1101 int rc = SQLITE_OK; /* Error code */ | 1117 int rc = SQLITE_OK; /* Error code */ |
| 1102 int iVal = 0; /* Counter for apVal[] */ | 1118 int iVal = 0; /* Counter for apVal[] */ |
| 1103 int bDesc; /* True if ORDER BY [rank|rowid] DESC */ | 1119 int bDesc; /* True if ORDER BY [rank|rowid] DESC */ |
| 1104 int bOrderByRank; /* True if ORDER BY rank */ | 1120 int bOrderByRank; /* True if ORDER BY rank */ |
| 1105 sqlite3_value *pMatch = 0; /* <tbl> MATCH ? expression (or NULL) */ | 1121 sqlite3_value *pMatch = 0; /* <tbl> MATCH ? expression (or NULL) */ |
| 1106 sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */ | 1122 sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */ |
| 1107 sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */ | 1123 sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */ |
| 1108 sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */ | 1124 sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */ |
| 1109 sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */ | 1125 sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */ |
| 1110 char **pzErrmsg = pConfig->pzErrmsg; | 1126 char **pzErrmsg = pConfig->pzErrmsg; |
| 1111 | 1127 |
| 1128 UNUSED_PARAM(zUnused); |
| 1129 UNUSED_PARAM(nVal); |
| 1130 |
| 1112 if( pCsr->ePlan ){ | 1131 if( pCsr->ePlan ){ |
| 1113 fts5FreeCursorComponents(pCsr); | 1132 fts5FreeCursorComponents(pCsr); |
| 1114 memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr)); | 1133 memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr)); |
| 1115 } | 1134 } |
| 1116 | 1135 |
| 1117 assert( pCsr->pStmt==0 ); | 1136 assert( pCsr->pStmt==0 ); |
| 1118 assert( pCsr->pExpr==0 ); | 1137 assert( pCsr->pExpr==0 ); |
| 1119 assert( pCsr->csrflags==0 ); | 1138 assert( pCsr->csrflags==0 ); |
| 1120 assert( pCsr->pRank==0 ); | 1139 assert( pCsr->pRank==0 ); |
| 1121 assert( pCsr->zRank==0 ); | 1140 assert( pCsr->zRank==0 ); |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1385 }else{ | 1404 }else{ |
| 1386 rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0); | 1405 rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0); |
| 1387 } | 1406 } |
| 1388 } | 1407 } |
| 1389 } | 1408 } |
| 1390 return rc; | 1409 return rc; |
| 1391 } | 1410 } |
| 1392 | 1411 |
| 1393 static int fts5SpecialDelete( | 1412 static int fts5SpecialDelete( |
| 1394 Fts5Table *pTab, | 1413 Fts5Table *pTab, |
| 1395 sqlite3_value **apVal, | 1414 sqlite3_value **apVal |
| 1396 sqlite3_int64 *piRowid | |
| 1397 ){ | 1415 ){ |
| 1398 int rc = SQLITE_OK; | 1416 int rc = SQLITE_OK; |
| 1399 int eType1 = sqlite3_value_type(apVal[1]); | 1417 int eType1 = sqlite3_value_type(apVal[1]); |
| 1400 if( eType1==SQLITE_INTEGER ){ | 1418 if( eType1==SQLITE_INTEGER ){ |
| 1401 sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]); | 1419 sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]); |
| 1402 rc = sqlite3Fts5StorageSpecialDelete(pTab->pStorage, iDel, &apVal[2]); | 1420 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]); |
| 1403 } | 1421 } |
| 1404 return rc; | 1422 return rc; |
| 1405 } | 1423 } |
| 1406 | 1424 |
| 1407 static void fts5StorageInsert( | 1425 static void fts5StorageInsert( |
| 1408 int *pRc, | 1426 int *pRc, |
| 1409 Fts5Table *pTab, | 1427 Fts5Table *pTab, |
| 1410 sqlite3_value **apVal, | 1428 sqlite3_value **apVal, |
| 1411 i64 *piRowid | 1429 i64 *piRowid |
| 1412 ){ | 1430 ){ |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1462 | 1480 |
| 1463 eType0 = sqlite3_value_type(apVal[0]); | 1481 eType0 = sqlite3_value_type(apVal[0]); |
| 1464 if( eType0==SQLITE_NULL | 1482 if( eType0==SQLITE_NULL |
| 1465 && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL | 1483 && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL |
| 1466 ){ | 1484 ){ |
| 1467 /* A "special" INSERT op. These are handled separately. */ | 1485 /* A "special" INSERT op. These are handled separately. */ |
| 1468 const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]); | 1486 const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]); |
| 1469 if( pConfig->eContent!=FTS5_CONTENT_NORMAL | 1487 if( pConfig->eContent!=FTS5_CONTENT_NORMAL |
| 1470 && 0==sqlite3_stricmp("delete", z) | 1488 && 0==sqlite3_stricmp("delete", z) |
| 1471 ){ | 1489 ){ |
| 1472 rc = fts5SpecialDelete(pTab, apVal, pRowid); | 1490 rc = fts5SpecialDelete(pTab, apVal); |
| 1473 }else{ | 1491 }else{ |
| 1474 rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]); | 1492 rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]); |
| 1475 } | 1493 } |
| 1476 }else{ | 1494 }else{ |
| 1477 /* A regular INSERT, UPDATE or DELETE statement. The trick here is that | 1495 /* A regular INSERT, UPDATE or DELETE statement. The trick here is that |
| 1478 ** any conflict on the rowid value must be detected before any | 1496 ** any conflict on the rowid value must be detected before any |
| 1479 ** modifications are made to the database file. There are 4 cases: | 1497 ** modifications are made to the database file. There are 4 cases: |
| 1480 ** | 1498 ** |
| 1481 ** 1) DELETE | 1499 ** 1) DELETE |
| 1482 ** 2) UPDATE (rowid not modified) | 1500 ** 2) UPDATE (rowid not modified) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1496 /* Filter out attempts to run UPDATE or DELETE on contentless tables. | 1514 /* Filter out attempts to run UPDATE or DELETE on contentless tables. |
| 1497 ** This is not suported. */ | 1515 ** This is not suported. */ |
| 1498 if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){ | 1516 if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){ |
| 1499 pTab->base.zErrMsg = sqlite3_mprintf( | 1517 pTab->base.zErrMsg = sqlite3_mprintf( |
| 1500 "cannot %s contentless fts5 table: %s", | 1518 "cannot %s contentless fts5 table: %s", |
| 1501 (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName | 1519 (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName |
| 1502 ); | 1520 ); |
| 1503 rc = SQLITE_ERROR; | 1521 rc = SQLITE_ERROR; |
| 1504 } | 1522 } |
| 1505 | 1523 |
| 1506 /* Case 1: DELETE */ | 1524 /* DELETE */ |
| 1507 else if( nArg==1 ){ | 1525 else if( nArg==1 ){ |
| 1508 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ | 1526 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ |
| 1509 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel); | 1527 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); |
| 1510 } | 1528 } |
| 1511 | 1529 |
| 1512 /* Case 2: INSERT */ | 1530 /* INSERT */ |
| 1513 else if( eType0!=SQLITE_INTEGER ){ | 1531 else if( eType0!=SQLITE_INTEGER ){ |
| 1514 /* If this is a REPLACE, first remove the current entry (if any) */ | 1532 /* If this is a REPLACE, first remove the current entry (if any) */ |
| 1515 if( eConflict==SQLITE_REPLACE | 1533 if( eConflict==SQLITE_REPLACE |
| 1516 && sqlite3_value_type(apVal[1])==SQLITE_INTEGER | 1534 && sqlite3_value_type(apVal[1])==SQLITE_INTEGER |
| 1517 ){ | 1535 ){ |
| 1518 i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ | 1536 i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ |
| 1519 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew); | 1537 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); |
| 1520 } | 1538 } |
| 1521 fts5StorageInsert(&rc, pTab, apVal, pRowid); | 1539 fts5StorageInsert(&rc, pTab, apVal, pRowid); |
| 1522 } | 1540 } |
| 1523 | 1541 |
| 1524 /* Case 2: UPDATE */ | 1542 /* UPDATE */ |
| 1525 else{ | 1543 else{ |
| 1526 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ | 1544 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ |
| 1527 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ | 1545 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ |
| 1528 if( iOld!=iNew ){ | 1546 if( iOld!=iNew ){ |
| 1529 if( eConflict==SQLITE_REPLACE ){ | 1547 if( eConflict==SQLITE_REPLACE ){ |
| 1530 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld); | 1548 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); |
| 1531 if( rc==SQLITE_OK ){ | 1549 if( rc==SQLITE_OK ){ |
| 1532 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew); | 1550 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); |
| 1533 } | 1551 } |
| 1534 fts5StorageInsert(&rc, pTab, apVal, pRowid); | 1552 fts5StorageInsert(&rc, pTab, apVal, pRowid); |
| 1535 }else{ | 1553 }else{ |
| 1536 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); | 1554 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); |
| 1537 if( rc==SQLITE_OK ){ | 1555 if( rc==SQLITE_OK ){ |
| 1538 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld); | 1556 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); |
| 1539 } | 1557 } |
| 1540 if( rc==SQLITE_OK ){ | 1558 if( rc==SQLITE_OK ){ |
| 1541 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid); | 1559 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid); |
| 1542 } | 1560 } |
| 1543 } | 1561 } |
| 1544 }else{ | 1562 }else{ |
| 1545 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld); | 1563 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); |
| 1546 fts5StorageInsert(&rc, pTab, apVal, pRowid); | 1564 fts5StorageInsert(&rc, pTab, apVal, pRowid); |
| 1547 } | 1565 } |
| 1548 } | 1566 } |
| 1549 } | 1567 } |
| 1550 | 1568 |
| 1551 pTab->pConfig->pzErrmsg = 0; | 1569 pTab->pConfig->pzErrmsg = 0; |
| 1552 return rc; | 1570 return rc; |
| 1553 } | 1571 } |
| 1554 | 1572 |
| 1555 /* | 1573 /* |
| 1556 ** Implementation of xSync() method. | 1574 ** Implementation of xSync() method. |
| 1557 */ | 1575 */ |
| 1558 static int fts5SyncMethod(sqlite3_vtab *pVtab){ | 1576 static int fts5SyncMethod(sqlite3_vtab *pVtab){ |
| 1559 int rc; | 1577 int rc; |
| 1560 Fts5Table *pTab = (Fts5Table*)pVtab; | 1578 Fts5Table *pTab = (Fts5Table*)pVtab; |
| 1561 fts5CheckTransactionState(pTab, FTS5_SYNC, 0); | 1579 fts5CheckTransactionState(pTab, FTS5_SYNC, 0); |
| 1562 pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; | 1580 pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; |
| 1563 fts5TripCursors(pTab); | 1581 fts5TripCursors(pTab); |
| 1564 rc = sqlite3Fts5StorageSync(pTab->pStorage, 1); | 1582 rc = sqlite3Fts5StorageSync(pTab->pStorage, 1); |
| 1565 pTab->pConfig->pzErrmsg = 0; | 1583 pTab->pConfig->pzErrmsg = 0; |
| 1566 return rc; | 1584 return rc; |
| 1567 } | 1585 } |
| 1568 | 1586 |
| 1569 /* | 1587 /* |
| 1570 ** Implementation of xBegin() method. | 1588 ** Implementation of xBegin() method. |
| 1571 */ | 1589 */ |
| 1572 static int fts5BeginMethod(sqlite3_vtab *pVtab){ | 1590 static int fts5BeginMethod(sqlite3_vtab *pVtab){ |
| 1573 fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0); | 1591 fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0); |
| 1592 fts5NewTransaction((Fts5Table*)pVtab); |
| 1574 return SQLITE_OK; | 1593 return SQLITE_OK; |
| 1575 } | 1594 } |
| 1576 | 1595 |
| 1577 /* | 1596 /* |
| 1578 ** Implementation of xCommit() method. This is a no-op. The contents of | 1597 ** Implementation of xCommit() method. This is a no-op. The contents of |
| 1579 ** the pending-terms hash-table have already been flushed into the database | 1598 ** the pending-terms hash-table have already been flushed into the database |
| 1580 ** by fts5SyncMethod(). | 1599 ** by fts5SyncMethod(). |
| 1581 */ | 1600 */ |
| 1582 static int fts5CommitMethod(sqlite3_vtab *pVtab){ | 1601 static int fts5CommitMethod(sqlite3_vtab *pVtab){ |
| 1602 UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */ |
| 1583 fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0); | 1603 fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0); |
| 1584 return SQLITE_OK; | 1604 return SQLITE_OK; |
| 1585 } | 1605 } |
| 1586 | 1606 |
| 1587 /* | 1607 /* |
| 1588 ** Implementation of xRollback(). Discard the contents of the pending-terms | 1608 ** Implementation of xRollback(). Discard the contents of the pending-terms |
| 1589 ** hash-table. Any changes made to the database are reverted by SQLite. | 1609 ** hash-table. Any changes made to the database are reverted by SQLite. |
| 1590 */ | 1610 */ |
| 1591 static int fts5RollbackMethod(sqlite3_vtab *pVtab){ | 1611 static int fts5RollbackMethod(sqlite3_vtab *pVtab){ |
| 1592 int rc; | 1612 int rc; |
| 1593 Fts5Table *pTab = (Fts5Table*)pVtab; | 1613 Fts5Table *pTab = (Fts5Table*)pVtab; |
| 1594 fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0); | 1614 fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0); |
| 1595 rc = sqlite3Fts5StorageRollback(pTab->pStorage); | 1615 rc = sqlite3Fts5StorageRollback(pTab->pStorage); |
| 1596 return rc; | 1616 return rc; |
| 1597 } | 1617 } |
| 1598 | 1618 |
| 1619 static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*); |
| 1620 |
| 1599 static void *fts5ApiUserData(Fts5Context *pCtx){ | 1621 static void *fts5ApiUserData(Fts5Context *pCtx){ |
| 1600 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | 1622 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 1601 return pCsr->pAux->pUserData; | 1623 return pCsr->pAux->pUserData; |
| 1602 } | 1624 } |
| 1603 | 1625 |
| 1604 static int fts5ApiColumnCount(Fts5Context *pCtx){ | 1626 static int fts5ApiColumnCount(Fts5Context *pCtx){ |
| 1605 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | 1627 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 1606 return ((Fts5Table*)(pCsr->base.pVtab))->pConfig->nCol; | 1628 return ((Fts5Table*)(pCsr->base.pVtab))->pConfig->nCol; |
| 1607 } | 1629 } |
| 1608 | 1630 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1638 static int fts5ApiPhraseCount(Fts5Context *pCtx){ | 1660 static int fts5ApiPhraseCount(Fts5Context *pCtx){ |
| 1639 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | 1661 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 1640 return sqlite3Fts5ExprPhraseCount(pCsr->pExpr); | 1662 return sqlite3Fts5ExprPhraseCount(pCsr->pExpr); |
| 1641 } | 1663 } |
| 1642 | 1664 |
| 1643 static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){ | 1665 static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){ |
| 1644 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | 1666 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 1645 return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase); | 1667 return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase); |
| 1646 } | 1668 } |
| 1647 | 1669 |
| 1648 static int fts5CsrPoslist(Fts5Cursor *pCsr, int iPhrase, const u8 **pa){ | 1670 static int fts5ApiColumnText( |
| 1649 int n; | 1671 Fts5Context *pCtx, |
| 1650 if( pCsr->pSorter ){ | 1672 int iCol, |
| 1673 const char **pz, |
| 1674 int *pn |
| 1675 ){ |
| 1676 int rc = SQLITE_OK; |
| 1677 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 1678 if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ |
| 1679 *pz = 0; |
| 1680 *pn = 0; |
| 1681 }else{ |
| 1682 rc = fts5SeekCursor(pCsr, 0); |
| 1683 if( rc==SQLITE_OK ){ |
| 1684 *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); |
| 1685 *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); |
| 1686 } |
| 1687 } |
| 1688 return rc; |
| 1689 } |
| 1690 |
| 1691 static int fts5CsrPoslist( |
| 1692 Fts5Cursor *pCsr, |
| 1693 int iPhrase, |
| 1694 const u8 **pa, |
| 1695 int *pn |
| 1696 ){ |
| 1697 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; |
| 1698 int rc = SQLITE_OK; |
| 1699 int bLive = (pCsr->pSorter==0); |
| 1700 |
| 1701 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ |
| 1702 |
| 1703 if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ |
| 1704 Fts5PoslistPopulator *aPopulator; |
| 1705 int i; |
| 1706 aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive); |
| 1707 if( aPopulator==0 ) rc = SQLITE_NOMEM; |
| 1708 for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){ |
| 1709 int n; const char *z; |
| 1710 rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n); |
| 1711 if( rc==SQLITE_OK ){ |
| 1712 rc = sqlite3Fts5ExprPopulatePoslists( |
| 1713 pConfig, pCsr->pExpr, aPopulator, i, z, n |
| 1714 ); |
| 1715 } |
| 1716 } |
| 1717 sqlite3_free(aPopulator); |
| 1718 |
| 1719 if( pCsr->pSorter ){ |
| 1720 sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid); |
| 1721 } |
| 1722 } |
| 1723 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST); |
| 1724 } |
| 1725 |
| 1726 if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){ |
| 1651 Fts5Sorter *pSorter = pCsr->pSorter; | 1727 Fts5Sorter *pSorter = pCsr->pSorter; |
| 1652 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); | 1728 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); |
| 1653 n = pSorter->aIdx[iPhrase] - i1; | 1729 *pn = pSorter->aIdx[iPhrase] - i1; |
| 1654 *pa = &pSorter->aPoslist[i1]; | 1730 *pa = &pSorter->aPoslist[i1]; |
| 1655 }else{ | 1731 }else{ |
| 1656 n = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); | 1732 *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); |
| 1657 } | 1733 } |
| 1658 return n; | 1734 |
| 1735 return rc; |
| 1659 } | 1736 } |
| 1660 | 1737 |
| 1661 /* | 1738 /* |
| 1662 ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated | 1739 ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated |
| 1663 ** correctly for the current view. Return SQLITE_OK if successful, or an | 1740 ** correctly for the current view. Return SQLITE_OK if successful, or an |
| 1664 ** SQLite error code otherwise. | 1741 ** SQLite error code otherwise. |
| 1665 */ | 1742 */ |
| 1666 static int fts5CacheInstArray(Fts5Cursor *pCsr){ | 1743 static int fts5CacheInstArray(Fts5Cursor *pCsr){ |
| 1667 int rc = SQLITE_OK; | 1744 int rc = SQLITE_OK; |
| 1668 Fts5PoslistReader *aIter; /* One iterator for each phrase */ | 1745 Fts5PoslistReader *aIter; /* One iterator for each phrase */ |
| 1669 int nIter; /* Number of iterators/phrases */ | 1746 int nIter; /* Number of iterators/phrases */ |
| 1670 | 1747 |
| 1671 nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); | 1748 nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); |
| 1672 if( pCsr->aInstIter==0 ){ | 1749 if( pCsr->aInstIter==0 ){ |
| 1673 int nByte = sizeof(Fts5PoslistReader) * nIter; | 1750 int nByte = sizeof(Fts5PoslistReader) * nIter; |
| 1674 pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte); | 1751 pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte); |
| 1675 } | 1752 } |
| 1676 aIter = pCsr->aInstIter; | 1753 aIter = pCsr->aInstIter; |
| 1677 | 1754 |
| 1678 if( aIter ){ | 1755 if( aIter ){ |
| 1679 int nInst = 0; /* Number instances seen so far */ | 1756 int nInst = 0; /* Number instances seen so far */ |
| 1680 int i; | 1757 int i; |
| 1681 | 1758 |
| 1682 /* Initialize all iterators */ | 1759 /* Initialize all iterators */ |
| 1683 for(i=0; i<nIter; i++){ | 1760 for(i=0; i<nIter && rc==SQLITE_OK; i++){ |
| 1684 const u8 *a; | 1761 const u8 *a; |
| 1685 int n = fts5CsrPoslist(pCsr, i, &a); | 1762 int n; |
| 1686 sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]); | 1763 rc = fts5CsrPoslist(pCsr, i, &a, &n); |
| 1764 if( rc==SQLITE_OK ){ |
| 1765 sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]); |
| 1766 } |
| 1687 } | 1767 } |
| 1688 | 1768 |
| 1689 while( 1 ){ | 1769 if( rc==SQLITE_OK ){ |
| 1690 int *aInst; | 1770 while( 1 ){ |
| 1691 int iBest = -1; | 1771 int *aInst; |
| 1692 for(i=0; i<nIter; i++){ | 1772 int iBest = -1; |
| 1693 if( (aIter[i].bEof==0) | 1773 for(i=0; i<nIter; i++){ |
| 1694 && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos) | 1774 if( (aIter[i].bEof==0) |
| 1695 ){ | 1775 && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos) |
| 1696 iBest = i; | 1776 ){ |
| 1777 iBest = i; |
| 1778 } |
| 1697 } | 1779 } |
| 1780 if( iBest<0 ) break; |
| 1781 |
| 1782 nInst++; |
| 1783 if( nInst>=pCsr->nInstAlloc ){ |
| 1784 pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; |
| 1785 aInst = (int*)sqlite3_realloc( |
| 1786 pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3 |
| 1787 ); |
| 1788 if( aInst ){ |
| 1789 pCsr->aInst = aInst; |
| 1790 }else{ |
| 1791 rc = SQLITE_NOMEM; |
| 1792 break; |
| 1793 } |
| 1794 } |
| 1795 |
| 1796 aInst = &pCsr->aInst[3 * (nInst-1)]; |
| 1797 aInst[0] = iBest; |
| 1798 aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); |
| 1799 aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); |
| 1800 sqlite3Fts5PoslistReaderNext(&aIter[iBest]); |
| 1698 } | 1801 } |
| 1699 if( iBest<0 ) break; | |
| 1700 | |
| 1701 nInst++; | |
| 1702 if( nInst>=pCsr->nInstAlloc ){ | |
| 1703 pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; | |
| 1704 aInst = (int*)sqlite3_realloc( | |
| 1705 pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3 | |
| 1706 ); | |
| 1707 if( aInst ){ | |
| 1708 pCsr->aInst = aInst; | |
| 1709 }else{ | |
| 1710 rc = SQLITE_NOMEM; | |
| 1711 break; | |
| 1712 } | |
| 1713 } | |
| 1714 | |
| 1715 aInst = &pCsr->aInst[3 * (nInst-1)]; | |
| 1716 aInst[0] = iBest; | |
| 1717 aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); | |
| 1718 aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); | |
| 1719 sqlite3Fts5PoslistReaderNext(&aIter[iBest]); | |
| 1720 } | 1802 } |
| 1721 | 1803 |
| 1722 pCsr->nInstCount = nInst; | 1804 pCsr->nInstCount = nInst; |
| 1723 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST); | 1805 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST); |
| 1724 } | 1806 } |
| 1725 return rc; | 1807 return rc; |
| 1726 } | 1808 } |
| 1727 | 1809 |
| 1728 static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){ | 1810 static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){ |
| 1729 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | 1811 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1742 int *piCol, | 1824 int *piCol, |
| 1743 int *piOff | 1825 int *piOff |
| 1744 ){ | 1826 ){ |
| 1745 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | 1827 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 1746 int rc = SQLITE_OK; | 1828 int rc = SQLITE_OK; |
| 1747 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 | 1829 if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 |
| 1748 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) | 1830 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) |
| 1749 ){ | 1831 ){ |
| 1750 if( iIdx<0 || iIdx>=pCsr->nInstCount ){ | 1832 if( iIdx<0 || iIdx>=pCsr->nInstCount ){ |
| 1751 rc = SQLITE_RANGE; | 1833 rc = SQLITE_RANGE; |
| 1834 #if 0 |
| 1835 }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){ |
| 1836 *piPhrase = pCsr->aInst[iIdx*3]; |
| 1837 *piCol = pCsr->aInst[iIdx*3 + 2]; |
| 1838 *piOff = -1; |
| 1839 #endif |
| 1752 }else{ | 1840 }else{ |
| 1753 *piPhrase = pCsr->aInst[iIdx*3]; | 1841 *piPhrase = pCsr->aInst[iIdx*3]; |
| 1754 *piCol = pCsr->aInst[iIdx*3 + 1]; | 1842 *piCol = pCsr->aInst[iIdx*3 + 1]; |
| 1755 *piOff = pCsr->aInst[iIdx*3 + 2]; | 1843 *piOff = pCsr->aInst[iIdx*3 + 2]; |
| 1756 } | 1844 } |
| 1757 } | 1845 } |
| 1758 return rc; | 1846 return rc; |
| 1759 } | 1847 } |
| 1760 | 1848 |
| 1761 static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){ | 1849 static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){ |
| 1762 return fts5CursorRowid((Fts5Cursor*)pCtx); | 1850 return fts5CursorRowid((Fts5Cursor*)pCtx); |
| 1763 } | 1851 } |
| 1764 | 1852 |
| 1765 static int fts5ApiColumnText( | |
| 1766 Fts5Context *pCtx, | |
| 1767 int iCol, | |
| 1768 const char **pz, | |
| 1769 int *pn | |
| 1770 ){ | |
| 1771 int rc = SQLITE_OK; | |
| 1772 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | |
| 1773 if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ | |
| 1774 *pz = 0; | |
| 1775 *pn = 0; | |
| 1776 }else{ | |
| 1777 rc = fts5SeekCursor(pCsr, 0); | |
| 1778 if( rc==SQLITE_OK ){ | |
| 1779 *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); | |
| 1780 *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); | |
| 1781 } | |
| 1782 } | |
| 1783 return rc; | |
| 1784 } | |
| 1785 | |
| 1786 static int fts5ColumnSizeCb( | 1853 static int fts5ColumnSizeCb( |
| 1787 void *pContext, /* Pointer to int */ | 1854 void *pContext, /* Pointer to int */ |
| 1788 int tflags, | 1855 int tflags, |
| 1789 const char *pToken, /* Buffer containing token */ | 1856 const char *pUnused, /* Buffer containing token */ |
| 1790 int nToken, /* Size of token in bytes */ | 1857 int nUnused, /* Size of token in bytes */ |
| 1791 int iStart, /* Start offset of token */ | 1858 int iUnused1, /* Start offset of token */ |
| 1792 int iEnd /* End offset of token */ | 1859 int iUnused2 /* End offset of token */ |
| 1793 ){ | 1860 ){ |
| 1794 int *pCnt = (int*)pContext; | 1861 int *pCnt = (int*)pContext; |
| 1862 UNUSED_PARAM2(pUnused, nUnused); |
| 1863 UNUSED_PARAM2(iUnused1, iUnused2); |
| 1795 if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){ | 1864 if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){ |
| 1796 (*pCnt)++; | 1865 (*pCnt)++; |
| 1797 } | 1866 } |
| 1798 return SQLITE_OK; | 1867 return SQLITE_OK; |
| 1799 } | 1868 } |
| 1800 | 1869 |
| 1801 static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ | 1870 static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ |
| 1802 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | 1871 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 1803 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); | 1872 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); |
| 1804 Fts5Config *pConfig = pTab->pConfig; | 1873 Fts5Config *pConfig = pTab->pConfig; |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1900 if( bClear ){ | 1969 if( bClear ){ |
| 1901 pData->pPtr = 0; | 1970 pData->pPtr = 0; |
| 1902 pData->xDelete = 0; | 1971 pData->xDelete = 0; |
| 1903 } | 1972 } |
| 1904 } | 1973 } |
| 1905 | 1974 |
| 1906 return pRet; | 1975 return pRet; |
| 1907 } | 1976 } |
| 1908 | 1977 |
| 1909 static void fts5ApiPhraseNext( | 1978 static void fts5ApiPhraseNext( |
| 1910 Fts5Context *pCtx, | 1979 Fts5Context *pUnused, |
| 1911 Fts5PhraseIter *pIter, | 1980 Fts5PhraseIter *pIter, |
| 1912 int *piCol, int *piOff | 1981 int *piCol, int *piOff |
| 1913 ){ | 1982 ){ |
| 1983 UNUSED_PARAM(pUnused); |
| 1914 if( pIter->a>=pIter->b ){ | 1984 if( pIter->a>=pIter->b ){ |
| 1915 *piCol = -1; | 1985 *piCol = -1; |
| 1916 *piOff = -1; | 1986 *piOff = -1; |
| 1917 }else{ | 1987 }else{ |
| 1918 int iVal; | 1988 int iVal; |
| 1919 pIter->a += fts5GetVarint32(pIter->a, iVal); | 1989 pIter->a += fts5GetVarint32(pIter->a, iVal); |
| 1920 if( iVal==1 ){ | 1990 if( iVal==1 ){ |
| 1921 pIter->a += fts5GetVarint32(pIter->a, iVal); | 1991 pIter->a += fts5GetVarint32(pIter->a, iVal); |
| 1922 *piCol = iVal; | 1992 *piCol = iVal; |
| 1923 *piOff = 0; | 1993 *piOff = 0; |
| 1924 pIter->a += fts5GetVarint32(pIter->a, iVal); | 1994 pIter->a += fts5GetVarint32(pIter->a, iVal); |
| 1925 } | 1995 } |
| 1926 *piOff += (iVal-2); | 1996 *piOff += (iVal-2); |
| 1927 } | 1997 } |
| 1928 } | 1998 } |
| 1929 | 1999 |
| 1930 static void fts5ApiPhraseFirst( | 2000 static int fts5ApiPhraseFirst( |
| 1931 Fts5Context *pCtx, | 2001 Fts5Context *pCtx, |
| 1932 int iPhrase, | 2002 int iPhrase, |
| 1933 Fts5PhraseIter *pIter, | 2003 Fts5PhraseIter *pIter, |
| 1934 int *piCol, int *piOff | 2004 int *piCol, int *piOff |
| 1935 ){ | 2005 ){ |
| 1936 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | 2006 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 1937 int n = fts5CsrPoslist(pCsr, iPhrase, &pIter->a); | 2007 int n; |
| 1938 pIter->b = &pIter->a[n]; | 2008 int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); |
| 1939 *piCol = 0; | 2009 if( rc==SQLITE_OK ){ |
| 1940 *piOff = 0; | 2010 pIter->b = &pIter->a[n]; |
| 1941 fts5ApiPhraseNext(pCtx, pIter, piCol, piOff); | 2011 *piCol = 0; |
| 2012 *piOff = 0; |
| 2013 fts5ApiPhraseNext(pCtx, pIter, piCol, piOff); |
| 2014 } |
| 2015 return rc; |
| 1942 } | 2016 } |
| 1943 | 2017 |
| 2018 static void fts5ApiPhraseNextColumn( |
| 2019 Fts5Context *pCtx, |
| 2020 Fts5PhraseIter *pIter, |
| 2021 int *piCol |
| 2022 ){ |
| 2023 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 2024 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; |
| 2025 |
| 2026 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ |
| 2027 if( pIter->a>=pIter->b ){ |
| 2028 *piCol = -1; |
| 2029 }else{ |
| 2030 int iIncr; |
| 2031 pIter->a += fts5GetVarint32(&pIter->a[0], iIncr); |
| 2032 *piCol += (iIncr-2); |
| 2033 } |
| 2034 }else{ |
| 2035 while( 1 ){ |
| 2036 int dummy; |
| 2037 if( pIter->a>=pIter->b ){ |
| 2038 *piCol = -1; |
| 2039 return; |
| 2040 } |
| 2041 if( pIter->a[0]==0x01 ) break; |
| 2042 pIter->a += fts5GetVarint32(pIter->a, dummy); |
| 2043 } |
| 2044 pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); |
| 2045 } |
| 2046 } |
| 2047 |
| 2048 static int fts5ApiPhraseFirstColumn( |
| 2049 Fts5Context *pCtx, |
| 2050 int iPhrase, |
| 2051 Fts5PhraseIter *pIter, |
| 2052 int *piCol |
| 2053 ){ |
| 2054 int rc = SQLITE_OK; |
| 2055 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 2056 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; |
| 2057 |
| 2058 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ |
| 2059 Fts5Sorter *pSorter = pCsr->pSorter; |
| 2060 int n; |
| 2061 if( pSorter ){ |
| 2062 int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); |
| 2063 n = pSorter->aIdx[iPhrase] - i1; |
| 2064 pIter->a = &pSorter->aPoslist[i1]; |
| 2065 }else{ |
| 2066 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); |
| 2067 } |
| 2068 if( rc==SQLITE_OK ){ |
| 2069 pIter->b = &pIter->a[n]; |
| 2070 *piCol = 0; |
| 2071 fts5ApiPhraseNextColumn(pCtx, pIter, piCol); |
| 2072 } |
| 2073 }else{ |
| 2074 int n; |
| 2075 rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); |
| 2076 if( rc==SQLITE_OK ){ |
| 2077 pIter->b = &pIter->a[n]; |
| 2078 if( n<=0 ){ |
| 2079 *piCol = -1; |
| 2080 }else if( pIter->a[0]==0x01 ){ |
| 2081 pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); |
| 2082 }else{ |
| 2083 *piCol = 0; |
| 2084 } |
| 2085 } |
| 2086 } |
| 2087 |
| 2088 return rc; |
| 2089 } |
| 2090 |
| 2091 |
| 1944 static int fts5ApiQueryPhrase(Fts5Context*, int, void*, | 2092 static int fts5ApiQueryPhrase(Fts5Context*, int, void*, |
| 1945 int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) | 2093 int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) |
| 1946 ); | 2094 ); |
| 1947 | 2095 |
| 1948 static const Fts5ExtensionApi sFts5Api = { | 2096 static const Fts5ExtensionApi sFts5Api = { |
| 1949 2, /* iVersion */ | 2097 2, /* iVersion */ |
| 1950 fts5ApiUserData, | 2098 fts5ApiUserData, |
| 1951 fts5ApiColumnCount, | 2099 fts5ApiColumnCount, |
| 1952 fts5ApiRowCount, | 2100 fts5ApiRowCount, |
| 1953 fts5ApiColumnTotalSize, | 2101 fts5ApiColumnTotalSize, |
| 1954 fts5ApiTokenize, | 2102 fts5ApiTokenize, |
| 1955 fts5ApiPhraseCount, | 2103 fts5ApiPhraseCount, |
| 1956 fts5ApiPhraseSize, | 2104 fts5ApiPhraseSize, |
| 1957 fts5ApiInstCount, | 2105 fts5ApiInstCount, |
| 1958 fts5ApiInst, | 2106 fts5ApiInst, |
| 1959 fts5ApiRowid, | 2107 fts5ApiRowid, |
| 1960 fts5ApiColumnText, | 2108 fts5ApiColumnText, |
| 1961 fts5ApiColumnSize, | 2109 fts5ApiColumnSize, |
| 1962 fts5ApiQueryPhrase, | 2110 fts5ApiQueryPhrase, |
| 1963 fts5ApiSetAuxdata, | 2111 fts5ApiSetAuxdata, |
| 1964 fts5ApiGetAuxdata, | 2112 fts5ApiGetAuxdata, |
| 1965 fts5ApiPhraseFirst, | 2113 fts5ApiPhraseFirst, |
| 1966 fts5ApiPhraseNext, | 2114 fts5ApiPhraseNext, |
| 2115 fts5ApiPhraseFirstColumn, |
| 2116 fts5ApiPhraseNextColumn, |
| 1967 }; | 2117 }; |
| 1968 | 2118 |
| 1969 | |
| 1970 /* | 2119 /* |
| 1971 ** Implementation of API function xQueryPhrase(). | 2120 ** Implementation of API function xQueryPhrase(). |
| 1972 */ | 2121 */ |
| 1973 static int fts5ApiQueryPhrase( | 2122 static int fts5ApiQueryPhrase( |
| 1974 Fts5Context *pCtx, | 2123 Fts5Context *pCtx, |
| 1975 int iPhrase, | 2124 int iPhrase, |
| 1976 void *pUserData, | 2125 void *pUserData, |
| 1977 int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*) | 2126 int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*) |
| 1978 ){ | 2127 ){ |
| 1979 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | 2128 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 1980 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); | 2129 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); |
| 1981 int rc; | 2130 int rc; |
| 1982 Fts5Cursor *pNew = 0; | 2131 Fts5Cursor *pNew = 0; |
| 1983 | 2132 |
| 1984 rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew); | 2133 rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew); |
| 1985 if( rc==SQLITE_OK ){ | 2134 if( rc==SQLITE_OK ){ |
| 1986 Fts5Config *pConf = pTab->pConfig; | |
| 1987 pNew->ePlan = FTS5_PLAN_MATCH; | 2135 pNew->ePlan = FTS5_PLAN_MATCH; |
| 1988 pNew->iFirstRowid = SMALLEST_INT64; | 2136 pNew->iFirstRowid = SMALLEST_INT64; |
| 1989 pNew->iLastRowid = LARGEST_INT64; | 2137 pNew->iLastRowid = LARGEST_INT64; |
| 1990 pNew->base.pVtab = (sqlite3_vtab*)pTab; | 2138 pNew->base.pVtab = (sqlite3_vtab*)pTab; |
| 1991 rc = sqlite3Fts5ExprClonePhrase(pConf, pCsr->pExpr, iPhrase, &pNew->pExpr); | 2139 rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr); |
| 1992 } | 2140 } |
| 1993 | 2141 |
| 1994 if( rc==SQLITE_OK ){ | 2142 if( rc==SQLITE_OK ){ |
| 1995 for(rc = fts5CursorFirst(pTab, pNew, 0); | 2143 for(rc = fts5CursorFirst(pTab, pNew, 0); |
| 1996 rc==SQLITE_OK && CsrFlagTest(pNew, FTS5CSR_EOF)==0; | 2144 rc==SQLITE_OK && CsrFlagTest(pNew, FTS5CSR_EOF)==0; |
| 1997 rc = fts5NextMethod((sqlite3_vtab_cursor*)pNew) | 2145 rc = fts5NextMethod((sqlite3_vtab_cursor*)pNew) |
| 1998 ){ | 2146 ){ |
| 1999 rc = xCallback(&sFts5Api, (Fts5Context*)pNew, pUserData); | 2147 rc = xCallback(&sFts5Api, (Fts5Context*)pNew, pUserData); |
| 2000 if( rc!=SQLITE_OK ){ | 2148 if( rc!=SQLITE_OK ){ |
| 2001 if( rc==SQLITE_DONE ) rc = SQLITE_OK; | 2149 if( rc==SQLITE_DONE ) rc = SQLITE_OK; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2091 ** list 1. And so on. There is no size field for the final position list, | 2239 ** list 1. And so on. There is no size field for the final position list, |
| 2092 ** as it can be derived from the total size of the blob. | 2240 ** as it can be derived from the total size of the blob. |
| 2093 */ | 2241 */ |
| 2094 static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){ | 2242 static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){ |
| 2095 int i; | 2243 int i; |
| 2096 int rc = SQLITE_OK; | 2244 int rc = SQLITE_OK; |
| 2097 int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); | 2245 int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); |
| 2098 Fts5Buffer val; | 2246 Fts5Buffer val; |
| 2099 | 2247 |
| 2100 memset(&val, 0, sizeof(Fts5Buffer)); | 2248 memset(&val, 0, sizeof(Fts5Buffer)); |
| 2249 switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){ |
| 2250 case FTS5_DETAIL_FULL: |
| 2101 | 2251 |
| 2102 /* Append the varints */ | 2252 /* Append the varints */ |
| 2103 for(i=0; i<(nPhrase-1); i++){ | 2253 for(i=0; i<(nPhrase-1); i++){ |
| 2104 const u8 *dummy; | 2254 const u8 *dummy; |
| 2105 int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy); | 2255 int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy); |
| 2106 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); | 2256 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); |
| 2107 } | 2257 } |
| 2108 | 2258 |
| 2109 /* Append the position lists */ | 2259 /* Append the position lists */ |
| 2110 for(i=0; i<nPhrase; i++){ | 2260 for(i=0; i<nPhrase; i++){ |
| 2111 const u8 *pPoslist; | 2261 const u8 *pPoslist; |
| 2112 int nPoslist; | 2262 int nPoslist; |
| 2113 nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist); | 2263 nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist); |
| 2114 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); | 2264 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); |
| 2265 } |
| 2266 break; |
| 2267 |
| 2268 case FTS5_DETAIL_COLUMNS: |
| 2269 |
| 2270 /* Append the varints */ |
| 2271 for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){ |
| 2272 const u8 *dummy; |
| 2273 int nByte; |
| 2274 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte); |
| 2275 sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); |
| 2276 } |
| 2277 |
| 2278 /* Append the position lists */ |
| 2279 for(i=0; rc==SQLITE_OK && i<nPhrase; i++){ |
| 2280 const u8 *pPoslist; |
| 2281 int nPoslist; |
| 2282 rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &pPoslist, &nPoslist); |
| 2283 sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); |
| 2284 } |
| 2285 break; |
| 2286 |
| 2287 default: |
| 2288 break; |
| 2115 } | 2289 } |
| 2116 | 2290 |
| 2117 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free); | 2291 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free); |
| 2118 return rc; | 2292 return rc; |
| 2119 } | 2293 } |
| 2120 | 2294 |
| 2121 /* | 2295 /* |
| 2122 ** This is the xColumn method, called by SQLite to request a value from | 2296 ** This is the xColumn method, called by SQLite to request a value from |
| 2123 ** the row that the supplied cursor currently points to. | 2297 ** the row that the supplied cursor currently points to. |
| 2124 */ | 2298 */ |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2168 return rc; | 2342 return rc; |
| 2169 } | 2343 } |
| 2170 | 2344 |
| 2171 | 2345 |
| 2172 /* | 2346 /* |
| 2173 ** This routine implements the xFindFunction method for the FTS3 | 2347 ** This routine implements the xFindFunction method for the FTS3 |
| 2174 ** virtual table. | 2348 ** virtual table. |
| 2175 */ | 2349 */ |
| 2176 static int fts5FindFunctionMethod( | 2350 static int fts5FindFunctionMethod( |
| 2177 sqlite3_vtab *pVtab, /* Virtual table handle */ | 2351 sqlite3_vtab *pVtab, /* Virtual table handle */ |
| 2178 int nArg, /* Number of SQL function arguments */ | 2352 int nUnused, /* Number of SQL function arguments */ |
| 2179 const char *zName, /* Name of SQL function */ | 2353 const char *zName, /* Name of SQL function */ |
| 2180 void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ | 2354 void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ |
| 2181 void **ppArg /* OUT: User data for *pxFunc */ | 2355 void **ppArg /* OUT: User data for *pxFunc */ |
| 2182 ){ | 2356 ){ |
| 2183 Fts5Table *pTab = (Fts5Table*)pVtab; | 2357 Fts5Table *pTab = (Fts5Table*)pVtab; |
| 2184 Fts5Auxiliary *pAux; | 2358 Fts5Auxiliary *pAux; |
| 2185 | 2359 |
| 2360 UNUSED_PARAM(nUnused); |
| 2186 pAux = fts5FindAuxiliary(pTab, zName); | 2361 pAux = fts5FindAuxiliary(pTab, zName); |
| 2187 if( pAux ){ | 2362 if( pAux ){ |
| 2188 *pxFunc = fts5ApiCallback; | 2363 *pxFunc = fts5ApiCallback; |
| 2189 *ppArg = (void*)pAux; | 2364 *ppArg = (void*)pAux; |
| 2190 return 1; | 2365 return 1; |
| 2191 } | 2366 } |
| 2192 | 2367 |
| 2193 /* No function of the specified name was found. Return 0. */ | 2368 /* No function of the specified name was found. Return 0. */ |
| 2194 return 0; | 2369 return 0; |
| 2195 } | 2370 } |
| 2196 | 2371 |
| 2197 /* | 2372 /* |
| 2198 ** Implementation of FTS5 xRename method. Rename an fts5 table. | 2373 ** Implementation of FTS5 xRename method. Rename an fts5 table. |
| 2199 */ | 2374 */ |
| 2200 static int fts5RenameMethod( | 2375 static int fts5RenameMethod( |
| 2201 sqlite3_vtab *pVtab, /* Virtual table handle */ | 2376 sqlite3_vtab *pVtab, /* Virtual table handle */ |
| 2202 const char *zName /* New name of table */ | 2377 const char *zName /* New name of table */ |
| 2203 ){ | 2378 ){ |
| 2204 Fts5Table *pTab = (Fts5Table*)pVtab; | 2379 Fts5Table *pTab = (Fts5Table*)pVtab; |
| 2205 return sqlite3Fts5StorageRename(pTab->pStorage, zName); | 2380 return sqlite3Fts5StorageRename(pTab->pStorage, zName); |
| 2206 } | 2381 } |
| 2207 | 2382 |
| 2208 /* | 2383 /* |
| 2209 ** The xSavepoint() method. | 2384 ** The xSavepoint() method. |
| 2210 ** | 2385 ** |
| 2211 ** Flush the contents of the pending-terms table to disk. | 2386 ** Flush the contents of the pending-terms table to disk. |
| 2212 */ | 2387 */ |
| 2213 static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ | 2388 static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ |
| 2214 Fts5Table *pTab = (Fts5Table*)pVtab; | 2389 Fts5Table *pTab = (Fts5Table*)pVtab; |
| 2390 UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ |
| 2215 fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); | 2391 fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); |
| 2216 fts5TripCursors(pTab); | 2392 fts5TripCursors(pTab); |
| 2217 return sqlite3Fts5StorageSync(pTab->pStorage, 0); | 2393 return sqlite3Fts5StorageSync(pTab->pStorage, 0); |
| 2218 } | 2394 } |
| 2219 | 2395 |
| 2220 /* | 2396 /* |
| 2221 ** The xRelease() method. | 2397 ** The xRelease() method. |
| 2222 ** | 2398 ** |
| 2223 ** This is a no-op. | 2399 ** This is a no-op. |
| 2224 */ | 2400 */ |
| 2225 static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ | 2401 static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ |
| 2226 Fts5Table *pTab = (Fts5Table*)pVtab; | 2402 Fts5Table *pTab = (Fts5Table*)pVtab; |
| 2403 UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ |
| 2227 fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint); | 2404 fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint); |
| 2228 fts5TripCursors(pTab); | 2405 fts5TripCursors(pTab); |
| 2229 return sqlite3Fts5StorageSync(pTab->pStorage, 0); | 2406 return sqlite3Fts5StorageSync(pTab->pStorage, 0); |
| 2230 } | 2407 } |
| 2231 | 2408 |
| 2232 /* | 2409 /* |
| 2233 ** The xRollbackTo() method. | 2410 ** The xRollbackTo() method. |
| 2234 ** | 2411 ** |
| 2235 ** Discard the contents of the pending terms table. | 2412 ** Discard the contents of the pending terms table. |
| 2236 */ | 2413 */ |
| 2237 static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ | 2414 static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ |
| 2238 Fts5Table *pTab = (Fts5Table*)pVtab; | 2415 Fts5Table *pTab = (Fts5Table*)pVtab; |
| 2416 UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ |
| 2239 fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); | 2417 fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); |
| 2240 fts5TripCursors(pTab); | 2418 fts5TripCursors(pTab); |
| 2241 return sqlite3Fts5StorageRollback(pTab->pStorage); | 2419 return sqlite3Fts5StorageRollback(pTab->pStorage); |
| 2242 } | 2420 } |
| 2243 | 2421 |
| 2244 /* | 2422 /* |
| 2245 ** Register a new auxiliary function with global context pGlobal. | 2423 ** Register a new auxiliary function with global context pGlobal. |
| 2246 */ | 2424 */ |
| 2247 static int fts5CreateAux( | 2425 static int fts5CreateAux( |
| 2248 fts5_api *pApi, /* Global context (one per db handle) */ | 2426 fts5_api *pApi, /* Global context (one per db handle) */ |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2408 if( pTok->xDestroy ) pTok->xDestroy(pTok->pUserData); | 2586 if( pTok->xDestroy ) pTok->xDestroy(pTok->pUserData); |
| 2409 sqlite3_free(pTok); | 2587 sqlite3_free(pTok); |
| 2410 } | 2588 } |
| 2411 | 2589 |
| 2412 sqlite3_free(pGlobal); | 2590 sqlite3_free(pGlobal); |
| 2413 } | 2591 } |
| 2414 | 2592 |
| 2415 static void fts5Fts5Func( | 2593 static void fts5Fts5Func( |
| 2416 sqlite3_context *pCtx, /* Function call context */ | 2594 sqlite3_context *pCtx, /* Function call context */ |
| 2417 int nArg, /* Number of args */ | 2595 int nArg, /* Number of args */ |
| 2418 sqlite3_value **apVal /* Function arguments */ | 2596 sqlite3_value **apUnused /* Function arguments */ |
| 2419 ){ | 2597 ){ |
| 2420 Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx); | 2598 Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx); |
| 2421 char buf[8]; | 2599 char buf[8]; |
| 2600 UNUSED_PARAM2(nArg, apUnused); |
| 2422 assert( nArg==0 ); | 2601 assert( nArg==0 ); |
| 2423 assert( sizeof(buf)>=sizeof(pGlobal) ); | 2602 assert( sizeof(buf)>=sizeof(pGlobal) ); |
| 2424 memcpy(buf, (void*)&pGlobal, sizeof(pGlobal)); | 2603 memcpy(buf, (void*)&pGlobal, sizeof(pGlobal)); |
| 2425 sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT); | 2604 sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT); |
| 2426 } | 2605 } |
| 2427 | 2606 |
| 2428 /* | 2607 /* |
| 2429 ** Implementation of fts5_source_id() function. | 2608 ** Implementation of fts5_source_id() function. |
| 2430 */ | 2609 */ |
| 2431 static void fts5SourceIdFunc( | 2610 static void fts5SourceIdFunc( |
| 2432 sqlite3_context *pCtx, /* Function call context */ | 2611 sqlite3_context *pCtx, /* Function call context */ |
| 2433 int nArg, /* Number of args */ | 2612 int nArg, /* Number of args */ |
| 2434 sqlite3_value **apVal /* Function arguments */ | 2613 sqlite3_value **apUnused /* Function arguments */ |
| 2435 ){ | 2614 ){ |
| 2436 assert( nArg==0 ); | 2615 assert( nArg==0 ); |
| 2616 UNUSED_PARAM2(nArg, apUnused); |
| 2437 sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT); | 2617 sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT); |
| 2438 } | 2618 } |
| 2439 | 2619 |
| 2440 static int fts5Init(sqlite3 *db){ | 2620 static int fts5Init(sqlite3 *db){ |
| 2441 static const sqlite3_module fts5Mod = { | 2621 static const sqlite3_module fts5Mod = { |
| 2442 /* iVersion */ 2, | 2622 /* iVersion */ 2, |
| 2443 /* xCreate */ fts5CreateMethod, | 2623 /* xCreate */ fts5CreateMethod, |
| 2444 /* xConnect */ fts5ConnectMethod, | 2624 /* xConnect */ fts5ConnectMethod, |
| 2445 /* xBestIndex */ fts5BestIndexMethod, | 2625 /* xBestIndex */ fts5BestIndexMethod, |
| 2446 /* xDisconnect */ fts5DisconnectMethod, | 2626 /* xDisconnect */ fts5DisconnectMethod, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2488 rc = sqlite3_create_function( | 2668 rc = sqlite3_create_function( |
| 2489 db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0 | 2669 db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0 |
| 2490 ); | 2670 ); |
| 2491 } | 2671 } |
| 2492 if( rc==SQLITE_OK ){ | 2672 if( rc==SQLITE_OK ){ |
| 2493 rc = sqlite3_create_function( | 2673 rc = sqlite3_create_function( |
| 2494 db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0 | 2674 db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0 |
| 2495 ); | 2675 ); |
| 2496 } | 2676 } |
| 2497 } | 2677 } |
| 2678 |
| 2679 /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file |
| 2680 ** fts5_test_mi.c is compiled and linked into the executable. And call |
| 2681 ** its entry point to enable the matchinfo() demo. */ |
| 2682 #ifdef SQLITE_FTS5_ENABLE_TEST_MI |
| 2683 if( rc==SQLITE_OK ){ |
| 2684 extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*); |
| 2685 rc = sqlite3Fts5TestRegisterMatchinfo(db); |
| 2686 } |
| 2687 #endif |
| 2688 |
| 2498 return rc; | 2689 return rc; |
| 2499 } | 2690 } |
| 2500 | 2691 |
| 2501 /* | 2692 /* |
| 2502 ** The following functions are used to register the module with SQLite. If | 2693 ** The following functions are used to register the module with SQLite. If |
| 2503 ** this module is being built as part of the SQLite core (SQLITE_CORE is | 2694 ** this module is being built as part of the SQLite core (SQLITE_CORE is |
| 2504 ** defined), then sqlite3_open() will call sqlite3Fts5Init() directly. | 2695 ** defined), then sqlite3_open() will call sqlite3Fts5Init() directly. |
| 2505 ** | 2696 ** |
| 2506 ** Or, if this module is being built as a loadable extension, | 2697 ** Or, if this module is being built as a loadable extension, |
| 2507 ** sqlite3Fts5Init() is omitted and the two standard entry points | 2698 ** sqlite3Fts5Init() is omitted and the two standard entry points |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2531 ){ | 2722 ){ |
| 2532 SQLITE_EXTENSION_INIT2(pApi); | 2723 SQLITE_EXTENSION_INIT2(pApi); |
| 2533 (void)pzErrMsg; /* Unused parameter */ | 2724 (void)pzErrMsg; /* Unused parameter */ |
| 2534 return fts5Init(db); | 2725 return fts5Init(db); |
| 2535 } | 2726 } |
| 2536 #else | 2727 #else |
| 2537 int sqlite3Fts5Init(sqlite3 *db){ | 2728 int sqlite3Fts5Init(sqlite3 *db){ |
| 2538 return fts5Init(db); | 2729 return fts5Init(db); |
| 2539 } | 2730 } |
| 2540 #endif | 2731 #endif |
| OLD | NEW |