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 |