OLD | NEW |
1 /* fts2 has a design flaw which can lead to database corruption (see | 1 /* fts2 has a design flaw which can lead to database corruption (see |
2 ** below). It is recommended not to use it any longer, instead use | 2 ** below). It is recommended not to use it any longer, instead use |
3 ** fts3 (or higher). If you believe that your use of fts2 is safe, | 3 ** fts3 (or higher). If you believe that your use of fts2 is safe, |
4 ** add -DSQLITE_ENABLE_BROKEN_FTS2=1 to your CFLAGS. | 4 ** add -DSQLITE_ENABLE_BROKEN_FTS2=1 to your CFLAGS. |
5 */ | 5 */ |
6 #if (!defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2)) \ | 6 #if (!defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2)) \ |
7 && !defined(SQLITE_ENABLE_BROKEN_FTS2) | 7 && !defined(SQLITE_ENABLE_BROKEN_FTS2) |
8 #error fts2 has a design flaw and has been deprecated. | 8 #error fts2 has a design flaw and has been deprecated. |
9 #endif | 9 #endif |
10 /* The flaw is that fts2 uses the content table's unaliased rowid as | 10 /* The flaw is that fts2 uses the content table's unaliased rowid as |
(...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 vu >>= 7; | 440 vu >>= 7; |
441 }while( vu!=0 ); | 441 }while( vu!=0 ); |
442 q[-1] &= 0x7f; /* turn off high bit in final byte */ | 442 q[-1] &= 0x7f; /* turn off high bit in final byte */ |
443 assert( q - (unsigned char *)p <= VARINT_MAX ); | 443 assert( q - (unsigned char *)p <= VARINT_MAX ); |
444 return (int) (q - (unsigned char *)p); | 444 return (int) (q - (unsigned char *)p); |
445 } | 445 } |
446 | 446 |
447 /* Read a 64-bit variable-length integer from memory starting at p[0]. | 447 /* Read a 64-bit variable-length integer from memory starting at p[0]. |
448 * Return the number of bytes read, or 0 on error. | 448 * Return the number of bytes read, or 0 on error. |
449 * The value is stored in *v. */ | 449 * The value is stored in *v. */ |
450 static int getVarint(const char *p, sqlite_int64 *v){ | 450 static int getVarintSafe(const char *p, sqlite_int64 *v, int max){ |
451 const unsigned char *q = (const unsigned char *) p; | 451 const unsigned char *q = (const unsigned char *) p; |
452 sqlite_uint64 x = 0, y = 1; | 452 sqlite_uint64 x = 0, y = 1; |
453 while( (*q & 0x80) == 0x80 ){ | 453 if( max>VARINT_MAX ) max = VARINT_MAX; |
| 454 while( max && (*q & 0x80) == 0x80 ){ |
| 455 max--; |
454 x += y * (*q++ & 0x7f); | 456 x += y * (*q++ & 0x7f); |
455 y <<= 7; | 457 y <<= 7; |
456 if( q - (unsigned char *)p >= VARINT_MAX ){ /* bad data */ | 458 } |
457 assert( 0 ); | 459 if ( !max ){ |
458 return 0; | 460 assert( 0 ); |
459 } | 461 return 0; /* tried to read too much; bad data */ |
460 } | 462 } |
461 x += y * (*q++); | 463 x += y * (*q++); |
462 *v = (sqlite_int64) x; | 464 *v = (sqlite_int64) x; |
463 return (int) (q - (unsigned char *)p); | 465 return (int) (q - (unsigned char *)p); |
464 } | 466 } |
465 | 467 |
466 static int getVarint32(const char *p, int *pi){ | 468 static int getVarint(const char *p, sqlite_int64 *v){ |
| 469 return getVarintSafe(p, v, VARINT_MAX); |
| 470 } |
| 471 |
| 472 static int getVarint32Safe(const char *p, int *pi, int max){ |
467 sqlite_int64 i; | 473 sqlite_int64 i; |
468 int ret = getVarint(p, &i); | 474 int ret = getVarintSafe(p, &i, max); |
| 475 if( !ret ) return ret; |
469 *pi = (int) i; | 476 *pi = (int) i; |
470 assert( *pi==i ); | 477 assert( *pi==i ); |
471 return ret; | 478 return ret; |
472 } | 479 } |
473 | 480 |
| 481 static int getVarint32(const char* p, int *pi){ |
| 482 return getVarint32Safe(p, pi, VARINT_MAX); |
| 483 } |
| 484 |
474 /*******************************************************************/ | 485 /*******************************************************************/ |
475 /* DataBuffer is used to collect data into a buffer in piecemeal | 486 /* DataBuffer is used to collect data into a buffer in piecemeal |
476 ** fashion. It implements the usual distinction between amount of | 487 ** fashion. It implements the usual distinction between amount of |
477 ** data currently stored (nData) and buffer capacity (nCapacity). | 488 ** data currently stored (nData) and buffer capacity (nCapacity). |
478 ** | 489 ** |
479 ** dataBufferInit - create a buffer with given initial capacity. | 490 ** dataBufferInit - create a buffer with given initial capacity. |
480 ** dataBufferReset - forget buffer's data, retaining capacity. | 491 ** dataBufferReset - forget buffer's data, retaining capacity. |
481 ** dataBufferDestroy - free buffer's data. | 492 ** dataBufferDestroy - free buffer's data. |
482 ** dataBufferSwap - swap contents of two buffers. | 493 ** dataBufferSwap - swap contents of two buffers. |
483 ** dataBufferExpand - expand capacity without adding data. | 494 ** dataBufferExpand - expand capacity without adding data. |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
632 DocListType iType; | 643 DocListType iType; |
633 const char *pData; | 644 const char *pData; |
634 int nData; | 645 int nData; |
635 | 646 |
636 sqlite_int64 iDocid; | 647 sqlite_int64 iDocid; |
637 int nElement; | 648 int nElement; |
638 } DLReader; | 649 } DLReader; |
639 | 650 |
640 static int dlrAtEnd(DLReader *pReader){ | 651 static int dlrAtEnd(DLReader *pReader){ |
641 assert( pReader->nData>=0 ); | 652 assert( pReader->nData>=0 ); |
642 return pReader->nData==0; | 653 return pReader->nData<=0; |
643 } | 654 } |
644 static sqlite_int64 dlrDocid(DLReader *pReader){ | 655 static sqlite_int64 dlrDocid(DLReader *pReader){ |
645 assert( !dlrAtEnd(pReader) ); | 656 assert( !dlrAtEnd(pReader) ); |
646 return pReader->iDocid; | 657 return pReader->iDocid; |
647 } | 658 } |
648 static const char *dlrDocData(DLReader *pReader){ | 659 static const char *dlrDocData(DLReader *pReader){ |
649 assert( !dlrAtEnd(pReader) ); | 660 assert( !dlrAtEnd(pReader) ); |
650 return pReader->pData; | 661 return pReader->pData; |
651 } | 662 } |
652 static int dlrDocDataBytes(DLReader *pReader){ | 663 static int dlrDocDataBytes(DLReader *pReader){ |
653 assert( !dlrAtEnd(pReader) ); | 664 assert( !dlrAtEnd(pReader) ); |
654 return pReader->nElement; | 665 return pReader->nElement; |
655 } | 666 } |
656 static int dlrAllDataBytes(DLReader *pReader){ | 667 static int dlrAllDataBytes(DLReader *pReader){ |
657 assert( !dlrAtEnd(pReader) ); | 668 assert( !dlrAtEnd(pReader) ); |
658 return pReader->nData; | 669 return pReader->nData; |
659 } | 670 } |
660 /* TODO(shess) Consider adding a field to track iDocid varint length | 671 /* TODO(shess) Consider adding a field to track iDocid varint length |
661 ** to make these two functions faster. This might matter (a tiny bit) | 672 ** to make these two functions faster. This might matter (a tiny bit) |
662 ** for queries. | 673 ** for queries. |
663 */ | 674 */ |
664 static const char *dlrPosData(DLReader *pReader){ | 675 static const char *dlrPosData(DLReader *pReader){ |
665 sqlite_int64 iDummy; | 676 sqlite_int64 iDummy; |
666 int n = getVarint(pReader->pData, &iDummy); | 677 int n = getVarintSafe(pReader->pData, &iDummy, pReader->nElement); |
| 678 if( !n ) return NULL; |
667 assert( !dlrAtEnd(pReader) ); | 679 assert( !dlrAtEnd(pReader) ); |
668 return pReader->pData+n; | 680 return pReader->pData+n; |
669 } | 681 } |
670 static int dlrPosDataLen(DLReader *pReader){ | 682 static int dlrPosDataLen(DLReader *pReader){ |
671 sqlite_int64 iDummy; | 683 sqlite_int64 iDummy; |
672 int n = getVarint(pReader->pData, &iDummy); | 684 int n = getVarint(pReader->pData, &iDummy); |
673 assert( !dlrAtEnd(pReader) ); | 685 assert( !dlrAtEnd(pReader) ); |
674 return pReader->nElement-n; | 686 return pReader->nElement-n; |
675 } | 687 } |
676 static void dlrStep(DLReader *pReader){ | 688 static int dlrStep(DLReader *pReader){ |
677 assert( !dlrAtEnd(pReader) ); | 689 assert( !dlrAtEnd(pReader) ); |
678 | 690 |
679 /* Skip past current doclist element. */ | 691 /* Skip past current doclist element. */ |
680 assert( pReader->nElement<=pReader->nData ); | 692 assert( pReader->nElement<=pReader->nData ); |
681 pReader->pData += pReader->nElement; | 693 pReader->pData += pReader->nElement; |
682 pReader->nData -= pReader->nElement; | 694 pReader->nData -= pReader->nElement; |
683 | 695 |
684 /* If there is more data, read the next doclist element. */ | 696 /* If there is more data, read the next doclist element. */ |
685 if( pReader->nData!=0 ){ | 697 if( pReader->nData>0 ){ |
686 sqlite_int64 iDocidDelta; | 698 sqlite_int64 iDocidDelta; |
687 int iDummy, n = getVarint(pReader->pData, &iDocidDelta); | 699 int nTotal = 0; |
| 700 int iDummy, n = getVarintSafe(pReader->pData, &iDocidDelta, pReader->nData); |
| 701 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 702 nTotal += n; |
688 pReader->iDocid += iDocidDelta; | 703 pReader->iDocid += iDocidDelta; |
689 if( pReader->iType>=DL_POSITIONS ){ | 704 if( pReader->iType>=DL_POSITIONS ){ |
690 assert( n<pReader->nData ); | |
691 while( 1 ){ | 705 while( 1 ){ |
692 n += getVarint32(pReader->pData+n, &iDummy); | 706 n = getVarint32Safe(pReader->pData+nTotal, &iDummy, |
693 assert( n<=pReader->nData ); | 707 pReader->nData-nTotal); |
| 708 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 709 nTotal += n; |
694 if( iDummy==POS_END ) break; | 710 if( iDummy==POS_END ) break; |
695 if( iDummy==POS_COLUMN ){ | 711 if( iDummy==POS_COLUMN ){ |
696 n += getVarint32(pReader->pData+n, &iDummy); | 712 n = getVarint32Safe(pReader->pData+nTotal, &iDummy, |
697 assert( n<pReader->nData ); | 713 pReader->nData-nTotal); |
| 714 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 715 nTotal += n; |
698 }else if( pReader->iType==DL_POSITIONS_OFFSETS ){ | 716 }else if( pReader->iType==DL_POSITIONS_OFFSETS ){ |
699 n += getVarint32(pReader->pData+n, &iDummy); | 717 n = getVarint32Safe(pReader->pData+nTotal, &iDummy, |
700 n += getVarint32(pReader->pData+n, &iDummy); | 718 pReader->nData-nTotal); |
701 assert( n<pReader->nData ); | 719 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 720 nTotal += n; |
| 721 n = getVarint32Safe(pReader->pData+nTotal, &iDummy, |
| 722 pReader->nData-nTotal); |
| 723 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 724 nTotal += n; |
702 } | 725 } |
703 } | 726 } |
704 } | 727 } |
705 pReader->nElement = n; | 728 pReader->nElement = nTotal; |
706 assert( pReader->nElement<=pReader->nData ); | 729 assert( pReader->nElement<=pReader->nData ); |
707 } | 730 } |
| 731 return SQLITE_OK; |
708 } | 732 } |
709 static void dlrInit(DLReader *pReader, DocListType iType, | 733 static void dlrDestroy(DLReader *pReader){ |
710 const char *pData, int nData){ | 734 SCRAMBLE(pReader); |
| 735 } |
| 736 static int dlrInit(DLReader *pReader, DocListType iType, |
| 737 const char *pData, int nData){ |
| 738 int rc; |
711 assert( pData!=NULL && nData!=0 ); | 739 assert( pData!=NULL && nData!=0 ); |
712 pReader->iType = iType; | 740 pReader->iType = iType; |
713 pReader->pData = pData; | 741 pReader->pData = pData; |
714 pReader->nData = nData; | 742 pReader->nData = nData; |
715 pReader->nElement = 0; | 743 pReader->nElement = 0; |
716 pReader->iDocid = 0; | 744 pReader->iDocid = 0; |
717 | 745 |
718 /* Load the first element's data. There must be a first element. */ | 746 /* Load the first element's data. There must be a first element. */ |
719 dlrStep(pReader); | 747 rc = dlrStep(pReader); |
720 } | 748 if( rc!=SQLITE_OK ) dlrDestroy(pReader); |
721 static void dlrDestroy(DLReader *pReader){ | 749 return rc; |
722 SCRAMBLE(pReader); | |
723 } | 750 } |
724 | 751 |
725 #ifndef NDEBUG | 752 #ifndef NDEBUG |
726 /* Verify that the doclist can be validly decoded. Also returns the | 753 /* Verify that the doclist can be validly decoded. Also returns the |
727 ** last docid found because it is convenient in other assertions for | 754 ** last docid found because it is convenient in other assertions for |
728 ** DLWriter. | 755 ** DLWriter. |
729 */ | 756 */ |
730 static void docListValidate(DocListType iType, const char *pData, int nData, | 757 static void docListValidate(DocListType iType, const char *pData, int nData, |
731 sqlite_int64 *pLastDocid){ | 758 sqlite_int64 *pLastDocid){ |
732 sqlite_int64 iPrevDocid = 0; | 759 sqlite_int64 iPrevDocid = 0; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
799 ** | 826 ** |
800 ** iLastDocid is the final docid in the doclist in pData. It is | 827 ** iLastDocid is the final docid in the doclist in pData. It is |
801 ** needed to create the new iPrevDocid for future delta-encoding. The | 828 ** needed to create the new iPrevDocid for future delta-encoding. The |
802 ** code could decode the passed doclist to recreate iLastDocid, but | 829 ** code could decode the passed doclist to recreate iLastDocid, but |
803 ** the only current user (docListMerge) already has decoded this | 830 ** the only current user (docListMerge) already has decoded this |
804 ** information. | 831 ** information. |
805 */ | 832 */ |
806 /* TODO(shess) This has become just a helper for docListMerge. | 833 /* TODO(shess) This has become just a helper for docListMerge. |
807 ** Consider a refactor to make this cleaner. | 834 ** Consider a refactor to make this cleaner. |
808 */ | 835 */ |
809 static void dlwAppend(DLWriter *pWriter, | 836 static int dlwAppend(DLWriter *pWriter, |
810 const char *pData, int nData, | 837 const char *pData, int nData, |
811 sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ | 838 sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ |
812 sqlite_int64 iDocid = 0; | 839 sqlite_int64 iDocid = 0; |
813 char c[VARINT_MAX]; | 840 char c[VARINT_MAX]; |
814 int nFirstOld, nFirstNew; /* Old and new varint len of first docid. */ | 841 int nFirstOld, nFirstNew; /* Old and new varint len of first docid. */ |
815 #ifndef NDEBUG | 842 #ifndef NDEBUG |
816 sqlite_int64 iLastDocidDelta; | 843 sqlite_int64 iLastDocidDelta; |
817 #endif | 844 #endif |
818 | 845 |
819 /* Recode the initial docid as delta from iPrevDocid. */ | 846 /* Recode the initial docid as delta from iPrevDocid. */ |
820 nFirstOld = getVarint(pData, &iDocid); | 847 nFirstOld = getVarintSafe(pData, &iDocid, nData); |
| 848 if( !nFirstOld ) return SQLITE_CORRUPT_BKPT; |
821 assert( nFirstOld<nData || (nFirstOld==nData && pWriter->iType==DL_DOCIDS) ); | 849 assert( nFirstOld<nData || (nFirstOld==nData && pWriter->iType==DL_DOCIDS) ); |
822 nFirstNew = putVarint(c, iFirstDocid-pWriter->iPrevDocid); | 850 nFirstNew = putVarint(c, iFirstDocid-pWriter->iPrevDocid); |
823 | 851 |
824 /* Verify that the incoming doclist is valid AND that it ends with | 852 /* Verify that the incoming doclist is valid AND that it ends with |
825 ** the expected docid. This is essential because we'll trust this | 853 ** the expected docid. This is essential because we'll trust this |
826 ** docid in future delta-encoding. | 854 ** docid in future delta-encoding. |
827 */ | 855 */ |
828 ASSERT_VALID_DOCLIST(pWriter->iType, pData, nData, &iLastDocidDelta); | 856 ASSERT_VALID_DOCLIST(pWriter->iType, pData, nData, &iLastDocidDelta); |
829 assert( iLastDocid==iFirstDocid-iDocid+iLastDocidDelta ); | 857 assert( iLastDocid==iFirstDocid-iDocid+iLastDocidDelta ); |
830 | 858 |
831 /* Append recoded initial docid and everything else. Rest of docids | 859 /* Append recoded initial docid and everything else. Rest of docids |
832 ** should have been delta-encoded from previous initial docid. | 860 ** should have been delta-encoded from previous initial docid. |
833 */ | 861 */ |
834 if( nFirstOld<nData ){ | 862 if( nFirstOld<nData ){ |
835 dataBufferAppend2(pWriter->b, c, nFirstNew, | 863 dataBufferAppend2(pWriter->b, c, nFirstNew, |
836 pData+nFirstOld, nData-nFirstOld); | 864 pData+nFirstOld, nData-nFirstOld); |
837 }else{ | 865 }else{ |
838 dataBufferAppend(pWriter->b, c, nFirstNew); | 866 dataBufferAppend(pWriter->b, c, nFirstNew); |
839 } | 867 } |
840 pWriter->iPrevDocid = iLastDocid; | 868 pWriter->iPrevDocid = iLastDocid; |
| 869 return SQLITE_OK; |
841 } | 870 } |
842 static void dlwCopy(DLWriter *pWriter, DLReader *pReader){ | 871 static int dlwCopy(DLWriter *pWriter, DLReader *pReader){ |
843 dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), | 872 return dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), |
844 dlrDocid(pReader), dlrDocid(pReader)); | 873 dlrDocid(pReader), dlrDocid(pReader)); |
845 } | 874 } |
846 static void dlwAdd(DLWriter *pWriter, sqlite_int64 iDocid){ | 875 static void dlwAdd(DLWriter *pWriter, sqlite_int64 iDocid){ |
847 char c[VARINT_MAX]; | 876 char c[VARINT_MAX]; |
848 int n = putVarint(c, iDocid-pWriter->iPrevDocid); | 877 int n = putVarint(c, iDocid-pWriter->iPrevDocid); |
849 | 878 |
850 /* Docids must ascend. */ | 879 /* Docids must ascend. */ |
851 assert( !pWriter->has_iPrevDocid || iDocid>pWriter->iPrevDocid ); | 880 assert( !pWriter->has_iPrevDocid || iDocid>pWriter->iPrevDocid ); |
852 assert( pWriter->iType==DL_DOCIDS ); | 881 assert( pWriter->iType==DL_DOCIDS ); |
853 | 882 |
854 dataBufferAppend(pWriter->b, c, n); | 883 dataBufferAppend(pWriter->b, c, n); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
895 return pReader->iPosition; | 924 return pReader->iPosition; |
896 } | 925 } |
897 static int plrStartOffset(PLReader *pReader){ | 926 static int plrStartOffset(PLReader *pReader){ |
898 assert( !plrAtEnd(pReader) ); | 927 assert( !plrAtEnd(pReader) ); |
899 return pReader->iStartOffset; | 928 return pReader->iStartOffset; |
900 } | 929 } |
901 static int plrEndOffset(PLReader *pReader){ | 930 static int plrEndOffset(PLReader *pReader){ |
902 assert( !plrAtEnd(pReader) ); | 931 assert( !plrAtEnd(pReader) ); |
903 return pReader->iEndOffset; | 932 return pReader->iEndOffset; |
904 } | 933 } |
905 static void plrStep(PLReader *pReader){ | 934 static int plrStep(PLReader *pReader){ |
906 int i, n; | 935 int i, n, nTotal = 0; |
907 | 936 |
908 assert( !plrAtEnd(pReader) ); | 937 assert( !plrAtEnd(pReader) ); |
909 | 938 |
910 if( pReader->nData==0 ){ | 939 if( pReader->nData<=0 ){ |
911 pReader->pData = NULL; | 940 pReader->pData = NULL; |
912 return; | 941 return SQLITE_OK; |
913 } | 942 } |
914 | 943 |
915 n = getVarint32(pReader->pData, &i); | 944 n = getVarint32Safe(pReader->pData, &i, pReader->nData); |
| 945 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 946 nTotal += n; |
916 if( i==POS_COLUMN ){ | 947 if( i==POS_COLUMN ){ |
917 n += getVarint32(pReader->pData+n, &pReader->iColumn); | 948 n = getVarint32Safe(pReader->pData+nTotal, &pReader->iColumn, |
| 949 pReader->nData-nTotal); |
| 950 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 951 nTotal += n; |
918 pReader->iPosition = 0; | 952 pReader->iPosition = 0; |
919 pReader->iStartOffset = 0; | 953 pReader->iStartOffset = 0; |
920 n += getVarint32(pReader->pData+n, &i); | 954 n = getVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); |
| 955 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 956 nTotal += n; |
921 } | 957 } |
922 /* Should never see adjacent column changes. */ | 958 /* Should never see adjacent column changes. */ |
923 assert( i!=POS_COLUMN ); | 959 assert( i!=POS_COLUMN ); |
924 | 960 |
925 if( i==POS_END ){ | 961 if( i==POS_END ){ |
| 962 assert( nTotal<=pReader->nData ); |
926 pReader->nData = 0; | 963 pReader->nData = 0; |
927 pReader->pData = NULL; | 964 pReader->pData = NULL; |
928 return; | 965 return SQLITE_OK; |
929 } | 966 } |
930 | 967 |
931 pReader->iPosition += i-POS_BASE; | 968 pReader->iPosition += i-POS_BASE; |
932 if( pReader->iType==DL_POSITIONS_OFFSETS ){ | 969 if( pReader->iType==DL_POSITIONS_OFFSETS ){ |
933 n += getVarint32(pReader->pData+n, &i); | 970 n = getVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); |
| 971 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 972 nTotal += n; |
934 pReader->iStartOffset += i; | 973 pReader->iStartOffset += i; |
935 n += getVarint32(pReader->pData+n, &i); | 974 n = getVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); |
| 975 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 976 nTotal += n; |
936 pReader->iEndOffset = pReader->iStartOffset+i; | 977 pReader->iEndOffset = pReader->iStartOffset+i; |
937 } | 978 } |
938 assert( n<=pReader->nData ); | 979 assert( nTotal<=pReader->nData ); |
939 pReader->pData += n; | 980 pReader->pData += nTotal; |
940 pReader->nData -= n; | 981 pReader->nData -= nTotal; |
| 982 return SQLITE_OK; |
941 } | 983 } |
942 | 984 |
943 static void plrInit(PLReader *pReader, DLReader *pDLReader){ | 985 static void plrDestroy(PLReader *pReader){ |
| 986 SCRAMBLE(pReader); |
| 987 } |
| 988 |
| 989 static int plrInit(PLReader *pReader, DLReader *pDLReader){ |
| 990 int rc; |
944 pReader->pData = dlrPosData(pDLReader); | 991 pReader->pData = dlrPosData(pDLReader); |
945 pReader->nData = dlrPosDataLen(pDLReader); | 992 pReader->nData = dlrPosDataLen(pDLReader); |
946 pReader->iType = pDLReader->iType; | 993 pReader->iType = pDLReader->iType; |
947 pReader->iColumn = 0; | 994 pReader->iColumn = 0; |
948 pReader->iPosition = 0; | 995 pReader->iPosition = 0; |
949 pReader->iStartOffset = 0; | 996 pReader->iStartOffset = 0; |
950 pReader->iEndOffset = 0; | 997 pReader->iEndOffset = 0; |
951 plrStep(pReader); | 998 rc = plrStep(pReader); |
952 } | 999 if( rc!=SQLITE_OK ) plrDestroy(pReader); |
953 static void plrDestroy(PLReader *pReader){ | 1000 return rc; |
954 SCRAMBLE(pReader); | |
955 } | 1001 } |
956 | 1002 |
957 /*******************************************************************/ | 1003 /*******************************************************************/ |
958 /* PLWriter is used in constructing a document's position list. As a | 1004 /* PLWriter is used in constructing a document's position list. As a |
959 ** convenience, if iType is DL_DOCIDS, PLWriter becomes a no-op. | 1005 ** convenience, if iType is DL_DOCIDS, PLWriter becomes a no-op. |
960 ** PLWriter writes to the associated DLWriter's buffer. | 1006 ** PLWriter writes to the associated DLWriter's buffer. |
961 ** | 1007 ** |
962 ** plwInit - init for writing a document's poslist. | 1008 ** plwInit - init for writing a document's poslist. |
963 ** plwDestroy - clear a writer. | 1009 ** plwDestroy - clear a writer. |
964 ** plwAdd - append position and offset information. | 1010 ** plwAdd - append position and offset information. |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1130 /* Copy the doclist data of iType in pData/nData into *out, trimming | 1176 /* Copy the doclist data of iType in pData/nData into *out, trimming |
1131 ** unnecessary data as we go. Only columns matching iColumn are | 1177 ** unnecessary data as we go. Only columns matching iColumn are |
1132 ** copied, all columns copied if iColumn is -1. Elements with no | 1178 ** copied, all columns copied if iColumn is -1. Elements with no |
1133 ** matching columns are dropped. The output is an iOutType doclist. | 1179 ** matching columns are dropped. The output is an iOutType doclist. |
1134 */ | 1180 */ |
1135 /* NOTE(shess) This code is only valid after all doclists are merged. | 1181 /* NOTE(shess) This code is only valid after all doclists are merged. |
1136 ** If this is run before merges, then doclist items which represent | 1182 ** If this is run before merges, then doclist items which represent |
1137 ** deletion will be trimmed, and will thus not effect a deletion | 1183 ** deletion will be trimmed, and will thus not effect a deletion |
1138 ** during the merge. | 1184 ** during the merge. |
1139 */ | 1185 */ |
1140 static void docListTrim(DocListType iType, const char *pData, int nData, | 1186 static int docListTrim(DocListType iType, const char *pData, int nData, |
1141 int iColumn, DocListType iOutType, DataBuffer *out){ | 1187 int iColumn, DocListType iOutType, DataBuffer *out){ |
1142 DLReader dlReader; | 1188 DLReader dlReader; |
1143 DLWriter dlWriter; | 1189 DLWriter dlWriter; |
| 1190 int rc; |
1144 | 1191 |
1145 assert( iOutType<=iType ); | 1192 assert( iOutType<=iType ); |
1146 | 1193 |
1147 dlrInit(&dlReader, iType, pData, nData); | 1194 rc = dlrInit(&dlReader, iType, pData, nData); |
| 1195 if( rc!=SQLITE_OK ) return rc; |
1148 dlwInit(&dlWriter, iOutType, out); | 1196 dlwInit(&dlWriter, iOutType, out); |
1149 | 1197 |
1150 while( !dlrAtEnd(&dlReader) ){ | 1198 while( !dlrAtEnd(&dlReader) ){ |
1151 PLReader plReader; | 1199 PLReader plReader; |
1152 PLWriter plWriter; | 1200 PLWriter plWriter; |
1153 int match = 0; | 1201 int match = 0; |
1154 | 1202 |
1155 plrInit(&plReader, &dlReader); | 1203 rc = plrInit(&plReader, &dlReader); |
| 1204 if( rc!=SQLITE_OK ) break; |
1156 | 1205 |
1157 while( !plrAtEnd(&plReader) ){ | 1206 while( !plrAtEnd(&plReader) ){ |
1158 if( iColumn==-1 || plrColumn(&plReader)==iColumn ){ | 1207 if( iColumn==-1 || plrColumn(&plReader)==iColumn ){ |
1159 if( !match ){ | 1208 if( !match ){ |
1160 plwInit(&plWriter, &dlWriter, dlrDocid(&dlReader)); | 1209 plwInit(&plWriter, &dlWriter, dlrDocid(&dlReader)); |
1161 match = 1; | 1210 match = 1; |
1162 } | 1211 } |
1163 plwAdd(&plWriter, plrColumn(&plReader), plrPosition(&plReader), | 1212 plwAdd(&plWriter, plrColumn(&plReader), plrPosition(&plReader), |
1164 plrStartOffset(&plReader), plrEndOffset(&plReader)); | 1213 plrStartOffset(&plReader), plrEndOffset(&plReader)); |
1165 } | 1214 } |
1166 plrStep(&plReader); | 1215 rc = plrStep(&plReader); |
| 1216 if( rc!=SQLITE_OK ){ |
| 1217 plrDestroy(&plReader); |
| 1218 goto err; |
| 1219 } |
1167 } | 1220 } |
1168 if( match ){ | 1221 if( match ){ |
1169 plwTerminate(&plWriter); | 1222 plwTerminate(&plWriter); |
1170 plwDestroy(&plWriter); | 1223 plwDestroy(&plWriter); |
1171 } | 1224 } |
1172 | 1225 |
1173 plrDestroy(&plReader); | 1226 plrDestroy(&plReader); |
1174 dlrStep(&dlReader); | 1227 rc = dlrStep(&dlReader); |
| 1228 if( rc!=SQLITE_OK ) break; |
1175 } | 1229 } |
| 1230 err: |
1176 dlwDestroy(&dlWriter); | 1231 dlwDestroy(&dlWriter); |
1177 dlrDestroy(&dlReader); | 1232 dlrDestroy(&dlReader); |
| 1233 return rc; |
1178 } | 1234 } |
1179 | 1235 |
1180 /* Used by docListMerge() to keep doclists in the ascending order by | 1236 /* Used by docListMerge() to keep doclists in the ascending order by |
1181 ** docid, then ascending order by age (so the newest comes first). | 1237 ** docid, then ascending order by age (so the newest comes first). |
1182 */ | 1238 */ |
1183 typedef struct OrderedDLReader { | 1239 typedef struct OrderedDLReader { |
1184 DLReader *pReader; | 1240 DLReader *pReader; |
1185 | 1241 |
1186 /* TODO(shess) If we assume that docListMerge pReaders is ordered by | 1242 /* TODO(shess) If we assume that docListMerge pReaders is ordered by |
1187 ** age (which we do), then we could use pReader comparisons to break | 1243 ** age (which we do), then we could use pReader comparisons to break |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1224 } | 1280 } |
1225 | 1281 |
1226 /* Given an array of doclist readers, merge their doclist elements | 1282 /* Given an array of doclist readers, merge their doclist elements |
1227 ** into out in sorted order (by docid), dropping elements from older | 1283 ** into out in sorted order (by docid), dropping elements from older |
1228 ** readers when there is a duplicate docid. pReaders is assumed to be | 1284 ** readers when there is a duplicate docid. pReaders is assumed to be |
1229 ** ordered by age, oldest first. | 1285 ** ordered by age, oldest first. |
1230 */ | 1286 */ |
1231 /* TODO(shess) nReaders must be <= MERGE_COUNT. This should probably | 1287 /* TODO(shess) nReaders must be <= MERGE_COUNT. This should probably |
1232 ** be fixed. | 1288 ** be fixed. |
1233 */ | 1289 */ |
1234 static void docListMerge(DataBuffer *out, | 1290 static int docListMerge(DataBuffer *out, |
1235 DLReader *pReaders, int nReaders){ | 1291 DLReader *pReaders, int nReaders){ |
1236 OrderedDLReader readers[MERGE_COUNT]; | 1292 OrderedDLReader readers[MERGE_COUNT]; |
1237 DLWriter writer; | 1293 DLWriter writer; |
1238 int i, n; | 1294 int i, n; |
1239 const char *pStart = 0; | 1295 const char *pStart = 0; |
1240 int nStart = 0; | 1296 int nStart = 0; |
1241 sqlite_int64 iFirstDocid = 0, iLastDocid = 0; | 1297 sqlite_int64 iFirstDocid = 0, iLastDocid = 0; |
| 1298 int rc = SQLITE_OK; |
1242 | 1299 |
1243 assert( nReaders>0 ); | 1300 assert( nReaders>0 ); |
1244 if( nReaders==1 ){ | 1301 if( nReaders==1 ){ |
1245 dataBufferAppend(out, dlrDocData(pReaders), dlrAllDataBytes(pReaders)); | 1302 dataBufferAppend(out, dlrDocData(pReaders), dlrAllDataBytes(pReaders)); |
1246 return; | 1303 return SQLITE_OK; |
1247 } | 1304 } |
1248 | 1305 |
1249 assert( nReaders<=MERGE_COUNT ); | 1306 assert( nReaders<=MERGE_COUNT ); |
1250 n = 0; | 1307 n = 0; |
1251 for(i=0; i<nReaders; i++){ | 1308 for(i=0; i<nReaders; i++){ |
1252 assert( pReaders[i].iType==pReaders[0].iType ); | 1309 assert( pReaders[i].iType==pReaders[0].iType ); |
1253 readers[i].pReader = pReaders+i; | 1310 readers[i].pReader = pReaders+i; |
1254 readers[i].idx = i; | 1311 readers[i].idx = i; |
1255 n += dlrAllDataBytes(&pReaders[i]); | 1312 n += dlrAllDataBytes(&pReaders[i]); |
1256 } | 1313 } |
(...skipping 12 matching lines...) Expand all Loading... |
1269 sqlite_int64 iDocid = dlrDocid(readers[0].pReader); | 1326 sqlite_int64 iDocid = dlrDocid(readers[0].pReader); |
1270 | 1327 |
1271 /* If this is a continuation of the current buffer to copy, extend | 1328 /* If this is a continuation of the current buffer to copy, extend |
1272 ** that buffer. memcpy() seems to be more efficient if it has a | 1329 ** that buffer. memcpy() seems to be more efficient if it has a |
1273 ** lots of data to copy. | 1330 ** lots of data to copy. |
1274 */ | 1331 */ |
1275 if( dlrDocData(readers[0].pReader)==pStart+nStart ){ | 1332 if( dlrDocData(readers[0].pReader)==pStart+nStart ){ |
1276 nStart += dlrDocDataBytes(readers[0].pReader); | 1333 nStart += dlrDocDataBytes(readers[0].pReader); |
1277 }else{ | 1334 }else{ |
1278 if( pStart!=0 ){ | 1335 if( pStart!=0 ){ |
1279 dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | 1336 rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); |
| 1337 if( rc!=SQLITE_OK ) goto err; |
1280 } | 1338 } |
1281 pStart = dlrDocData(readers[0].pReader); | 1339 pStart = dlrDocData(readers[0].pReader); |
1282 nStart = dlrDocDataBytes(readers[0].pReader); | 1340 nStart = dlrDocDataBytes(readers[0].pReader); |
1283 iFirstDocid = iDocid; | 1341 iFirstDocid = iDocid; |
1284 } | 1342 } |
1285 iLastDocid = iDocid; | 1343 iLastDocid = iDocid; |
1286 dlrStep(readers[0].pReader); | 1344 rc = dlrStep(readers[0].pReader); |
| 1345 if( rc!=SQLITE_OK ) goto err; |
1287 | 1346 |
1288 /* Drop all of the older elements with the same docid. */ | 1347 /* Drop all of the older elements with the same docid. */ |
1289 for(i=1; i<nReaders && | 1348 for(i=1; i<nReaders && |
1290 !dlrAtEnd(readers[i].pReader) && | 1349 !dlrAtEnd(readers[i].pReader) && |
1291 dlrDocid(readers[i].pReader)==iDocid; i++){ | 1350 dlrDocid(readers[i].pReader)==iDocid; i++){ |
1292 dlrStep(readers[i].pReader); | 1351 rc = dlrStep(readers[i].pReader); |
| 1352 if( rc!=SQLITE_OK ) goto err; |
1293 } | 1353 } |
1294 | 1354 |
1295 /* Get the readers back into order. */ | 1355 /* Get the readers back into order. */ |
1296 while( i-->0 ){ | 1356 while( i-->0 ){ |
1297 orderedDLReaderReorder(readers+i, nReaders-i); | 1357 orderedDLReaderReorder(readers+i, nReaders-i); |
1298 } | 1358 } |
1299 } | 1359 } |
1300 | 1360 |
1301 /* Copy over any remaining elements. */ | 1361 /* Copy over any remaining elements. */ |
1302 if( nStart>0 ) dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | 1362 if( nStart>0 ) |
| 1363 rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); |
| 1364 err: |
1303 dlwDestroy(&writer); | 1365 dlwDestroy(&writer); |
| 1366 return rc; |
1304 } | 1367 } |
1305 | 1368 |
1306 /* Helper function for posListUnion(). Compares the current position | 1369 /* Helper function for posListUnion(). Compares the current position |
1307 ** between left and right, returning as standard C idiom of <0 if | 1370 ** between left and right, returning as standard C idiom of <0 if |
1308 ** left<right, >0 if left>right, and 0 if left==right. "End" always | 1371 ** left<right, >0 if left>right, and 0 if left==right. "End" always |
1309 ** compares greater. | 1372 ** compares greater. |
1310 */ | 1373 */ |
1311 static int posListCmp(PLReader *pLeft, PLReader *pRight){ | 1374 static int posListCmp(PLReader *pLeft, PLReader *pRight){ |
1312 assert( pLeft->iType==pRight->iType ); | 1375 assert( pLeft->iType==pRight->iType ); |
1313 if( pLeft->iType==DL_DOCIDS ) return 0; | 1376 if( pLeft->iType==DL_DOCIDS ) return 0; |
(...skipping 15 matching lines...) Expand all Loading... |
1329 if( plrEndOffset(pLeft)>plrEndOffset(pRight) ) return 1; | 1392 if( plrEndOffset(pLeft)>plrEndOffset(pRight) ) return 1; |
1330 | 1393 |
1331 return 0; | 1394 return 0; |
1332 } | 1395 } |
1333 | 1396 |
1334 /* Write the union of position lists in pLeft and pRight to pOut. | 1397 /* Write the union of position lists in pLeft and pRight to pOut. |
1335 ** "Union" in this case meaning "All unique position tuples". Should | 1398 ** "Union" in this case meaning "All unique position tuples". Should |
1336 ** work with any doclist type, though both inputs and the output | 1399 ** work with any doclist type, though both inputs and the output |
1337 ** should be the same type. | 1400 ** should be the same type. |
1338 */ | 1401 */ |
1339 static void posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ | 1402 static int posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ |
1340 PLReader left, right; | 1403 PLReader left, right; |
1341 PLWriter writer; | 1404 PLWriter writer; |
| 1405 int rc; |
1342 | 1406 |
1343 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); | 1407 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); |
1344 assert( pLeft->iType==pRight->iType ); | 1408 assert( pLeft->iType==pRight->iType ); |
1345 assert( pLeft->iType==pOut->iType ); | 1409 assert( pLeft->iType==pOut->iType ); |
1346 | 1410 |
1347 plrInit(&left, pLeft); | 1411 rc = plrInit(&left, pLeft); |
1348 plrInit(&right, pRight); | 1412 if( rc != SQLITE_OK ) return rc; |
| 1413 rc = plrInit(&right, pRight); |
| 1414 if( rc != SQLITE_OK ){ |
| 1415 plrDestroy(&left); |
| 1416 return rc; |
| 1417 } |
1349 plwInit(&writer, pOut, dlrDocid(pLeft)); | 1418 plwInit(&writer, pOut, dlrDocid(pLeft)); |
1350 | 1419 |
1351 while( !plrAtEnd(&left) || !plrAtEnd(&right) ){ | 1420 while( !plrAtEnd(&left) || !plrAtEnd(&right) ){ |
1352 int c = posListCmp(&left, &right); | 1421 int c = posListCmp(&left, &right); |
1353 if( c<0 ){ | 1422 if( c<0 ){ |
1354 plwCopy(&writer, &left); | 1423 plwCopy(&writer, &left); |
1355 plrStep(&left); | 1424 rc = plrStep(&left); |
| 1425 if( rc != SQLITE_OK ) break; |
1356 }else if( c>0 ){ | 1426 }else if( c>0 ){ |
1357 plwCopy(&writer, &right); | 1427 plwCopy(&writer, &right); |
1358 plrStep(&right); | 1428 rc = plrStep(&right); |
| 1429 if( rc != SQLITE_OK ) break; |
1359 }else{ | 1430 }else{ |
1360 plwCopy(&writer, &left); | 1431 plwCopy(&writer, &left); |
1361 plrStep(&left); | 1432 rc = plrStep(&left); |
1362 plrStep(&right); | 1433 if( rc != SQLITE_OK ) break; |
| 1434 rc = plrStep(&right); |
| 1435 if( rc != SQLITE_OK ) break; |
1363 } | 1436 } |
1364 } | 1437 } |
1365 | 1438 |
1366 plwTerminate(&writer); | 1439 plwTerminate(&writer); |
1367 plwDestroy(&writer); | 1440 plwDestroy(&writer); |
1368 plrDestroy(&left); | 1441 plrDestroy(&left); |
1369 plrDestroy(&right); | 1442 plrDestroy(&right); |
| 1443 return rc; |
1370 } | 1444 } |
1371 | 1445 |
1372 /* Write the union of doclists in pLeft and pRight to pOut. For | 1446 /* Write the union of doclists in pLeft and pRight to pOut. For |
1373 ** docids in common between the inputs, the union of the position | 1447 ** docids in common between the inputs, the union of the position |
1374 ** lists is written. Inputs and outputs are always type DL_DEFAULT. | 1448 ** lists is written. Inputs and outputs are always type DL_DEFAULT. |
1375 */ | 1449 */ |
1376 static void docListUnion( | 1450 static int docListUnion( |
1377 const char *pLeft, int nLeft, | 1451 const char *pLeft, int nLeft, |
1378 const char *pRight, int nRight, | 1452 const char *pRight, int nRight, |
1379 DataBuffer *pOut /* Write the combined doclist here */ | 1453 DataBuffer *pOut /* Write the combined doclist here */ |
1380 ){ | 1454 ){ |
1381 DLReader left, right; | 1455 DLReader left, right; |
1382 DLWriter writer; | 1456 DLWriter writer; |
| 1457 int rc; |
1383 | 1458 |
1384 if( nLeft==0 ){ | 1459 if( nLeft==0 ){ |
1385 if( nRight!=0) dataBufferAppend(pOut, pRight, nRight); | 1460 if( nRight!=0) dataBufferAppend(pOut, pRight, nRight); |
1386 return; | 1461 return SQLITE_OK; |
1387 } | 1462 } |
1388 if( nRight==0 ){ | 1463 if( nRight==0 ){ |
1389 dataBufferAppend(pOut, pLeft, nLeft); | 1464 dataBufferAppend(pOut, pLeft, nLeft); |
1390 return; | 1465 return SQLITE_OK; |
1391 } | 1466 } |
1392 | 1467 |
1393 dlrInit(&left, DL_DEFAULT, pLeft, nLeft); | 1468 rc = dlrInit(&left, DL_DEFAULT, pLeft, nLeft); |
1394 dlrInit(&right, DL_DEFAULT, pRight, nRight); | 1469 if( rc!=SQLITE_OK ) return rc; |
| 1470 rc = dlrInit(&right, DL_DEFAULT, pRight, nRight); |
| 1471 if( rc!=SQLITE_OK ){ |
| 1472 dlrDestroy(&left); |
| 1473 return rc; |
| 1474 } |
1395 dlwInit(&writer, DL_DEFAULT, pOut); | 1475 dlwInit(&writer, DL_DEFAULT, pOut); |
1396 | 1476 |
1397 while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ | 1477 while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ |
1398 if( dlrAtEnd(&right) ){ | 1478 if( dlrAtEnd(&right) ){ |
1399 dlwCopy(&writer, &left); | 1479 rc = dlwCopy(&writer, &left); |
1400 dlrStep(&left); | 1480 if( rc!=SQLITE_OK ) break; |
| 1481 rc = dlrStep(&left); |
| 1482 if( rc!=SQLITE_OK ) break; |
1401 }else if( dlrAtEnd(&left) ){ | 1483 }else if( dlrAtEnd(&left) ){ |
1402 dlwCopy(&writer, &right); | 1484 rc = dlwCopy(&writer, &right); |
1403 dlrStep(&right); | 1485 if( rc!=SQLITE_OK ) break; |
| 1486 rc = dlrStep(&right); |
| 1487 if( rc!=SQLITE_OK ) break; |
1404 }else if( dlrDocid(&left)<dlrDocid(&right) ){ | 1488 }else if( dlrDocid(&left)<dlrDocid(&right) ){ |
1405 dlwCopy(&writer, &left); | 1489 rc = dlwCopy(&writer, &left); |
1406 dlrStep(&left); | 1490 if( rc!=SQLITE_OK ) break; |
| 1491 rc = dlrStep(&left); |
| 1492 if( rc!=SQLITE_OK ) break; |
1407 }else if( dlrDocid(&left)>dlrDocid(&right) ){ | 1493 }else if( dlrDocid(&left)>dlrDocid(&right) ){ |
1408 dlwCopy(&writer, &right); | 1494 rc = dlwCopy(&writer, &right); |
1409 dlrStep(&right); | 1495 if( rc!=SQLITE_OK ) break; |
| 1496 rc = dlrStep(&right); |
| 1497 if( rc!=SQLITE_OK ) break; |
1410 }else{ | 1498 }else{ |
1411 posListUnion(&left, &right, &writer); | 1499 rc = posListUnion(&left, &right, &writer); |
1412 dlrStep(&left); | 1500 if( rc!=SQLITE_OK ) break; |
1413 dlrStep(&right); | 1501 rc = dlrStep(&left); |
| 1502 if( rc!=SQLITE_OK ) break; |
| 1503 rc = dlrStep(&right); |
| 1504 if( rc!=SQLITE_OK ) break; |
1414 } | 1505 } |
1415 } | 1506 } |
1416 | 1507 |
1417 dlrDestroy(&left); | 1508 dlrDestroy(&left); |
1418 dlrDestroy(&right); | 1509 dlrDestroy(&right); |
1419 dlwDestroy(&writer); | 1510 dlwDestroy(&writer); |
| 1511 return rc; |
1420 } | 1512 } |
1421 | 1513 |
1422 /* pLeft and pRight are DLReaders positioned to the same docid. | 1514 /* pLeft and pRight are DLReaders positioned to the same docid. |
1423 ** | 1515 ** |
1424 ** If there are no instances in pLeft or pRight where the position | 1516 ** If there are no instances in pLeft or pRight where the position |
1425 ** of pLeft is one less than the position of pRight, then this | 1517 ** of pLeft is one less than the position of pRight, then this |
1426 ** routine adds nothing to pOut. | 1518 ** routine adds nothing to pOut. |
1427 ** | 1519 ** |
1428 ** If there are one or more instances where positions from pLeft | 1520 ** If there are one or more instances where positions from pLeft |
1429 ** are exactly one less than positions from pRight, then add a new | 1521 ** are exactly one less than positions from pRight, then add a new |
1430 ** document record to pOut. If pOut wants to hold positions, then | 1522 ** document record to pOut. If pOut wants to hold positions, then |
1431 ** include the positions from pRight that are one more than a | 1523 ** include the positions from pRight that are one more than a |
1432 ** position in pLeft. In other words: pRight.iPos==pLeft.iPos+1. | 1524 ** position in pLeft. In other words: pRight.iPos==pLeft.iPos+1. |
1433 */ | 1525 */ |
1434 static void posListPhraseMerge(DLReader *pLeft, DLReader *pRight, | 1526 static int posListPhraseMerge(DLReader *pLeft, DLReader *pRight, |
1435 DLWriter *pOut){ | 1527 DLWriter *pOut){ |
1436 PLReader left, right; | 1528 PLReader left, right; |
1437 PLWriter writer; | 1529 PLWriter writer; |
1438 int match = 0; | 1530 int match = 0; |
| 1531 int rc; |
1439 | 1532 |
1440 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); | 1533 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); |
1441 assert( pOut->iType!=DL_POSITIONS_OFFSETS ); | 1534 assert( pOut->iType!=DL_POSITIONS_OFFSETS ); |
1442 | 1535 |
1443 plrInit(&left, pLeft); | 1536 rc = plrInit(&left, pLeft); |
1444 plrInit(&right, pRight); | 1537 if( rc!=SQLITE_OK ) return rc; |
| 1538 rc = plrInit(&right, pRight); |
| 1539 if( rc!=SQLITE_OK ){ |
| 1540 plrDestroy(&left); |
| 1541 return rc; |
| 1542 } |
1445 | 1543 |
1446 while( !plrAtEnd(&left) && !plrAtEnd(&right) ){ | 1544 while( !plrAtEnd(&left) && !plrAtEnd(&right) ){ |
1447 if( plrColumn(&left)<plrColumn(&right) ){ | 1545 if( plrColumn(&left)<plrColumn(&right) ){ |
1448 plrStep(&left); | 1546 rc = plrStep(&left); |
| 1547 if( rc!=SQLITE_OK ) break; |
1449 }else if( plrColumn(&left)>plrColumn(&right) ){ | 1548 }else if( plrColumn(&left)>plrColumn(&right) ){ |
1450 plrStep(&right); | 1549 rc = plrStep(&right); |
| 1550 if( rc!=SQLITE_OK ) break; |
1451 }else if( plrPosition(&left)+1<plrPosition(&right) ){ | 1551 }else if( plrPosition(&left)+1<plrPosition(&right) ){ |
1452 plrStep(&left); | 1552 rc = plrStep(&left); |
| 1553 if( rc!=SQLITE_OK ) break; |
1453 }else if( plrPosition(&left)+1>plrPosition(&right) ){ | 1554 }else if( plrPosition(&left)+1>plrPosition(&right) ){ |
1454 plrStep(&right); | 1555 rc = plrStep(&right); |
| 1556 if( rc!=SQLITE_OK ) break; |
1455 }else{ | 1557 }else{ |
1456 if( !match ){ | 1558 if( !match ){ |
1457 plwInit(&writer, pOut, dlrDocid(pLeft)); | 1559 plwInit(&writer, pOut, dlrDocid(pLeft)); |
1458 match = 1; | 1560 match = 1; |
1459 } | 1561 } |
1460 plwAdd(&writer, plrColumn(&right), plrPosition(&right), 0, 0); | 1562 plwAdd(&writer, plrColumn(&right), plrPosition(&right), 0, 0); |
1461 plrStep(&left); | 1563 rc = plrStep(&left); |
1462 plrStep(&right); | 1564 if( rc!=SQLITE_OK ) break; |
| 1565 rc = plrStep(&right); |
| 1566 if( rc!=SQLITE_OK ) break; |
1463 } | 1567 } |
1464 } | 1568 } |
1465 | 1569 |
1466 if( match ){ | 1570 if( match ){ |
1467 plwTerminate(&writer); | 1571 plwTerminate(&writer); |
1468 plwDestroy(&writer); | 1572 plwDestroy(&writer); |
1469 } | 1573 } |
1470 | 1574 |
1471 plrDestroy(&left); | 1575 plrDestroy(&left); |
1472 plrDestroy(&right); | 1576 plrDestroy(&right); |
| 1577 return rc; |
1473 } | 1578 } |
1474 | 1579 |
1475 /* We have two doclists with positions: pLeft and pRight. | 1580 /* We have two doclists with positions: pLeft and pRight. |
1476 ** Write the phrase intersection of these two doclists into pOut. | 1581 ** Write the phrase intersection of these two doclists into pOut. |
1477 ** | 1582 ** |
1478 ** A phrase intersection means that two documents only match | 1583 ** A phrase intersection means that two documents only match |
1479 ** if pLeft.iPos+1==pRight.iPos. | 1584 ** if pLeft.iPos+1==pRight.iPos. |
1480 ** | 1585 ** |
1481 ** iType controls the type of data written to pOut. If iType is | 1586 ** iType controls the type of data written to pOut. If iType is |
1482 ** DL_POSITIONS, the positions are those from pRight. | 1587 ** DL_POSITIONS, the positions are those from pRight. |
1483 */ | 1588 */ |
1484 static void docListPhraseMerge( | 1589 static int docListPhraseMerge( |
1485 const char *pLeft, int nLeft, | 1590 const char *pLeft, int nLeft, |
1486 const char *pRight, int nRight, | 1591 const char *pRight, int nRight, |
1487 DocListType iType, | 1592 DocListType iType, |
1488 DataBuffer *pOut /* Write the combined doclist here */ | 1593 DataBuffer *pOut /* Write the combined doclist here */ |
1489 ){ | 1594 ){ |
1490 DLReader left, right; | 1595 DLReader left, right; |
1491 DLWriter writer; | 1596 DLWriter writer; |
| 1597 int rc; |
1492 | 1598 |
1493 if( nLeft==0 || nRight==0 ) return; | 1599 if( nLeft==0 || nRight==0 ) return SQLITE_OK; |
1494 | 1600 |
1495 assert( iType!=DL_POSITIONS_OFFSETS ); | 1601 assert( iType!=DL_POSITIONS_OFFSETS ); |
1496 | 1602 |
1497 dlrInit(&left, DL_POSITIONS, pLeft, nLeft); | 1603 rc = dlrInit(&left, DL_POSITIONS, pLeft, nLeft); |
1498 dlrInit(&right, DL_POSITIONS, pRight, nRight); | 1604 if( rc!=SQLITE_OK ) return rc; |
| 1605 rc = dlrInit(&right, DL_POSITIONS, pRight, nRight); |
| 1606 if( rc!=SQLITE_OK ){ |
| 1607 dlrDestroy(&left); |
| 1608 return rc; |
| 1609 } |
1499 dlwInit(&writer, iType, pOut); | 1610 dlwInit(&writer, iType, pOut); |
1500 | 1611 |
1501 while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ | 1612 while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ |
1502 if( dlrDocid(&left)<dlrDocid(&right) ){ | 1613 if( dlrDocid(&left)<dlrDocid(&right) ){ |
1503 dlrStep(&left); | 1614 rc = dlrStep(&left); |
| 1615 if( rc!=SQLITE_OK ) break; |
1504 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | 1616 }else if( dlrDocid(&right)<dlrDocid(&left) ){ |
1505 dlrStep(&right); | 1617 rc = dlrStep(&right); |
| 1618 if( rc!=SQLITE_OK ) break; |
1506 }else{ | 1619 }else{ |
1507 posListPhraseMerge(&left, &right, &writer); | 1620 rc = posListPhraseMerge(&left, &right, &writer); |
1508 dlrStep(&left); | 1621 if( rc!=SQLITE_OK ) break; |
1509 dlrStep(&right); | 1622 rc = dlrStep(&left); |
| 1623 if( rc!=SQLITE_OK ) break; |
| 1624 rc = dlrStep(&right); |
| 1625 if( rc!=SQLITE_OK ) break; |
1510 } | 1626 } |
1511 } | 1627 } |
1512 | 1628 |
1513 dlrDestroy(&left); | 1629 dlrDestroy(&left); |
1514 dlrDestroy(&right); | 1630 dlrDestroy(&right); |
1515 dlwDestroy(&writer); | 1631 dlwDestroy(&writer); |
| 1632 return rc; |
1516 } | 1633 } |
1517 | 1634 |
1518 /* We have two DL_DOCIDS doclists: pLeft and pRight. | 1635 /* We have two DL_DOCIDS doclists: pLeft and pRight. |
1519 ** Write the intersection of these two doclists into pOut as a | 1636 ** Write the intersection of these two doclists into pOut as a |
1520 ** DL_DOCIDS doclist. | 1637 ** DL_DOCIDS doclist. |
1521 */ | 1638 */ |
1522 static void docListAndMerge( | 1639 static int docListAndMerge( |
1523 const char *pLeft, int nLeft, | 1640 const char *pLeft, int nLeft, |
1524 const char *pRight, int nRight, | 1641 const char *pRight, int nRight, |
1525 DataBuffer *pOut /* Write the combined doclist here */ | 1642 DataBuffer *pOut /* Write the combined doclist here */ |
1526 ){ | 1643 ){ |
1527 DLReader left, right; | 1644 DLReader left, right; |
1528 DLWriter writer; | 1645 DLWriter writer; |
| 1646 int rc; |
1529 | 1647 |
1530 if( nLeft==0 || nRight==0 ) return; | 1648 if( nLeft==0 || nRight==0 ) return SQLITE_OK; |
1531 | 1649 |
1532 dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | 1650 rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); |
1533 dlrInit(&right, DL_DOCIDS, pRight, nRight); | 1651 if( rc!=SQLITE_OK ) return rc; |
| 1652 rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); |
| 1653 if( rc!=SQLITE_OK ){ |
| 1654 dlrDestroy(&left); |
| 1655 return rc; |
| 1656 } |
1534 dlwInit(&writer, DL_DOCIDS, pOut); | 1657 dlwInit(&writer, DL_DOCIDS, pOut); |
1535 | 1658 |
1536 while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ | 1659 while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ |
1537 if( dlrDocid(&left)<dlrDocid(&right) ){ | 1660 if( dlrDocid(&left)<dlrDocid(&right) ){ |
1538 dlrStep(&left); | 1661 rc = dlrStep(&left); |
| 1662 if( rc!=SQLITE_OK ) break; |
1539 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | 1663 }else if( dlrDocid(&right)<dlrDocid(&left) ){ |
1540 dlrStep(&right); | 1664 rc = dlrStep(&right); |
| 1665 if( rc!=SQLITE_OK ) break; |
1541 }else{ | 1666 }else{ |
1542 dlwAdd(&writer, dlrDocid(&left)); | 1667 dlwAdd(&writer, dlrDocid(&left)); |
1543 dlrStep(&left); | 1668 rc = dlrStep(&left); |
1544 dlrStep(&right); | 1669 if( rc!=SQLITE_OK ) break; |
| 1670 rc = dlrStep(&right); |
| 1671 if( rc!=SQLITE_OK ) break; |
1545 } | 1672 } |
1546 } | 1673 } |
1547 | 1674 |
1548 dlrDestroy(&left); | 1675 dlrDestroy(&left); |
1549 dlrDestroy(&right); | 1676 dlrDestroy(&right); |
1550 dlwDestroy(&writer); | 1677 dlwDestroy(&writer); |
| 1678 return rc; |
1551 } | 1679 } |
1552 | 1680 |
1553 /* We have two DL_DOCIDS doclists: pLeft and pRight. | 1681 /* We have two DL_DOCIDS doclists: pLeft and pRight. |
1554 ** Write the union of these two doclists into pOut as a | 1682 ** Write the union of these two doclists into pOut as a |
1555 ** DL_DOCIDS doclist. | 1683 ** DL_DOCIDS doclist. |
1556 */ | 1684 */ |
1557 static void docListOrMerge( | 1685 static int docListOrMerge( |
1558 const char *pLeft, int nLeft, | 1686 const char *pLeft, int nLeft, |
1559 const char *pRight, int nRight, | 1687 const char *pRight, int nRight, |
1560 DataBuffer *pOut /* Write the combined doclist here */ | 1688 DataBuffer *pOut /* Write the combined doclist here */ |
1561 ){ | 1689 ){ |
1562 DLReader left, right; | 1690 DLReader left, right; |
1563 DLWriter writer; | 1691 DLWriter writer; |
| 1692 int rc; |
1564 | 1693 |
1565 if( nLeft==0 ){ | 1694 if( nLeft==0 ){ |
1566 if( nRight!=0 ) dataBufferAppend(pOut, pRight, nRight); | 1695 if( nRight!=0 ) dataBufferAppend(pOut, pRight, nRight); |
1567 return; | 1696 return SQLITE_OK; |
1568 } | 1697 } |
1569 if( nRight==0 ){ | 1698 if( nRight==0 ){ |
1570 dataBufferAppend(pOut, pLeft, nLeft); | 1699 dataBufferAppend(pOut, pLeft, nLeft); |
1571 return; | 1700 return SQLITE_OK; |
1572 } | 1701 } |
1573 | 1702 |
1574 dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | 1703 rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); |
1575 dlrInit(&right, DL_DOCIDS, pRight, nRight); | 1704 if( rc!=SQLITE_OK ) return rc; |
| 1705 rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); |
| 1706 if( rc!=SQLITE_OK ){ |
| 1707 dlrDestroy(&left); |
| 1708 return rc; |
| 1709 } |
1576 dlwInit(&writer, DL_DOCIDS, pOut); | 1710 dlwInit(&writer, DL_DOCIDS, pOut); |
1577 | 1711 |
1578 while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ | 1712 while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ |
1579 if( dlrAtEnd(&right) ){ | 1713 if( dlrAtEnd(&right) ){ |
1580 dlwAdd(&writer, dlrDocid(&left)); | 1714 dlwAdd(&writer, dlrDocid(&left)); |
1581 dlrStep(&left); | 1715 rc = dlrStep(&left); |
| 1716 if( rc!=SQLITE_OK ) break; |
1582 }else if( dlrAtEnd(&left) ){ | 1717 }else if( dlrAtEnd(&left) ){ |
1583 dlwAdd(&writer, dlrDocid(&right)); | 1718 dlwAdd(&writer, dlrDocid(&right)); |
1584 dlrStep(&right); | 1719 rc = dlrStep(&right); |
| 1720 if( rc!=SQLITE_OK ) break; |
1585 }else if( dlrDocid(&left)<dlrDocid(&right) ){ | 1721 }else if( dlrDocid(&left)<dlrDocid(&right) ){ |
1586 dlwAdd(&writer, dlrDocid(&left)); | 1722 dlwAdd(&writer, dlrDocid(&left)); |
1587 dlrStep(&left); | 1723 rc = dlrStep(&left); |
| 1724 if( rc!=SQLITE_OK ) break; |
1588 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | 1725 }else if( dlrDocid(&right)<dlrDocid(&left) ){ |
1589 dlwAdd(&writer, dlrDocid(&right)); | 1726 dlwAdd(&writer, dlrDocid(&right)); |
1590 dlrStep(&right); | 1727 rc = dlrStep(&right); |
| 1728 if( rc!=SQLITE_OK ) break; |
1591 }else{ | 1729 }else{ |
1592 dlwAdd(&writer, dlrDocid(&left)); | 1730 dlwAdd(&writer, dlrDocid(&left)); |
1593 dlrStep(&left); | 1731 rc = dlrStep(&left); |
1594 dlrStep(&right); | 1732 if( rc!=SQLITE_OK ) break; |
| 1733 rc = dlrStep(&right); |
| 1734 if( rc!=SQLITE_OK ) break; |
1595 } | 1735 } |
1596 } | 1736 } |
1597 | 1737 |
1598 dlrDestroy(&left); | 1738 dlrDestroy(&left); |
1599 dlrDestroy(&right); | 1739 dlrDestroy(&right); |
1600 dlwDestroy(&writer); | 1740 dlwDestroy(&writer); |
| 1741 return rc; |
1601 } | 1742 } |
1602 | 1743 |
1603 /* We have two DL_DOCIDS doclists: pLeft and pRight. | 1744 /* We have two DL_DOCIDS doclists: pLeft and pRight. |
1604 ** Write into pOut as DL_DOCIDS doclist containing all documents that | 1745 ** Write into pOut as DL_DOCIDS doclist containing all documents that |
1605 ** occur in pLeft but not in pRight. | 1746 ** occur in pLeft but not in pRight. |
1606 */ | 1747 */ |
1607 static void docListExceptMerge( | 1748 static int docListExceptMerge( |
1608 const char *pLeft, int nLeft, | 1749 const char *pLeft, int nLeft, |
1609 const char *pRight, int nRight, | 1750 const char *pRight, int nRight, |
1610 DataBuffer *pOut /* Write the combined doclist here */ | 1751 DataBuffer *pOut /* Write the combined doclist here */ |
1611 ){ | 1752 ){ |
1612 DLReader left, right; | 1753 DLReader left, right; |
1613 DLWriter writer; | 1754 DLWriter writer; |
| 1755 int rc; |
1614 | 1756 |
1615 if( nLeft==0 ) return; | 1757 if( nLeft==0 ) return SQLITE_OK; |
1616 if( nRight==0 ){ | 1758 if( nRight==0 ){ |
1617 dataBufferAppend(pOut, pLeft, nLeft); | 1759 dataBufferAppend(pOut, pLeft, nLeft); |
1618 return; | 1760 return SQLITE_OK; |
1619 } | 1761 } |
1620 | 1762 |
1621 dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | 1763 rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); |
1622 dlrInit(&right, DL_DOCIDS, pRight, nRight); | 1764 if( rc!=SQLITE_OK ) return rc; |
| 1765 rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); |
| 1766 if( rc!=SQLITE_OK ){ |
| 1767 dlrDestroy(&left); |
| 1768 return rc; |
| 1769 } |
1623 dlwInit(&writer, DL_DOCIDS, pOut); | 1770 dlwInit(&writer, DL_DOCIDS, pOut); |
1624 | 1771 |
1625 while( !dlrAtEnd(&left) ){ | 1772 while( !dlrAtEnd(&left) ){ |
1626 while( !dlrAtEnd(&right) && dlrDocid(&right)<dlrDocid(&left) ){ | 1773 while( !dlrAtEnd(&right) && dlrDocid(&right)<dlrDocid(&left) ){ |
1627 dlrStep(&right); | 1774 rc = dlrStep(&right); |
| 1775 if( rc!=SQLITE_OK ) goto err; |
1628 } | 1776 } |
1629 if( dlrAtEnd(&right) || dlrDocid(&left)<dlrDocid(&right) ){ | 1777 if( dlrAtEnd(&right) || dlrDocid(&left)<dlrDocid(&right) ){ |
1630 dlwAdd(&writer, dlrDocid(&left)); | 1778 dlwAdd(&writer, dlrDocid(&left)); |
1631 } | 1779 } |
1632 dlrStep(&left); | 1780 rc = dlrStep(&left); |
| 1781 if( rc!=SQLITE_OK ) break; |
1633 } | 1782 } |
1634 | 1783 |
| 1784 err: |
1635 dlrDestroy(&left); | 1785 dlrDestroy(&left); |
1636 dlrDestroy(&right); | 1786 dlrDestroy(&right); |
1637 dlwDestroy(&writer); | 1787 dlwDestroy(&writer); |
| 1788 return rc; |
1638 } | 1789 } |
1639 | 1790 |
1640 static char *string_dup_n(const char *s, int n){ | 1791 static char *string_dup_n(const char *s, int n){ |
1641 char *str = sqlite3_malloc(n + 1); | 1792 char *str = sqlite3_malloc(n + 1); |
1642 memcpy(str, s, n); | 1793 memcpy(str, s, n); |
1643 str[n] = '\0'; | 1794 str[n] = '\0'; |
1644 return str; | 1795 return str; |
1645 } | 1796 } |
1646 | 1797 |
1647 /* Duplicate a string; the caller must free() the returned string. | 1798 /* Duplicate a string; the caller must free() the returned string. |
(...skipping 1782 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3430 } | 3581 } |
3431 } else { /* full-text query */ | 3582 } else { /* full-text query */ |
3432 rc = sqlite3_reset(c->pStmt); | 3583 rc = sqlite3_reset(c->pStmt); |
3433 if( rc!=SQLITE_OK ) return rc; | 3584 if( rc!=SQLITE_OK ) return rc; |
3434 | 3585 |
3435 if( c->result.nData==0 || dlrAtEnd(&c->reader) ){ | 3586 if( c->result.nData==0 || dlrAtEnd(&c->reader) ){ |
3436 c->eof = 1; | 3587 c->eof = 1; |
3437 return SQLITE_OK; | 3588 return SQLITE_OK; |
3438 } | 3589 } |
3439 rc = sqlite3_bind_int64(c->pStmt, 1, dlrDocid(&c->reader)); | 3590 rc = sqlite3_bind_int64(c->pStmt, 1, dlrDocid(&c->reader)); |
3440 dlrStep(&c->reader); | 3591 if( rc!=SQLITE_OK ) return rc; |
| 3592 rc = dlrStep(&c->reader); |
3441 if( rc!=SQLITE_OK ) return rc; | 3593 if( rc!=SQLITE_OK ) return rc; |
3442 /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ | 3594 /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ |
3443 rc = sqlite3_step(c->pStmt); | 3595 rc = sqlite3_step(c->pStmt); |
3444 if( rc==SQLITE_ROW ){ /* the case we expect */ | 3596 if( rc==SQLITE_ROW ){ /* the case we expect */ |
3445 c->eof = 0; | 3597 c->eof = 0; |
3446 return SQLITE_OK; | 3598 return SQLITE_OK; |
3447 } | 3599 } |
3448 | 3600 |
3449 /* Corrupt if the index refers to missing document. */ | 3601 /* Corrupt if the index refers to missing document. */ |
3450 if( rc==SQLITE_DONE ) return SQLITE_CORRUPT_BKPT; | 3602 if( rc==SQLITE_DONE ) return SQLITE_CORRUPT_BKPT; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3490 if( rc ) return rc; | 3642 if( rc ) return rc; |
3491 for(i=1; i<=pQTerm->nPhrase && left.nData>0; i++){ | 3643 for(i=1; i<=pQTerm->nPhrase && left.nData>0; i++){ |
3492 dataBufferInit(&right, 0); | 3644 dataBufferInit(&right, 0); |
3493 rc = termSelect(v, iColumn, pQTerm[i].pTerm, pQTerm[i].nTerm, | 3645 rc = termSelect(v, iColumn, pQTerm[i].pTerm, pQTerm[i].nTerm, |
3494 pQTerm[i].isPrefix, DL_POSITIONS, &right); | 3646 pQTerm[i].isPrefix, DL_POSITIONS, &right); |
3495 if( rc ){ | 3647 if( rc ){ |
3496 dataBufferDestroy(&left); | 3648 dataBufferDestroy(&left); |
3497 return rc; | 3649 return rc; |
3498 } | 3650 } |
3499 dataBufferInit(&new, 0); | 3651 dataBufferInit(&new, 0); |
3500 docListPhraseMerge(left.pData, left.nData, right.pData, right.nData, | 3652 rc = docListPhraseMerge(left.pData, left.nData, right.pData, right.nData, |
3501 i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &new); | 3653 i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &new); |
3502 dataBufferDestroy(&left); | 3654 dataBufferDestroy(&left); |
3503 dataBufferDestroy(&right); | 3655 dataBufferDestroy(&right); |
| 3656 if( rc!=SQLITE_OK ){ |
| 3657 dataBufferDestroy(&new); |
| 3658 return rc; |
| 3659 } |
3504 left = new; | 3660 left = new; |
3505 } | 3661 } |
3506 *pResult = left; | 3662 *pResult = left; |
3507 return SQLITE_OK; | 3663 return rc; |
3508 } | 3664 } |
3509 | 3665 |
3510 /* Add a new term pTerm[0..nTerm-1] to the query *q. | 3666 /* Add a new term pTerm[0..nTerm-1] to the query *q. |
3511 */ | 3667 */ |
3512 static void queryAdd(Query *q, const char *pTerm, int nTerm){ | 3668 static void queryAdd(Query *q, const char *pTerm, int nTerm){ |
3513 QueryTerm *t; | 3669 QueryTerm *t; |
3514 ++q->nTerms; | 3670 ++q->nTerms; |
3515 q->pTerms = sqlite3_realloc(q->pTerms, q->nTerms * sizeof(q->pTerms[0])); | 3671 q->pTerms = sqlite3_realloc(q->pTerms, q->nTerms * sizeof(q->pTerms[0])); |
3516 if( q->pTerms==0 ){ | 3672 if( q->pTerms==0 ){ |
3517 q->nTerms = 0; | 3673 q->nTerms = 0; |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3742 while( iNext<pQuery->nTerms && aTerm[iNext].isOr ){ | 3898 while( iNext<pQuery->nTerms && aTerm[iNext].isOr ){ |
3743 rc = docListOfTerm(v, aTerm[iNext].iColumn, &aTerm[iNext], &or); | 3899 rc = docListOfTerm(v, aTerm[iNext].iColumn, &aTerm[iNext], &or); |
3744 iNext += aTerm[iNext].nPhrase + 1; | 3900 iNext += aTerm[iNext].nPhrase + 1; |
3745 if( rc ){ | 3901 if( rc ){ |
3746 if( i!=nNot ) dataBufferDestroy(&left); | 3902 if( i!=nNot ) dataBufferDestroy(&left); |
3747 dataBufferDestroy(&right); | 3903 dataBufferDestroy(&right); |
3748 queryClear(pQuery); | 3904 queryClear(pQuery); |
3749 return rc; | 3905 return rc; |
3750 } | 3906 } |
3751 dataBufferInit(&new, 0); | 3907 dataBufferInit(&new, 0); |
3752 docListOrMerge(right.pData, right.nData, or.pData, or.nData, &new); | 3908 rc = docListOrMerge(right.pData, right.nData, or.pData, or.nData, &new); |
3753 dataBufferDestroy(&right); | 3909 dataBufferDestroy(&right); |
3754 dataBufferDestroy(&or); | 3910 dataBufferDestroy(&or); |
| 3911 if( rc!=SQLITE_OK ){ |
| 3912 if( i!=nNot ) dataBufferDestroy(&left); |
| 3913 queryClear(pQuery); |
| 3914 dataBufferDestroy(&new); |
| 3915 return rc; |
| 3916 } |
3755 right = new; | 3917 right = new; |
3756 } | 3918 } |
3757 if( i==nNot ){ /* first term processed. */ | 3919 if( i==nNot ){ /* first term processed. */ |
3758 left = right; | 3920 left = right; |
3759 }else{ | 3921 }else{ |
3760 dataBufferInit(&new, 0); | 3922 dataBufferInit(&new, 0); |
3761 docListAndMerge(left.pData, left.nData, right.pData, right.nData, &new); | 3923 rc = docListAndMerge(left.pData, left.nData, |
| 3924 right.pData, right.nData, &new); |
3762 dataBufferDestroy(&right); | 3925 dataBufferDestroy(&right); |
3763 dataBufferDestroy(&left); | 3926 dataBufferDestroy(&left); |
| 3927 if( rc!=SQLITE_OK ){ |
| 3928 queryClear(pQuery); |
| 3929 dataBufferDestroy(&new); |
| 3930 return rc; |
| 3931 } |
3764 left = new; | 3932 left = new; |
3765 } | 3933 } |
3766 } | 3934 } |
3767 | 3935 |
3768 if( nNot==pQuery->nTerms ){ | 3936 if( nNot==pQuery->nTerms ){ |
3769 /* We do not yet know how to handle a query of only NOT terms */ | 3937 /* We do not yet know how to handle a query of only NOT terms */ |
3770 return SQLITE_ERROR; | 3938 return SQLITE_ERROR; |
3771 } | 3939 } |
3772 | 3940 |
3773 /* Do the EXCEPT terms */ | 3941 /* Do the EXCEPT terms */ |
3774 for(i=0; i<pQuery->nTerms; i += aTerm[i].nPhrase + 1){ | 3942 for(i=0; i<pQuery->nTerms; i += aTerm[i].nPhrase + 1){ |
3775 if( !aTerm[i].isNot ) continue; | 3943 if( !aTerm[i].isNot ) continue; |
3776 rc = docListOfTerm(v, aTerm[i].iColumn, &aTerm[i], &right); | 3944 rc = docListOfTerm(v, aTerm[i].iColumn, &aTerm[i], &right); |
3777 if( rc ){ | 3945 if( rc ){ |
3778 queryClear(pQuery); | 3946 queryClear(pQuery); |
3779 dataBufferDestroy(&left); | 3947 dataBufferDestroy(&left); |
3780 return rc; | 3948 return rc; |
3781 } | 3949 } |
3782 dataBufferInit(&new, 0); | 3950 dataBufferInit(&new, 0); |
3783 docListExceptMerge(left.pData, left.nData, right.pData, right.nData, &new); | 3951 rc = docListExceptMerge(left.pData, left.nData, |
| 3952 right.pData, right.nData, &new); |
3784 dataBufferDestroy(&right); | 3953 dataBufferDestroy(&right); |
3785 dataBufferDestroy(&left); | 3954 dataBufferDestroy(&left); |
| 3955 if( rc!=SQLITE_OK ){ |
| 3956 queryClear(pQuery); |
| 3957 dataBufferDestroy(&new); |
| 3958 return rc; |
| 3959 } |
3786 left = new; | 3960 left = new; |
3787 } | 3961 } |
3788 | 3962 |
3789 *pResult = left; | 3963 *pResult = left; |
3790 return rc; | 3964 return rc; |
3791 } | 3965 } |
3792 | 3966 |
3793 /* | 3967 /* |
3794 ** This is the xFilter interface for the virtual table. See | 3968 ** This is the xFilter interface for the virtual table. See |
3795 ** the virtual table xFilter method documentation for additional | 3969 ** the virtual table xFilter method documentation for additional |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3869 if( c->result.nData!=0 ){ | 4043 if( c->result.nData!=0 ){ |
3870 /* This case happens if the same cursor is used repeatedly. */ | 4044 /* This case happens if the same cursor is used repeatedly. */ |
3871 dlrDestroy(&c->reader); | 4045 dlrDestroy(&c->reader); |
3872 dataBufferReset(&c->result); | 4046 dataBufferReset(&c->result); |
3873 }else{ | 4047 }else{ |
3874 dataBufferInit(&c->result, 0); | 4048 dataBufferInit(&c->result, 0); |
3875 } | 4049 } |
3876 rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &c->result, &c->q
); | 4050 rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &c->result, &c->q
); |
3877 if( rc!=SQLITE_OK ) return rc; | 4051 if( rc!=SQLITE_OK ) return rc; |
3878 if( c->result.nData!=0 ){ | 4052 if( c->result.nData!=0 ){ |
3879 dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData); | 4053 rc = dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData); |
| 4054 if( rc!=SQLITE_OK ) return rc; |
3880 } | 4055 } |
3881 break; | 4056 break; |
3882 } | 4057 } |
3883 } | 4058 } |
3884 | 4059 |
3885 return fulltextNext(pCursor); | 4060 return fulltextNext(pCursor); |
3886 } | 4061 } |
3887 | 4062 |
3888 /* This is the xEof method of the virtual table. The SQLite core | 4063 /* This is the xEof method of the virtual table. The SQLite core |
3889 ** calls this routine to find out if it has reached the end of | 4064 ** calls this routine to find out if it has reached the end of |
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4370 DataBuffer term; /* previous term, for decoding term delta. */ | 4545 DataBuffer term; /* previous term, for decoding term delta. */ |
4371 | 4546 |
4372 sqlite_int64 iBlockid; | 4547 sqlite_int64 iBlockid; |
4373 } InteriorReader; | 4548 } InteriorReader; |
4374 | 4549 |
4375 static void interiorReaderDestroy(InteriorReader *pReader){ | 4550 static void interiorReaderDestroy(InteriorReader *pReader){ |
4376 dataBufferDestroy(&pReader->term); | 4551 dataBufferDestroy(&pReader->term); |
4377 SCRAMBLE(pReader); | 4552 SCRAMBLE(pReader); |
4378 } | 4553 } |
4379 | 4554 |
4380 /* TODO(shess) The assertions are great, but what if we're in NDEBUG | 4555 static int interiorReaderInit(const char *pData, int nData, |
4381 ** and the blob is empty or otherwise contains suspect data? | 4556 InteriorReader *pReader){ |
4382 */ | |
4383 static void interiorReaderInit(const char *pData, int nData, | |
4384 InteriorReader *pReader){ | |
4385 int n, nTerm; | 4557 int n, nTerm; |
4386 | 4558 |
4387 /* Require at least the leading flag byte */ | 4559 /* These conditions are checked and met by the callers. */ |
4388 assert( nData>0 ); | 4560 assert( nData>0 ); |
4389 assert( pData[0]!='\0' ); | 4561 assert( pData[0]!='\0' ); |
4390 | 4562 |
4391 CLEAR(pReader); | 4563 CLEAR(pReader); |
4392 | 4564 |
4393 /* Decode the base blockid, and set the cursor to the first term. */ | 4565 /* Decode the base blockid, and set the cursor to the first term. */ |
4394 n = getVarint(pData+1, &pReader->iBlockid); | 4566 n = getVarintSafe(pData+1, &pReader->iBlockid, nData-1); |
4395 assert( 1+n<=nData ); | 4567 if( !n ) return SQLITE_CORRUPT_BKPT; |
4396 pReader->pData = pData+1+n; | 4568 pReader->pData = pData+1+n; |
4397 pReader->nData = nData-(1+n); | 4569 pReader->nData = nData-(1+n); |
4398 | 4570 |
4399 /* A single-child interior node (such as when a leaf node was too | 4571 /* A single-child interior node (such as when a leaf node was too |
4400 ** large for the segment directory) won't have any terms. | 4572 ** large for the segment directory) won't have any terms. |
4401 ** Otherwise, decode the first term. | 4573 ** Otherwise, decode the first term. |
4402 */ | 4574 */ |
4403 if( pReader->nData==0 ){ | 4575 if( pReader->nData==0 ){ |
4404 dataBufferInit(&pReader->term, 0); | 4576 dataBufferInit(&pReader->term, 0); |
4405 }else{ | 4577 }else{ |
4406 n = getVarint32(pReader->pData, &nTerm); | 4578 n = getVarint32Safe(pReader->pData, &nTerm, pReader->nData); |
| 4579 if( !n || nTerm<0 || nTerm>pReader->nData-n) return SQLITE_CORRUPT_BKPT; |
4407 dataBufferInit(&pReader->term, nTerm); | 4580 dataBufferInit(&pReader->term, nTerm); |
4408 dataBufferReplace(&pReader->term, pReader->pData+n, nTerm); | 4581 dataBufferReplace(&pReader->term, pReader->pData+n, nTerm); |
4409 assert( n+nTerm<=pReader->nData ); | |
4410 pReader->pData += n+nTerm; | 4582 pReader->pData += n+nTerm; |
4411 pReader->nData -= n+nTerm; | 4583 pReader->nData -= n+nTerm; |
4412 } | 4584 } |
| 4585 return SQLITE_OK; |
4413 } | 4586 } |
4414 | 4587 |
4415 static int interiorReaderAtEnd(InteriorReader *pReader){ | 4588 static int interiorReaderAtEnd(InteriorReader *pReader){ |
4416 return pReader->term.nData==0; | 4589 return pReader->term.nData<=0; |
4417 } | 4590 } |
4418 | 4591 |
4419 static sqlite_int64 interiorReaderCurrentBlockid(InteriorReader *pReader){ | 4592 static sqlite_int64 interiorReaderCurrentBlockid(InteriorReader *pReader){ |
4420 return pReader->iBlockid; | 4593 return pReader->iBlockid; |
4421 } | 4594 } |
4422 | 4595 |
4423 static int interiorReaderTermBytes(InteriorReader *pReader){ | 4596 static int interiorReaderTermBytes(InteriorReader *pReader){ |
4424 assert( !interiorReaderAtEnd(pReader) ); | 4597 assert( !interiorReaderAtEnd(pReader) ); |
4425 return pReader->term.nData; | 4598 return pReader->term.nData; |
4426 } | 4599 } |
4427 static const char *interiorReaderTerm(InteriorReader *pReader){ | 4600 static const char *interiorReaderTerm(InteriorReader *pReader){ |
4428 assert( !interiorReaderAtEnd(pReader) ); | 4601 assert( !interiorReaderAtEnd(pReader) ); |
4429 return pReader->term.pData; | 4602 return pReader->term.pData; |
4430 } | 4603 } |
4431 | 4604 |
4432 /* Step forward to the next term in the node. */ | 4605 /* Step forward to the next term in the node. */ |
4433 static void interiorReaderStep(InteriorReader *pReader){ | 4606 static int interiorReaderStep(InteriorReader *pReader){ |
4434 assert( !interiorReaderAtEnd(pReader) ); | 4607 assert( !interiorReaderAtEnd(pReader) ); |
4435 | 4608 |
4436 /* If the last term has been read, signal eof, else construct the | 4609 /* If the last term has been read, signal eof, else construct the |
4437 ** next term. | 4610 ** next term. |
4438 */ | 4611 */ |
4439 if( pReader->nData==0 ){ | 4612 if( pReader->nData==0 ){ |
4440 dataBufferReset(&pReader->term); | 4613 dataBufferReset(&pReader->term); |
4441 }else{ | 4614 }else{ |
4442 int n, nPrefix, nSuffix; | 4615 int n, nPrefix, nSuffix; |
4443 | 4616 |
4444 n = getVarint32(pReader->pData, &nPrefix); | 4617 n = getVarint32Safe(pReader->pData, &nPrefix, pReader->nData); |
4445 n += getVarint32(pReader->pData+n, &nSuffix); | 4618 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 4619 pReader->nData -= n; |
| 4620 pReader->pData += n; |
| 4621 n = getVarint32Safe(pReader->pData, &nSuffix, pReader->nData); |
| 4622 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 4623 pReader->nData -= n; |
| 4624 pReader->pData += n; |
| 4625 if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT; |
| 4626 if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT; |
4446 | 4627 |
4447 /* Truncate the current term and append suffix data. */ | 4628 /* Truncate the current term and append suffix data. */ |
4448 pReader->term.nData = nPrefix; | 4629 pReader->term.nData = nPrefix; |
4449 dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); | 4630 dataBufferAppend(&pReader->term, pReader->pData, nSuffix); |
4450 | 4631 |
4451 assert( n+nSuffix<=pReader->nData ); | 4632 pReader->pData += nSuffix; |
4452 pReader->pData += n+nSuffix; | 4633 pReader->nData -= nSuffix; |
4453 pReader->nData -= n+nSuffix; | |
4454 } | 4634 } |
4455 pReader->iBlockid++; | 4635 pReader->iBlockid++; |
| 4636 return SQLITE_OK; |
4456 } | 4637 } |
4457 | 4638 |
4458 /* Compare the current term to pTerm[nTerm], returning strcmp-style | 4639 /* Compare the current term to pTerm[nTerm], returning strcmp-style |
4459 ** results. If isPrefix, equality means equal through nTerm bytes. | 4640 ** results. If isPrefix, equality means equal through nTerm bytes. |
4460 */ | 4641 */ |
4461 static int interiorReaderTermCmp(InteriorReader *pReader, | 4642 static int interiorReaderTermCmp(InteriorReader *pReader, |
4462 const char *pTerm, int nTerm, int isPrefix){ | 4643 const char *pTerm, int nTerm, int isPrefix){ |
4463 const char *pReaderTerm = interiorReaderTerm(pReader); | 4644 const char *pReaderTerm = interiorReaderTerm(pReader); |
4464 int nReaderTerm = interiorReaderTermBytes(pReader); | 4645 int nReaderTerm = interiorReaderTermBytes(pReader); |
4465 int c, n = nReaderTerm<nTerm ? nReaderTerm : nTerm; | 4646 int c, n = nReaderTerm<nTerm ? nReaderTerm : nTerm; |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4817 | 4998 |
4818 /* Estimate the length of the merged doclist so we can leave space | 4999 /* Estimate the length of the merged doclist so we can leave space |
4819 ** to encode it. | 5000 ** to encode it. |
4820 */ | 5001 */ |
4821 for(i=0, nData=0; i<nReaders; i++){ | 5002 for(i=0, nData=0; i<nReaders; i++){ |
4822 nData += dlrAllDataBytes(&pReaders[i]); | 5003 nData += dlrAllDataBytes(&pReaders[i]); |
4823 } | 5004 } |
4824 n = putVarint(c, nData); | 5005 n = putVarint(c, nData); |
4825 dataBufferAppend(&pWriter->data, c, n); | 5006 dataBufferAppend(&pWriter->data, c, n); |
4826 | 5007 |
4827 docListMerge(&pWriter->data, pReaders, nReaders); | 5008 rc = docListMerge(&pWriter->data, pReaders, nReaders); |
| 5009 if( rc!= SQLITE_OK ) return rc; |
4828 ASSERT_VALID_DOCLIST(DL_DEFAULT, | 5010 ASSERT_VALID_DOCLIST(DL_DEFAULT, |
4829 pWriter->data.pData+iDoclistData+n, | 5011 pWriter->data.pData+iDoclistData+n, |
4830 pWriter->data.nData-iDoclistData-n, NULL); | 5012 pWriter->data.nData-iDoclistData-n, NULL); |
4831 | 5013 |
4832 /* The actual amount of doclist data at this point could be smaller | 5014 /* The actual amount of doclist data at this point could be smaller |
4833 ** than the length we encoded. Additionally, the space required to | 5015 ** than the length we encoded. Additionally, the space required to |
4834 ** encode this length could be smaller. For small doclists, this is | 5016 ** encode this length could be smaller. For small doclists, this is |
4835 ** not a big deal, we can just use memmove() to adjust things. | 5017 ** not a big deal, we can just use memmove() to adjust things. |
4836 */ | 5018 */ |
4837 nActualData = pWriter->data.nData-(iDoclistData+n); | 5019 nActualData = pWriter->data.nData-(iDoclistData+n); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4927 */ | 5109 */ |
4928 /* TODO(shess) Revise writeZeroSegment() so that doclists are | 5110 /* TODO(shess) Revise writeZeroSegment() so that doclists are |
4929 ** constructed directly in pWriter->data. | 5111 ** constructed directly in pWriter->data. |
4930 */ | 5112 */ |
4931 static int leafWriterStep(fulltext_vtab *v, LeafWriter *pWriter, | 5113 static int leafWriterStep(fulltext_vtab *v, LeafWriter *pWriter, |
4932 const char *pTerm, int nTerm, | 5114 const char *pTerm, int nTerm, |
4933 const char *pData, int nData){ | 5115 const char *pData, int nData){ |
4934 int rc; | 5116 int rc; |
4935 DLReader reader; | 5117 DLReader reader; |
4936 | 5118 |
4937 dlrInit(&reader, DL_DEFAULT, pData, nData); | 5119 rc = dlrInit(&reader, DL_DEFAULT, pData, nData); |
| 5120 if( rc!=SQLITE_OK ) return rc; |
4938 rc = leafWriterStepMerge(v, pWriter, pTerm, nTerm, &reader, 1); | 5121 rc = leafWriterStepMerge(v, pWriter, pTerm, nTerm, &reader, 1); |
4939 dlrDestroy(&reader); | 5122 dlrDestroy(&reader); |
4940 | 5123 |
4941 return rc; | 5124 return rc; |
4942 } | 5125 } |
4943 | 5126 |
4944 | 5127 |
4945 /****************************************************************/ | 5128 /****************************************************************/ |
4946 /* LeafReader is used to iterate over an individual leaf node. */ | 5129 /* LeafReader is used to iterate over an individual leaf node. */ |
4947 typedef struct LeafReader { | 5130 typedef struct LeafReader { |
(...skipping 24 matching lines...) Expand all Loading... |
4972 /* Access the doclist data for the current term. */ | 5155 /* Access the doclist data for the current term. */ |
4973 static int leafReaderDataBytes(LeafReader *pReader){ | 5156 static int leafReaderDataBytes(LeafReader *pReader){ |
4974 int nData; | 5157 int nData; |
4975 assert( pReader->term.nData>0 ); | 5158 assert( pReader->term.nData>0 ); |
4976 getVarint32(pReader->pData, &nData); | 5159 getVarint32(pReader->pData, &nData); |
4977 return nData; | 5160 return nData; |
4978 } | 5161 } |
4979 static const char *leafReaderData(LeafReader *pReader){ | 5162 static const char *leafReaderData(LeafReader *pReader){ |
4980 int n, nData; | 5163 int n, nData; |
4981 assert( pReader->term.nData>0 ); | 5164 assert( pReader->term.nData>0 ); |
4982 n = getVarint32(pReader->pData, &nData); | 5165 n = getVarint32Safe(pReader->pData, &nData, pReader->nData); |
| 5166 if( !n || nData>pReader->nData-n ) return NULL; |
4983 return pReader->pData+n; | 5167 return pReader->pData+n; |
4984 } | 5168 } |
4985 | 5169 |
4986 static void leafReaderInit(const char *pData, int nData, | 5170 static int leafReaderInit(const char *pData, int nData, LeafReader *pReader){ |
4987 LeafReader *pReader){ | |
4988 int nTerm, n; | 5171 int nTerm, n; |
4989 | 5172 |
| 5173 /* All callers check this precondition. */ |
4990 assert( nData>0 ); | 5174 assert( nData>0 ); |
4991 assert( pData[0]=='\0' ); | 5175 assert( pData[0]=='\0' ); |
4992 | 5176 |
4993 CLEAR(pReader); | 5177 CLEAR(pReader); |
4994 | 5178 |
4995 /* Read the first term, skipping the header byte. */ | 5179 /* Read the first term, skipping the header byte. */ |
4996 n = getVarint32(pData+1, &nTerm); | 5180 n = getVarint32Safe(pData+1, &nTerm, nData-1); |
| 5181 if( !n || nTerm<0 || nTerm>nData-1-n ) return SQLITE_CORRUPT_BKPT; |
4997 dataBufferInit(&pReader->term, nTerm); | 5182 dataBufferInit(&pReader->term, nTerm); |
4998 dataBufferReplace(&pReader->term, pData+1+n, nTerm); | 5183 dataBufferReplace(&pReader->term, pData+1+n, nTerm); |
4999 | 5184 |
5000 /* Position after the first term. */ | 5185 /* Position after the first term. */ |
5001 assert( 1+n+nTerm<nData ); | |
5002 pReader->pData = pData+1+n+nTerm; | 5186 pReader->pData = pData+1+n+nTerm; |
5003 pReader->nData = nData-1-n-nTerm; | 5187 pReader->nData = nData-1-n-nTerm; |
| 5188 return SQLITE_OK; |
5004 } | 5189 } |
5005 | 5190 |
5006 /* Step the reader forward to the next term. */ | 5191 /* Step the reader forward to the next term. */ |
5007 static void leafReaderStep(LeafReader *pReader){ | 5192 static int leafReaderStep(LeafReader *pReader){ |
5008 int n, nData, nPrefix, nSuffix; | 5193 int n, nData, nPrefix, nSuffix; |
5009 assert( !leafReaderAtEnd(pReader) ); | 5194 assert( !leafReaderAtEnd(pReader) ); |
5010 | 5195 |
5011 /* Skip previous entry's data block. */ | 5196 /* Skip previous entry's data block. */ |
5012 n = getVarint32(pReader->pData, &nData); | 5197 n = getVarint32Safe(pReader->pData, &nData, pReader->nData); |
5013 assert( n+nData<=pReader->nData ); | 5198 if( !n || nData<0 || nData>pReader->nData-n ) return SQLITE_CORRUPT_BKPT; |
5014 pReader->pData += n+nData; | 5199 pReader->pData += n+nData; |
5015 pReader->nData -= n+nData; | 5200 pReader->nData -= n+nData; |
5016 | 5201 |
5017 if( !leafReaderAtEnd(pReader) ){ | 5202 if( !leafReaderAtEnd(pReader) ){ |
5018 /* Construct the new term using a prefix from the old term plus a | 5203 /* Construct the new term using a prefix from the old term plus a |
5019 ** suffix from the leaf data. | 5204 ** suffix from the leaf data. |
5020 */ | 5205 */ |
5021 n = getVarint32(pReader->pData, &nPrefix); | 5206 n = getVarint32Safe(pReader->pData, &nPrefix, pReader->nData); |
5022 n += getVarint32(pReader->pData+n, &nSuffix); | 5207 if( !n ) return SQLITE_CORRUPT_BKPT; |
5023 assert( n+nSuffix<pReader->nData ); | 5208 pReader->nData -= n; |
| 5209 pReader->pData += n; |
| 5210 n = getVarint32Safe(pReader->pData, &nSuffix, pReader->nData); |
| 5211 if( !n ) return SQLITE_CORRUPT_BKPT; |
| 5212 pReader->nData -= n; |
| 5213 pReader->pData += n; |
| 5214 if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT; |
| 5215 if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT; |
5024 pReader->term.nData = nPrefix; | 5216 pReader->term.nData = nPrefix; |
5025 dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); | 5217 dataBufferAppend(&pReader->term, pReader->pData, nSuffix); |
5026 | 5218 |
5027 pReader->pData += n+nSuffix; | 5219 pReader->pData += nSuffix; |
5028 pReader->nData -= n+nSuffix; | 5220 pReader->nData -= nSuffix; |
5029 } | 5221 } |
| 5222 return SQLITE_OK; |
5030 } | 5223 } |
5031 | 5224 |
5032 /* strcmp-style comparison of pReader's current term against pTerm. | 5225 /* strcmp-style comparison of pReader's current term against pTerm. |
5033 ** If isPrefix, equality means equal through nTerm bytes. | 5226 ** If isPrefix, equality means equal through nTerm bytes. |
5034 */ | 5227 */ |
5035 static int leafReaderTermCmp(LeafReader *pReader, | 5228 static int leafReaderTermCmp(LeafReader *pReader, |
5036 const char *pTerm, int nTerm, int isPrefix){ | 5229 const char *pTerm, int nTerm, int isPrefix){ |
5037 int c, n = pReader->term.nData<nTerm ? pReader->term.nData : nTerm; | 5230 int c, n = pReader->term.nData<nTerm ? pReader->term.nData : nTerm; |
5038 if( n==0 ){ | 5231 if( n==0 ){ |
5039 if( pReader->term.nData>0 ) return -1; | 5232 if( pReader->term.nData>0 ) return -1; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5126 int idx, | 5319 int idx, |
5127 sqlite_int64 iStartBlockid, | 5320 sqlite_int64 iStartBlockid, |
5128 sqlite_int64 iEndBlockid, | 5321 sqlite_int64 iEndBlockid, |
5129 const char *pRootData, int nRootData, | 5322 const char *pRootData, int nRootData, |
5130 LeavesReader *pReader){ | 5323 LeavesReader *pReader){ |
5131 CLEAR(pReader); | 5324 CLEAR(pReader); |
5132 pReader->idx = idx; | 5325 pReader->idx = idx; |
5133 | 5326 |
5134 dataBufferInit(&pReader->rootData, 0); | 5327 dataBufferInit(&pReader->rootData, 0); |
5135 if( iStartBlockid==0 ){ | 5328 if( iStartBlockid==0 ){ |
| 5329 int rc; |
5136 /* Corrupt if this can't be a leaf node. */ | 5330 /* Corrupt if this can't be a leaf node. */ |
5137 if( pRootData==NULL || nRootData<1 || pRootData[0]!='\0' ){ | 5331 if( pRootData==NULL || nRootData<1 || pRootData[0]!='\0' ){ |
5138 return SQLITE_CORRUPT_BKPT; | 5332 return SQLITE_CORRUPT_BKPT; |
5139 } | 5333 } |
5140 /* Entire leaf level fit in root data. */ | 5334 /* Entire leaf level fit in root data. */ |
5141 dataBufferReplace(&pReader->rootData, pRootData, nRootData); | 5335 dataBufferReplace(&pReader->rootData, pRootData, nRootData); |
5142 leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, | 5336 rc = leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, |
5143 &pReader->leafReader); | 5337 &pReader->leafReader); |
| 5338 if( rc!=SQLITE_OK ){ |
| 5339 dataBufferDestroy(&pReader->rootData); |
| 5340 return rc; |
| 5341 } |
5144 }else{ | 5342 }else{ |
5145 sqlite3_stmt *s; | 5343 sqlite3_stmt *s; |
5146 int rc = sql_get_leaf_statement(v, idx, &s); | 5344 int rc = sql_get_leaf_statement(v, idx, &s); |
5147 if( rc!=SQLITE_OK ) return rc; | 5345 if( rc!=SQLITE_OK ) return rc; |
5148 | 5346 |
5149 rc = sqlite3_bind_int64(s, 1, iStartBlockid); | 5347 rc = sqlite3_bind_int64(s, 1, iStartBlockid); |
5150 if( rc!=SQLITE_OK ) goto err; | 5348 if( rc!=SQLITE_OK ) goto err; |
5151 | 5349 |
5152 rc = sqlite3_bind_int64(s, 2, iEndBlockid); | 5350 rc = sqlite3_bind_int64(s, 2, iEndBlockid); |
5153 if( rc!=SQLITE_OK ) goto err; | 5351 if( rc!=SQLITE_OK ) goto err; |
(...skipping 13 matching lines...) Expand all Loading... |
5167 if( sqlite3_column_type(s, 0)!=SQLITE_BLOB ){ | 5365 if( sqlite3_column_type(s, 0)!=SQLITE_BLOB ){ |
5168 rc = SQLITE_CORRUPT_BKPT; | 5366 rc = SQLITE_CORRUPT_BKPT; |
5169 }else{ | 5367 }else{ |
5170 const char *pLeafData = sqlite3_column_blob(s, 0); | 5368 const char *pLeafData = sqlite3_column_blob(s, 0); |
5171 int nLeafData = sqlite3_column_bytes(s, 0); | 5369 int nLeafData = sqlite3_column_bytes(s, 0); |
5172 | 5370 |
5173 /* Corrupt if this can't be a leaf node. */ | 5371 /* Corrupt if this can't be a leaf node. */ |
5174 if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ | 5372 if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ |
5175 rc = SQLITE_CORRUPT_BKPT; | 5373 rc = SQLITE_CORRUPT_BKPT; |
5176 }else{ | 5374 }else{ |
5177 leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); | 5375 rc = leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); |
5178 } | 5376 } |
5179 } | 5377 } |
5180 | 5378 |
5181 err: | 5379 err: |
5182 if( rc!=SQLITE_OK ){ | 5380 if( rc!=SQLITE_OK ){ |
5183 if( idx==-1 ){ | 5381 if( idx==-1 ){ |
5184 sqlite3_finalize(s); | 5382 sqlite3_finalize(s); |
5185 }else{ | 5383 }else{ |
5186 sqlite3_reset(s); | 5384 sqlite3_reset(s); |
5187 } | 5385 } |
5188 return rc; | 5386 return rc; |
5189 } | 5387 } |
5190 | 5388 |
5191 pReader->pStmt = s; | 5389 pReader->pStmt = s; |
5192 } | 5390 } |
5193 return SQLITE_OK; | 5391 return SQLITE_OK; |
5194 } | 5392 } |
5195 | 5393 |
5196 /* Step the current leaf forward to the next term. If we reach the | 5394 /* Step the current leaf forward to the next term. If we reach the |
5197 ** end of the current leaf, step forward to the next leaf block. | 5395 ** end of the current leaf, step forward to the next leaf block. |
5198 */ | 5396 */ |
5199 static int leavesReaderStep(fulltext_vtab *v, LeavesReader *pReader){ | 5397 static int leavesReaderStep(fulltext_vtab *v, LeavesReader *pReader){ |
| 5398 int rc; |
5200 assert( !leavesReaderAtEnd(pReader) ); | 5399 assert( !leavesReaderAtEnd(pReader) ); |
5201 leafReaderStep(&pReader->leafReader); | 5400 rc = leafReaderStep(&pReader->leafReader); |
| 5401 if( rc!=SQLITE_OK ) return rc; |
5202 | 5402 |
5203 if( leafReaderAtEnd(&pReader->leafReader) ){ | 5403 if( leafReaderAtEnd(&pReader->leafReader) ){ |
5204 int rc; | |
5205 if( pReader->rootData.pData ){ | 5404 if( pReader->rootData.pData ){ |
5206 pReader->eof = 1; | 5405 pReader->eof = 1; |
5207 return SQLITE_OK; | 5406 return SQLITE_OK; |
5208 } | 5407 } |
5209 rc = sqlite3_step(pReader->pStmt); | 5408 rc = sqlite3_step(pReader->pStmt); |
5210 if( rc!=SQLITE_ROW ){ | 5409 if( rc!=SQLITE_ROW ){ |
5211 pReader->eof = 1; | 5410 pReader->eof = 1; |
5212 return rc==SQLITE_DONE ? SQLITE_OK : rc; | 5411 return rc==SQLITE_DONE ? SQLITE_OK : rc; |
5213 } | 5412 } |
5214 | 5413 |
5215 /* Corrupt if leaf data isn't a blob. */ | 5414 /* Corrupt if leaf data isn't a blob. */ |
5216 if( sqlite3_column_type(pReader->pStmt, 0)!=SQLITE_BLOB ){ | 5415 if( sqlite3_column_type(pReader->pStmt, 0)!=SQLITE_BLOB ){ |
5217 return SQLITE_CORRUPT_BKPT; | 5416 return SQLITE_CORRUPT_BKPT; |
5218 }else{ | 5417 }else{ |
| 5418 LeafReader tmp; |
5219 const char *pLeafData = sqlite3_column_blob(pReader->pStmt, 0); | 5419 const char *pLeafData = sqlite3_column_blob(pReader->pStmt, 0); |
5220 int nLeafData = sqlite3_column_bytes(pReader->pStmt, 0); | 5420 int nLeafData = sqlite3_column_bytes(pReader->pStmt, 0); |
5221 | 5421 |
5222 /* Corrupt if this can't be a leaf node. */ | 5422 /* Corrupt if this can't be a leaf node. */ |
5223 if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ | 5423 if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ |
5224 return SQLITE_CORRUPT_BKPT; | 5424 return SQLITE_CORRUPT_BKPT; |
5225 } | 5425 } |
5226 | 5426 |
| 5427 rc = leafReaderInit(pLeafData, nLeafData, &tmp); |
| 5428 if( rc!=SQLITE_OK ) return rc; |
5227 leafReaderDestroy(&pReader->leafReader); | 5429 leafReaderDestroy(&pReader->leafReader); |
5228 leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); | 5430 pReader->leafReader = tmp; |
5229 } | 5431 } |
5230 } | 5432 } |
5231 return SQLITE_OK; | 5433 return SQLITE_OK; |
5232 } | 5434 } |
5233 | 5435 |
5234 /* Order LeavesReaders by their term, ignoring idx. Readers at eof | 5436 /* Order LeavesReaders by their term, ignoring idx. Readers at eof |
5235 ** always sort to the end. | 5437 ** always sort to the end. |
5236 */ | 5438 */ |
5237 static int leavesReaderTermCmp(LeavesReader *lr1, LeavesReader *lr2){ | 5439 static int leavesReaderTermCmp(LeavesReader *lr1, LeavesReader *lr2){ |
5238 if( leavesReaderAtEnd(lr1) ){ | 5440 if( leavesReaderAtEnd(lr1) ){ |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5327 ** is written to pWriter. Assumes pReaders is ordered oldest to | 5529 ** is written to pWriter. Assumes pReaders is ordered oldest to |
5328 ** newest. | 5530 ** newest. |
5329 */ | 5531 */ |
5330 /* TODO(shess) Consider putting this inline in segmentMerge(). */ | 5532 /* TODO(shess) Consider putting this inline in segmentMerge(). */ |
5331 static int leavesReadersMerge(fulltext_vtab *v, | 5533 static int leavesReadersMerge(fulltext_vtab *v, |
5332 LeavesReader *pReaders, int nReaders, | 5534 LeavesReader *pReaders, int nReaders, |
5333 LeafWriter *pWriter){ | 5535 LeafWriter *pWriter){ |
5334 DLReader dlReaders[MERGE_COUNT]; | 5536 DLReader dlReaders[MERGE_COUNT]; |
5335 const char *pTerm = leavesReaderTerm(pReaders); | 5537 const char *pTerm = leavesReaderTerm(pReaders); |
5336 int i, nTerm = leavesReaderTermBytes(pReaders); | 5538 int i, nTerm = leavesReaderTermBytes(pReaders); |
| 5539 int rc; |
5337 | 5540 |
5338 assert( nReaders<=MERGE_COUNT ); | 5541 assert( nReaders<=MERGE_COUNT ); |
5339 | 5542 |
5340 for(i=0; i<nReaders; i++){ | 5543 for(i=0; i<nReaders; i++){ |
5341 dlrInit(&dlReaders[i], DL_DEFAULT, | 5544 const char *pData = leavesReaderData(pReaders+i); |
5342 leavesReaderData(pReaders+i), | 5545 if( pData==NULL ){ |
5343 leavesReaderDataBytes(pReaders+i)); | 5546 rc = SQLITE_CORRUPT_BKPT; |
| 5547 break; |
| 5548 } |
| 5549 rc = dlrInit(&dlReaders[i], DL_DEFAULT, |
| 5550 pData, |
| 5551 leavesReaderDataBytes(pReaders+i)); |
| 5552 if( rc!=SQLITE_OK ) break; |
| 5553 } |
| 5554 if( rc!=SQLITE_OK ){ |
| 5555 while( i-->0 ){ |
| 5556 dlrDestroy(&dlReaders[i]); |
| 5557 } |
| 5558 return rc; |
5344 } | 5559 } |
5345 | 5560 |
5346 return leafWriterStepMerge(v, pWriter, pTerm, nTerm, dlReaders, nReaders); | 5561 return leafWriterStepMerge(v, pWriter, pTerm, nTerm, dlReaders, nReaders); |
5347 } | 5562 } |
5348 | 5563 |
5349 /* Forward ref due to mutual recursion with segdirNextIndex(). */ | 5564 /* Forward ref due to mutual recursion with segdirNextIndex(). */ |
5350 static int segmentMerge(fulltext_vtab *v, int iLevel); | 5565 static int segmentMerge(fulltext_vtab *v, int iLevel); |
5351 | 5566 |
5352 /* Put the next available index at iLevel into *pidx. If iLevel | 5567 /* Put the next available index at iLevel into *pidx. If iLevel |
5353 ** already has MERGE_COUNT segments, they are merged to a higher | 5568 ** already has MERGE_COUNT segments, they are merged to a higher |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5437 | 5652 |
5438 err: | 5653 err: |
5439 for(i=0; i<MERGE_COUNT; i++){ | 5654 for(i=0; i<MERGE_COUNT; i++){ |
5440 leavesReaderDestroy(&lrs[i]); | 5655 leavesReaderDestroy(&lrs[i]); |
5441 } | 5656 } |
5442 leafWriterDestroy(&writer); | 5657 leafWriterDestroy(&writer); |
5443 return rc; | 5658 return rc; |
5444 } | 5659 } |
5445 | 5660 |
5446 /* Accumulate the union of *acc and *pData into *acc. */ | 5661 /* Accumulate the union of *acc and *pData into *acc. */ |
5447 static void docListAccumulateUnion(DataBuffer *acc, | 5662 static int docListAccumulateUnion(DataBuffer *acc, |
5448 const char *pData, int nData) { | 5663 const char *pData, int nData) { |
5449 DataBuffer tmp = *acc; | 5664 DataBuffer tmp = *acc; |
| 5665 int rc; |
5450 dataBufferInit(acc, tmp.nData+nData); | 5666 dataBufferInit(acc, tmp.nData+nData); |
5451 docListUnion(tmp.pData, tmp.nData, pData, nData, acc); | 5667 rc = docListUnion(tmp.pData, tmp.nData, pData, nData, acc); |
5452 dataBufferDestroy(&tmp); | 5668 dataBufferDestroy(&tmp); |
| 5669 return rc; |
5453 } | 5670 } |
5454 | 5671 |
5455 /* TODO(shess) It might be interesting to explore different merge | 5672 /* TODO(shess) It might be interesting to explore different merge |
5456 ** strategies, here. For instance, since this is a sorted merge, we | 5673 ** strategies, here. For instance, since this is a sorted merge, we |
5457 ** could easily merge many doclists in parallel. With some | 5674 ** could easily merge many doclists in parallel. With some |
5458 ** comprehension of the storage format, we could merge all of the | 5675 ** comprehension of the storage format, we could merge all of the |
5459 ** doclists within a leaf node directly from the leaf node's storage. | 5676 ** doclists within a leaf node directly from the leaf node's storage. |
5460 ** It may be worthwhile to merge smaller doclists before larger | 5677 ** It may be worthwhile to merge smaller doclists before larger |
5461 ** doclists, since they can be traversed more quickly - but the | 5678 ** doclists, since they can be traversed more quickly - but the |
5462 ** results may have less overlap, making them more expensive in a | 5679 ** results may have less overlap, making them more expensive in a |
(...skipping 21 matching lines...) Expand all Loading... |
5484 for(rc=SQLITE_OK; rc==SQLITE_OK && !leavesReaderAtEnd(pReader); | 5701 for(rc=SQLITE_OK; rc==SQLITE_OK && !leavesReaderAtEnd(pReader); |
5485 rc=leavesReaderStep(v, pReader)){ | 5702 rc=leavesReaderStep(v, pReader)){ |
5486 /* TODO(shess) Really want leavesReaderTermCmp(), but that name is | 5703 /* TODO(shess) Really want leavesReaderTermCmp(), but that name is |
5487 ** already taken to compare the terms of two LeavesReaders. Think | 5704 ** already taken to compare the terms of two LeavesReaders. Think |
5488 ** on a better name. [Meanwhile, break encapsulation rather than | 5705 ** on a better name. [Meanwhile, break encapsulation rather than |
5489 ** use a confusing name.] | 5706 ** use a confusing name.] |
5490 */ | 5707 */ |
5491 int c = leafReaderTermCmp(&pReader->leafReader, pTerm, nTerm, isPrefix); | 5708 int c = leafReaderTermCmp(&pReader->leafReader, pTerm, nTerm, isPrefix); |
5492 if( c>0 ) break; /* Past any possible matches. */ | 5709 if( c>0 ) break; /* Past any possible matches. */ |
5493 if( c==0 ){ | 5710 if( c==0 ){ |
| 5711 int iBuffer, nData; |
5494 const char *pData = leavesReaderData(pReader); | 5712 const char *pData = leavesReaderData(pReader); |
5495 int iBuffer, nData = leavesReaderDataBytes(pReader); | 5713 if( pData==NULL ){ |
| 5714 rc = SQLITE_CORRUPT_BKPT; |
| 5715 break; |
| 5716 } |
| 5717 nData = leavesReaderDataBytes(pReader); |
5496 | 5718 |
5497 /* Find the first empty buffer. */ | 5719 /* Find the first empty buffer. */ |
5498 for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){ | 5720 for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){ |
5499 if( 0==pBuffers[iBuffer].nData ) break; | 5721 if( 0==pBuffers[iBuffer].nData ) break; |
5500 } | 5722 } |
5501 | 5723 |
5502 /* Out of buffers, add an empty one. */ | 5724 /* Out of buffers, add an empty one. */ |
5503 if( iBuffer==nBuffers ){ | 5725 if( iBuffer==nBuffers ){ |
5504 if( nBuffers==nMaxBuffers ){ | 5726 if( nBuffers==nMaxBuffers ){ |
5505 DataBuffer *p; | 5727 DataBuffer *p; |
(...skipping 25 matching lines...) Expand all Loading... |
5531 dataBufferReplace(&(pBuffers[0]), pData, nData); | 5753 dataBufferReplace(&(pBuffers[0]), pData, nData); |
5532 }else{ | 5754 }else{ |
5533 /* pAcc is the empty buffer the merged data will end up in. */ | 5755 /* pAcc is the empty buffer the merged data will end up in. */ |
5534 DataBuffer *pAcc = &(pBuffers[iBuffer]); | 5756 DataBuffer *pAcc = &(pBuffers[iBuffer]); |
5535 DataBuffer *p = &(pBuffers[0]); | 5757 DataBuffer *p = &(pBuffers[0]); |
5536 | 5758 |
5537 /* Handle position 0 specially to avoid need to prime pAcc | 5759 /* Handle position 0 specially to avoid need to prime pAcc |
5538 ** with pData/nData. | 5760 ** with pData/nData. |
5539 */ | 5761 */ |
5540 dataBufferSwap(p, pAcc); | 5762 dataBufferSwap(p, pAcc); |
5541 docListAccumulateUnion(pAcc, pData, nData); | 5763 rc = docListAccumulateUnion(pAcc, pData, nData); |
| 5764 if( rc!=SQLITE_OK ) goto err; |
5542 | 5765 |
5543 /* Accumulate remaining doclists into pAcc. */ | 5766 /* Accumulate remaining doclists into pAcc. */ |
5544 for(++p; p<pAcc; ++p){ | 5767 for(++p; p<pAcc; ++p){ |
5545 docListAccumulateUnion(pAcc, p->pData, p->nData); | 5768 rc = docListAccumulateUnion(pAcc, p->pData, p->nData); |
| 5769 if( rc!=SQLITE_OK ) goto err; |
5546 | 5770 |
5547 /* dataBufferReset() could allow a large doclist to blow up | 5771 /* dataBufferReset() could allow a large doclist to blow up |
5548 ** our memory requirements. | 5772 ** our memory requirements. |
5549 */ | 5773 */ |
5550 if( p->nCapacity<1024 ){ | 5774 if( p->nCapacity<1024 ){ |
5551 dataBufferReset(p); | 5775 dataBufferReset(p); |
5552 }else{ | 5776 }else{ |
5553 dataBufferDestroy(p); | 5777 dataBufferDestroy(p); |
5554 dataBufferInit(p, 0); | 5778 dataBufferInit(p, 0); |
5555 } | 5779 } |
5556 } | 5780 } |
5557 } | 5781 } |
5558 } | 5782 } |
5559 } | 5783 } |
5560 | 5784 |
5561 /* Union all the doclists together into *out. */ | 5785 /* Union all the doclists together into *out. */ |
5562 /* TODO(shess) What if *out is big? Sigh. */ | 5786 /* TODO(shess) What if *out is big? Sigh. */ |
5563 if( rc==SQLITE_OK && nBuffers>0 ){ | 5787 if( rc==SQLITE_OK && nBuffers>0 ){ |
5564 int iBuffer; | 5788 int iBuffer; |
5565 for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){ | 5789 for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){ |
5566 if( pBuffers[iBuffer].nData>0 ){ | 5790 if( pBuffers[iBuffer].nData>0 ){ |
5567 if( out->nData==0 ){ | 5791 if( out->nData==0 ){ |
5568 dataBufferSwap(out, &(pBuffers[iBuffer])); | 5792 dataBufferSwap(out, &(pBuffers[iBuffer])); |
5569 }else{ | 5793 }else{ |
5570 docListAccumulateUnion(out, pBuffers[iBuffer].pData, | 5794 rc = docListAccumulateUnion(out, pBuffers[iBuffer].pData, |
5571 pBuffers[iBuffer].nData); | 5795 pBuffers[iBuffer].nData); |
| 5796 if( rc!=SQLITE_OK ) break; |
5572 } | 5797 } |
5573 } | 5798 } |
5574 } | 5799 } |
5575 } | 5800 } |
5576 | 5801 |
| 5802 err: |
5577 while( nBuffers-- ){ | 5803 while( nBuffers-- ){ |
5578 dataBufferDestroy(&(pBuffers[nBuffers])); | 5804 dataBufferDestroy(&(pBuffers[nBuffers])); |
5579 } | 5805 } |
5580 if( pBuffers!=NULL ) sqlite3_free(pBuffers); | 5806 if( pBuffers!=NULL ) sqlite3_free(pBuffers); |
5581 | 5807 |
5582 return rc; | 5808 return rc; |
5583 } | 5809 } |
5584 | 5810 |
5585 /* Call loadSegmentLeavesInt() with pData/nData as input. */ | 5811 /* Call loadSegmentLeavesInt() with pData/nData as input. */ |
5586 static int loadSegmentLeaf(fulltext_vtab *v, const char *pData, int nData, | 5812 static int loadSegmentLeaf(fulltext_vtab *v, const char *pData, int nData, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5625 ** nodes which could include pTerm/nTerm/isPrefix. Note that the | 5851 ** nodes which could include pTerm/nTerm/isPrefix. Note that the |
5626 ** interior node terms logically come between the blocks, so there is | 5852 ** interior node terms logically come between the blocks, so there is |
5627 ** one more blockid than there are terms (that block contains terms >= | 5853 ** one more blockid than there are terms (that block contains terms >= |
5628 ** the last interior-node term). | 5854 ** the last interior-node term). |
5629 */ | 5855 */ |
5630 /* TODO(shess) The calling code may already know that the end child is | 5856 /* TODO(shess) The calling code may already know that the end child is |
5631 ** not worth calculating, because the end may be in a later sibling | 5857 ** not worth calculating, because the end may be in a later sibling |
5632 ** node. Consider whether breaking symmetry is worthwhile. I suspect | 5858 ** node. Consider whether breaking symmetry is worthwhile. I suspect |
5633 ** it is not worthwhile. | 5859 ** it is not worthwhile. |
5634 */ | 5860 */ |
5635 static void getChildrenContaining(const char *pData, int nData, | 5861 static int getChildrenContaining(const char *pData, int nData, |
5636 const char *pTerm, int nTerm, int isPrefix, | 5862 const char *pTerm, int nTerm, int isPrefix, |
5637 sqlite_int64 *piStartChild, | 5863 sqlite_int64 *piStartChild, |
5638 sqlite_int64 *piEndChild){ | 5864 sqlite_int64 *piEndChild){ |
5639 InteriorReader reader; | 5865 InteriorReader reader; |
| 5866 int rc; |
5640 | 5867 |
5641 assert( nData>1 ); | 5868 assert( nData>1 ); |
5642 assert( *pData!='\0' ); | 5869 assert( *pData!='\0' ); |
5643 interiorReaderInit(pData, nData, &reader); | 5870 rc = interiorReaderInit(pData, nData, &reader); |
| 5871 if( rc!=SQLITE_OK ) return rc; |
5644 | 5872 |
5645 /* Scan for the first child which could contain pTerm/nTerm. */ | 5873 /* Scan for the first child which could contain pTerm/nTerm. */ |
5646 while( !interiorReaderAtEnd(&reader) ){ | 5874 while( !interiorReaderAtEnd(&reader) ){ |
5647 if( interiorReaderTermCmp(&reader, pTerm, nTerm, 0)>0 ) break; | 5875 if( interiorReaderTermCmp(&reader, pTerm, nTerm, 0)>0 ) break; |
5648 interiorReaderStep(&reader); | 5876 rc = interiorReaderStep(&reader); |
| 5877 if( rc!=SQLITE_OK ){ |
| 5878 interiorReaderDestroy(&reader); |
| 5879 return rc; |
| 5880 } |
5649 } | 5881 } |
5650 *piStartChild = interiorReaderCurrentBlockid(&reader); | 5882 *piStartChild = interiorReaderCurrentBlockid(&reader); |
5651 | 5883 |
5652 /* Keep scanning to find a term greater than our term, using prefix | 5884 /* Keep scanning to find a term greater than our term, using prefix |
5653 ** comparison if indicated. If isPrefix is false, this will be the | 5885 ** comparison if indicated. If isPrefix is false, this will be the |
5654 ** same blockid as the starting block. | 5886 ** same blockid as the starting block. |
5655 */ | 5887 */ |
5656 while( !interiorReaderAtEnd(&reader) ){ | 5888 while( !interiorReaderAtEnd(&reader) ){ |
5657 if( interiorReaderTermCmp(&reader, pTerm, nTerm, isPrefix)>0 ) break; | 5889 if( interiorReaderTermCmp(&reader, pTerm, nTerm, isPrefix)>0 ) break; |
5658 interiorReaderStep(&reader); | 5890 rc = interiorReaderStep(&reader); |
| 5891 if( rc!=SQLITE_OK ){ |
| 5892 interiorReaderDestroy(&reader); |
| 5893 return rc; |
| 5894 } |
5659 } | 5895 } |
5660 *piEndChild = interiorReaderCurrentBlockid(&reader); | 5896 *piEndChild = interiorReaderCurrentBlockid(&reader); |
5661 | 5897 |
5662 interiorReaderDestroy(&reader); | 5898 interiorReaderDestroy(&reader); |
5663 | 5899 |
5664 /* Children must ascend, and if !prefix, both must be the same. */ | 5900 /* Children must ascend, and if !prefix, both must be the same. */ |
5665 assert( *piEndChild>=*piStartChild ); | 5901 assert( *piEndChild>=*piStartChild ); |
5666 assert( isPrefix || *piStartChild==*piEndChild ); | 5902 assert( isPrefix || *piStartChild==*piEndChild ); |
| 5903 return rc; |
5667 } | 5904 } |
5668 | 5905 |
5669 /* Read block at iBlockid and pass it with other params to | 5906 /* Read block at iBlockid and pass it with other params to |
5670 ** getChildrenContaining(). | 5907 ** getChildrenContaining(). |
5671 */ | 5908 */ |
5672 static int loadAndGetChildrenContaining( | 5909 static int loadAndGetChildrenContaining( |
5673 fulltext_vtab *v, | 5910 fulltext_vtab *v, |
5674 sqlite_int64 iBlockid, | 5911 sqlite_int64 iBlockid, |
5675 const char *pTerm, int nTerm, int isPrefix, | 5912 const char *pTerm, int nTerm, int isPrefix, |
5676 sqlite_int64 *piStartChild, sqlite_int64 *piEndChild | 5913 sqlite_int64 *piStartChild, sqlite_int64 *piEndChild |
(...skipping 25 matching lines...) Expand all Loading... |
5702 }else{ | 5939 }else{ |
5703 const char *pData = sqlite3_column_blob(s, 0); | 5940 const char *pData = sqlite3_column_blob(s, 0); |
5704 int nData = sqlite3_column_bytes(s, 0); | 5941 int nData = sqlite3_column_bytes(s, 0); |
5705 | 5942 |
5706 /* Corrupt if child is not a valid interior node. */ | 5943 /* Corrupt if child is not a valid interior node. */ |
5707 if( pData==NULL || nData<1 || pData[0]=='\0' ){ | 5944 if( pData==NULL || nData<1 || pData[0]=='\0' ){ |
5708 sqlite3_reset(s); /* So we don't leave a lock. */ | 5945 sqlite3_reset(s); /* So we don't leave a lock. */ |
5709 return SQLITE_CORRUPT_BKPT; | 5946 return SQLITE_CORRUPT_BKPT; |
5710 } | 5947 } |
5711 | 5948 |
5712 getChildrenContaining(pData, nData, pTerm, nTerm, | 5949 rc = getChildrenContaining(pData, nData, pTerm, nTerm, |
5713 isPrefix, piStartChild, piEndChild); | 5950 isPrefix, piStartChild, piEndChild); |
| 5951 if( rc!=SQLITE_OK ){ |
| 5952 sqlite3_reset(s); |
| 5953 return rc; |
| 5954 } |
5714 } | 5955 } |
5715 | 5956 |
5716 /* We expect only one row. We must execute another sqlite3_step() | 5957 /* We expect only one row. We must execute another sqlite3_step() |
5717 * to complete the iteration; otherwise the table will remain | 5958 * to complete the iteration; otherwise the table will remain |
5718 * locked. */ | 5959 * locked. */ |
5719 rc = sqlite3_step(s); | 5960 rc = sqlite3_step(s); |
5720 if( rc==SQLITE_ROW ) return SQLITE_ERROR; | 5961 if( rc==SQLITE_ROW ) return SQLITE_ERROR; |
5721 if( rc!=SQLITE_DONE ) return rc; | 5962 if( rc!=SQLITE_DONE ) return rc; |
5722 | 5963 |
5723 return SQLITE_OK; | 5964 return SQLITE_OK; |
(...skipping 10 matching lines...) Expand all Loading... |
5734 /* Special case where root is a leaf. */ | 5975 /* Special case where root is a leaf. */ |
5735 if( *pData=='\0' ){ | 5976 if( *pData=='\0' ){ |
5736 return loadSegmentLeaf(v, pData, nData, pTerm, nTerm, isPrefix, out); | 5977 return loadSegmentLeaf(v, pData, nData, pTerm, nTerm, isPrefix, out); |
5737 }else{ | 5978 }else{ |
5738 int rc; | 5979 int rc; |
5739 sqlite_int64 iStartChild, iEndChild; | 5980 sqlite_int64 iStartChild, iEndChild; |
5740 | 5981 |
5741 /* Process pData as an interior node, then loop down the tree | 5982 /* Process pData as an interior node, then loop down the tree |
5742 ** until we find the set of leaf nodes to scan for the term. | 5983 ** until we find the set of leaf nodes to scan for the term. |
5743 */ | 5984 */ |
5744 getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, | 5985 rc = getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, |
5745 &iStartChild, &iEndChild); | 5986 &iStartChild, &iEndChild); |
| 5987 if( rc!=SQLITE_OK ) return rc; |
5746 while( iStartChild>iLeavesEnd ){ | 5988 while( iStartChild>iLeavesEnd ){ |
5747 sqlite_int64 iNextStart, iNextEnd; | 5989 sqlite_int64 iNextStart, iNextEnd; |
5748 rc = loadAndGetChildrenContaining(v, iStartChild, pTerm, nTerm, isPrefix, | 5990 rc = loadAndGetChildrenContaining(v, iStartChild, pTerm, nTerm, isPrefix, |
5749 &iNextStart, &iNextEnd); | 5991 &iNextStart, &iNextEnd); |
5750 if( rc!=SQLITE_OK ) return rc; | 5992 if( rc!=SQLITE_OK ) return rc; |
5751 | 5993 |
5752 /* If we've branched, follow the end branch, too. */ | 5994 /* If we've branched, follow the end branch, too. */ |
5753 if( iStartChild!=iEndChild ){ | 5995 if( iStartChild!=iEndChild ){ |
5754 sqlite_int64 iDummy; | 5996 sqlite_int64 iDummy; |
5755 rc = loadAndGetChildrenContaining(v, iEndChild, pTerm, nTerm, isPrefix, | 5997 rc = loadAndGetChildrenContaining(v, iEndChild, pTerm, nTerm, isPrefix, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5805 pTerm, nTerm, isPrefix, &result); | 6047 pTerm, nTerm, isPrefix, &result); |
5806 if( rc==SQLITE_OK && result.nData>0 ){ | 6048 if( rc==SQLITE_OK && result.nData>0 ){ |
5807 if( out->nData==0 ){ | 6049 if( out->nData==0 ){ |
5808 DataBuffer tmp = *out; | 6050 DataBuffer tmp = *out; |
5809 *out = result; | 6051 *out = result; |
5810 result = tmp; | 6052 result = tmp; |
5811 }else{ | 6053 }else{ |
5812 DataBuffer merged; | 6054 DataBuffer merged; |
5813 DLReader readers[2]; | 6055 DLReader readers[2]; |
5814 | 6056 |
5815 dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); | 6057 rc = dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); |
5816 dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); | 6058 if( rc==SQLITE_OK ){ |
5817 dataBufferInit(&merged, out->nData+result.nData); | 6059 rc = dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); |
5818 docListMerge(&merged, readers, 2); | 6060 if( rc==SQLITE_OK ){ |
5819 dataBufferDestroy(out); | 6061 dataBufferInit(&merged, out->nData+result.nData); |
5820 *out = merged; | 6062 rc = docListMerge(&merged, readers, 2); |
5821 dlrDestroy(&readers[0]); | 6063 dataBufferDestroy(out); |
5822 dlrDestroy(&readers[1]); | 6064 *out = merged; |
| 6065 dlrDestroy(&readers[1]); |
| 6066 } |
| 6067 dlrDestroy(&readers[0]); |
| 6068 } |
5823 } | 6069 } |
5824 } | 6070 } |
| 6071 |
5825 dataBufferDestroy(&result); | 6072 dataBufferDestroy(&result); |
5826 return rc; | 6073 return rc; |
5827 } | 6074 } |
5828 | 6075 |
5829 /* Scan the database and merge together the posting lists for the term | 6076 /* Scan the database and merge together the posting lists for the term |
5830 ** into *out. | 6077 ** into *out. |
5831 */ | 6078 */ |
5832 static int termSelect(fulltext_vtab *v, int iColumn, | 6079 static int termSelect(fulltext_vtab *v, int iColumn, |
5833 const char *pTerm, int nTerm, int isPrefix, | 6080 const char *pTerm, int nTerm, int isPrefix, |
5834 DocListType iType, DataBuffer *out){ | 6081 DocListType iType, DataBuffer *out){ |
(...skipping 20 matching lines...) Expand all Loading... |
5855 sqlite3_column_type(s, 2)!=SQLITE_BLOB ){ | 6102 sqlite3_column_type(s, 2)!=SQLITE_BLOB ){ |
5856 rc = SQLITE_CORRUPT_BKPT; | 6103 rc = SQLITE_CORRUPT_BKPT; |
5857 goto err; | 6104 goto err; |
5858 } | 6105 } |
5859 | 6106 |
5860 rc = loadSegment(v, pData, nData, iLeavesEnd, pTerm, nTerm, isPrefix, | 6107 rc = loadSegment(v, pData, nData, iLeavesEnd, pTerm, nTerm, isPrefix, |
5861 &doclist); | 6108 &doclist); |
5862 if( rc!=SQLITE_OK ) goto err; | 6109 if( rc!=SQLITE_OK ) goto err; |
5863 } | 6110 } |
5864 if( rc==SQLITE_DONE ){ | 6111 if( rc==SQLITE_DONE ){ |
| 6112 rc = SQLITE_OK; |
5865 if( doclist.nData!=0 ){ | 6113 if( doclist.nData!=0 ){ |
5866 /* TODO(shess) The old term_select_all() code applied the column | 6114 /* TODO(shess) The old term_select_all() code applied the column |
5867 ** restrict as we merged segments, leading to smaller buffers. | 6115 ** restrict as we merged segments, leading to smaller buffers. |
5868 ** This is probably worthwhile to bring back, once the new storage | 6116 ** This is probably worthwhile to bring back, once the new storage |
5869 ** system is checked in. | 6117 ** system is checked in. |
5870 */ | 6118 */ |
5871 if( iColumn==v->nColumn) iColumn = -1; | 6119 if( iColumn==v->nColumn) iColumn = -1; |
5872 docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | 6120 rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, |
5873 iColumn, iType, out); | 6121 iColumn, iType, out); |
5874 } | 6122 } |
5875 rc = SQLITE_OK; | |
5876 } | 6123 } |
5877 | 6124 |
5878 err: | 6125 err: |
5879 sqlite3_reset(s); /* So we don't leave a lock. */ | 6126 sqlite3_reset(s); /* So we don't leave a lock. */ |
5880 dataBufferDestroy(&doclist); | 6127 dataBufferDestroy(&doclist); |
5881 return rc; | 6128 return rc; |
5882 } | 6129 } |
5883 | 6130 |
5884 /****************************************************************/ | 6131 /****************************************************************/ |
5885 /* Used to hold hashtable data for sorting. */ | 6132 /* Used to hold hashtable data for sorting. */ |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6211 /* optimize() helper function. Put the readers in order and iterate | 6458 /* optimize() helper function. Put the readers in order and iterate |
6212 ** through them, merging doclists for matching terms into pWriter. | 6459 ** through them, merging doclists for matching terms into pWriter. |
6213 ** Returns SQLITE_OK on success, or the SQLite error code which | 6460 ** Returns SQLITE_OK on success, or the SQLite error code which |
6214 ** prevented success. | 6461 ** prevented success. |
6215 */ | 6462 */ |
6216 static int optimizeInternal(fulltext_vtab *v, | 6463 static int optimizeInternal(fulltext_vtab *v, |
6217 OptLeavesReader *readers, int nReaders, | 6464 OptLeavesReader *readers, int nReaders, |
6218 LeafWriter *pWriter){ | 6465 LeafWriter *pWriter){ |
6219 int i, rc = SQLITE_OK; | 6466 int i, rc = SQLITE_OK; |
6220 DataBuffer doclist, merged, tmp; | 6467 DataBuffer doclist, merged, tmp; |
| 6468 const char *pData; |
6221 | 6469 |
6222 /* Order the readers. */ | 6470 /* Order the readers. */ |
6223 i = nReaders; | 6471 i = nReaders; |
6224 while( i-- > 0 ){ | 6472 while( i-- > 0 ){ |
6225 optLeavesReaderReorder(&readers[i], nReaders-i); | 6473 optLeavesReaderReorder(&readers[i], nReaders-i); |
6226 } | 6474 } |
6227 | 6475 |
6228 dataBufferInit(&doclist, LEAF_MAX); | 6476 dataBufferInit(&doclist, LEAF_MAX); |
6229 dataBufferInit(&merged, LEAF_MAX); | 6477 dataBufferInit(&merged, LEAF_MAX); |
6230 | 6478 |
6231 /* Exhausted readers bubble to the end, so when the first reader is | 6479 /* Exhausted readers bubble to the end, so when the first reader is |
6232 ** at eof, all are at eof. | 6480 ** at eof, all are at eof. |
6233 */ | 6481 */ |
6234 while( !optLeavesReaderAtEnd(&readers[0]) ){ | 6482 while( !optLeavesReaderAtEnd(&readers[0]) ){ |
6235 | 6483 |
6236 /* Figure out how many readers share the next term. */ | 6484 /* Figure out how many readers share the next term. */ |
6237 for(i=1; i<nReaders && !optLeavesReaderAtEnd(&readers[i]); i++){ | 6485 for(i=1; i<nReaders && !optLeavesReaderAtEnd(&readers[i]); i++){ |
6238 if( 0!=optLeavesReaderTermCmp(&readers[0], &readers[i]) ) break; | 6486 if( 0!=optLeavesReaderTermCmp(&readers[0], &readers[i]) ) break; |
6239 } | 6487 } |
6240 | 6488 |
| 6489 pData = optLeavesReaderData(&readers[0]); |
| 6490 if( pData==NULL ){ |
| 6491 rc = SQLITE_CORRUPT_BKPT; |
| 6492 break; |
| 6493 } |
| 6494 |
6241 /* Special-case for no merge. */ | 6495 /* Special-case for no merge. */ |
6242 if( i==1 ){ | 6496 if( i==1 ){ |
6243 /* Trim deletions from the doclist. */ | 6497 /* Trim deletions from the doclist. */ |
6244 dataBufferReset(&merged); | 6498 dataBufferReset(&merged); |
6245 docListTrim(DL_DEFAULT, | 6499 rc = docListTrim(DL_DEFAULT, |
6246 optLeavesReaderData(&readers[0]), | 6500 pData, |
6247 optLeavesReaderDataBytes(&readers[0]), | 6501 optLeavesReaderDataBytes(&readers[0]), |
6248 -1, DL_DEFAULT, &merged); | 6502 -1, DL_DEFAULT, &merged); |
| 6503 if( rc!= SQLITE_OK ) break; |
6249 }else{ | 6504 }else{ |
6250 DLReader dlReaders[MERGE_COUNT]; | 6505 DLReader dlReaders[MERGE_COUNT]; |
6251 int iReader, nReaders; | 6506 int iReader, nReaders; |
6252 | 6507 |
6253 /* Prime the pipeline with the first reader's doclist. After | 6508 /* Prime the pipeline with the first reader's doclist. After |
6254 ** one pass index 0 will reference the accumulated doclist. | 6509 ** one pass index 0 will reference the accumulated doclist. |
6255 */ | 6510 */ |
6256 dlrInit(&dlReaders[0], DL_DEFAULT, | 6511 rc = dlrInit(&dlReaders[0], DL_DEFAULT, |
6257 optLeavesReaderData(&readers[0]), | 6512 pData, |
6258 optLeavesReaderDataBytes(&readers[0])); | 6513 optLeavesReaderDataBytes(&readers[0])); |
| 6514 if( rc!=SQLITE_OK ) break; |
6259 iReader = 1; | 6515 iReader = 1; |
6260 | 6516 |
6261 assert( iReader<i ); /* Must execute the loop at least once. */ | 6517 assert( iReader<i ); /* Must execute the loop at least once. */ |
6262 while( iReader<i ){ | 6518 while( iReader<i ){ |
6263 /* Merge 16 inputs per pass. */ | 6519 /* Merge 16 inputs per pass. */ |
6264 for( nReaders=1; iReader<i && nReaders<MERGE_COUNT; | 6520 for( nReaders=1; iReader<i && nReaders<MERGE_COUNT; |
6265 iReader++, nReaders++ ){ | 6521 iReader++, nReaders++ ){ |
6266 dlrInit(&dlReaders[nReaders], DL_DEFAULT, | 6522 pData = optLeavesReaderData(&readers[iReader]); |
6267 optLeavesReaderData(&readers[iReader]), | 6523 if( pData == NULL ){ |
6268 optLeavesReaderDataBytes(&readers[iReader])); | 6524 rc = SQLITE_CORRUPT_BKPT; |
| 6525 break; |
| 6526 } |
| 6527 rc = dlrInit(&dlReaders[nReaders], DL_DEFAULT, |
| 6528 pData, |
| 6529 optLeavesReaderDataBytes(&readers[iReader])); |
| 6530 if( rc != SQLITE_OK ) break; |
6269 } | 6531 } |
6270 | 6532 |
6271 /* Merge doclists and swap result into accumulator. */ | 6533 /* Merge doclists and swap result into accumulator. */ |
6272 dataBufferReset(&merged); | 6534 if( rc==SQLITE_OK ){ |
6273 docListMerge(&merged, dlReaders, nReaders); | 6535 dataBufferReset(&merged); |
6274 tmp = merged; | 6536 rc = docListMerge(&merged, dlReaders, nReaders); |
6275 merged = doclist; | 6537 tmp = merged; |
6276 doclist = tmp; | 6538 merged = doclist; |
| 6539 doclist = tmp; |
| 6540 } |
6277 | 6541 |
6278 while( nReaders-- > 0 ){ | 6542 while( nReaders-- > 0 ){ |
6279 dlrDestroy(&dlReaders[nReaders]); | 6543 dlrDestroy(&dlReaders[nReaders]); |
6280 } | 6544 } |
6281 | 6545 |
| 6546 if( rc!=SQLITE_OK ) goto err; |
| 6547 |
6282 /* Accumulated doclist to reader 0 for next pass. */ | 6548 /* Accumulated doclist to reader 0 for next pass. */ |
6283 dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); | 6549 rc = dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); |
| 6550 if( rc!=SQLITE_OK ) goto err; |
6284 } | 6551 } |
6285 | 6552 |
6286 /* Destroy reader that was left in the pipeline. */ | 6553 /* Destroy reader that was left in the pipeline. */ |
6287 dlrDestroy(&dlReaders[0]); | 6554 dlrDestroy(&dlReaders[0]); |
6288 | 6555 |
6289 /* Trim deletions from the doclist. */ | 6556 /* Trim deletions from the doclist. */ |
6290 dataBufferReset(&merged); | 6557 dataBufferReset(&merged); |
6291 docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | 6558 rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, |
6292 -1, DL_DEFAULT, &merged); | 6559 -1, DL_DEFAULT, &merged); |
| 6560 if( rc!=SQLITE_OK ) goto err; |
6293 } | 6561 } |
6294 | 6562 |
6295 /* Only pass doclists with hits (skip if all hits deleted). */ | 6563 /* Only pass doclists with hits (skip if all hits deleted). */ |
6296 if( merged.nData>0 ){ | 6564 if( merged.nData>0 ){ |
6297 rc = leafWriterStep(v, pWriter, | 6565 rc = leafWriterStep(v, pWriter, |
6298 optLeavesReaderTerm(&readers[0]), | 6566 optLeavesReaderTerm(&readers[0]), |
6299 optLeavesReaderTermBytes(&readers[0]), | 6567 optLeavesReaderTermBytes(&readers[0]), |
6300 merged.pData, merged.nData); | 6568 merged.pData, merged.nData); |
6301 if( rc!=SQLITE_OK ) goto err; | 6569 if( rc!=SQLITE_OK ) goto err; |
6302 } | 6570 } |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6621 } | 6889 } |
6622 } | 6890 } |
6623 | 6891 |
6624 /* Expand the DL_DEFAULT doclist in pData into a text result in | 6892 /* Expand the DL_DEFAULT doclist in pData into a text result in |
6625 ** pContext. | 6893 ** pContext. |
6626 */ | 6894 */ |
6627 static void createDoclistResult(sqlite3_context *pContext, | 6895 static void createDoclistResult(sqlite3_context *pContext, |
6628 const char *pData, int nData){ | 6896 const char *pData, int nData){ |
6629 DataBuffer dump; | 6897 DataBuffer dump; |
6630 DLReader dlReader; | 6898 DLReader dlReader; |
| 6899 int rc; |
6631 | 6900 |
6632 assert( pData!=NULL && nData>0 ); | 6901 assert( pData!=NULL && nData>0 ); |
6633 | 6902 |
| 6903 rc = dlrInit(&dlReader, DL_DEFAULT, pData, nData); |
| 6904 if( rc!=SQLITE_OK ) return rc; |
6634 dataBufferInit(&dump, 0); | 6905 dataBufferInit(&dump, 0); |
6635 dlrInit(&dlReader, DL_DEFAULT, pData, nData); | 6906 for( ; rc==SQLITE_OK && !dlrAtEnd(&dlReader); rc = dlrStep(&dlReader) ){ |
6636 for( ; !dlrAtEnd(&dlReader); dlrStep(&dlReader) ){ | |
6637 char buf[256]; | 6907 char buf[256]; |
6638 PLReader plReader; | 6908 PLReader plReader; |
6639 | 6909 |
6640 plrInit(&plReader, &dlReader); | 6910 rc = plrInit(&plReader, &dlReader); |
| 6911 if( rc!=SQLITE_OK ) break; |
6641 if( DL_DEFAULT==DL_DOCIDS || plrAtEnd(&plReader) ){ | 6912 if( DL_DEFAULT==DL_DOCIDS || plrAtEnd(&plReader) ){ |
6642 sqlite3_snprintf(sizeof(buf), buf, "[%lld] ", dlrDocid(&dlReader)); | 6913 sqlite3_snprintf(sizeof(buf), buf, "[%lld] ", dlrDocid(&dlReader)); |
6643 dataBufferAppend(&dump, buf, strlen(buf)); | 6914 dataBufferAppend(&dump, buf, strlen(buf)); |
6644 }else{ | 6915 }else{ |
6645 int iColumn = plrColumn(&plReader); | 6916 int iColumn = plrColumn(&plReader); |
6646 | 6917 |
6647 sqlite3_snprintf(sizeof(buf), buf, "[%lld %d[", | 6918 sqlite3_snprintf(sizeof(buf), buf, "[%lld %d[", |
6648 dlrDocid(&dlReader), iColumn); | 6919 dlrDocid(&dlReader), iColumn); |
6649 dataBufferAppend(&dump, buf, strlen(buf)); | 6920 dataBufferAppend(&dump, buf, strlen(buf)); |
6650 | 6921 |
6651 for( ; !plrAtEnd(&plReader); plrStep(&plReader) ){ | 6922 for( ; !plrAtEnd(&plReader); rc = plrStep(&plReader) ){ |
| 6923 if( rc!=SQLITE_OK ) break; |
6652 if( plrColumn(&plReader)!=iColumn ){ | 6924 if( plrColumn(&plReader)!=iColumn ){ |
6653 iColumn = plrColumn(&plReader); | 6925 iColumn = plrColumn(&plReader); |
6654 sqlite3_snprintf(sizeof(buf), buf, "] %d[", iColumn); | 6926 sqlite3_snprintf(sizeof(buf), buf, "] %d[", iColumn); |
6655 assert( dump.nData>0 ); | 6927 assert( dump.nData>0 ); |
6656 dump.nData--; /* Overwrite trailing space. */ | 6928 dump.nData--; /* Overwrite trailing space. */ |
6657 assert( dump.pData[dump.nData]==' '); | 6929 assert( dump.pData[dump.nData]==' '); |
6658 dataBufferAppend(&dump, buf, strlen(buf)); | 6930 dataBufferAppend(&dump, buf, strlen(buf)); |
6659 } | 6931 } |
6660 if( DL_DEFAULT==DL_POSITIONS_OFFSETS ){ | 6932 if( DL_DEFAULT==DL_POSITIONS_OFFSETS ){ |
6661 sqlite3_snprintf(sizeof(buf), buf, "%d,%d,%d ", | 6933 sqlite3_snprintf(sizeof(buf), buf, "%d,%d,%d ", |
6662 plrPosition(&plReader), | 6934 plrPosition(&plReader), |
6663 plrStartOffset(&plReader), plrEndOffset(&plReader)); | 6935 plrStartOffset(&plReader), plrEndOffset(&plReader)); |
6664 }else if( DL_DEFAULT==DL_POSITIONS ){ | 6936 }else if( DL_DEFAULT==DL_POSITIONS ){ |
6665 sqlite3_snprintf(sizeof(buf), buf, "%d ", plrPosition(&plReader)); | 6937 sqlite3_snprintf(sizeof(buf), buf, "%d ", plrPosition(&plReader)); |
6666 }else{ | 6938 }else{ |
6667 assert( NULL=="Unhandled DL_DEFAULT value"); | 6939 assert( NULL=="Unhandled DL_DEFAULT value"); |
6668 } | 6940 } |
6669 dataBufferAppend(&dump, buf, strlen(buf)); | 6941 dataBufferAppend(&dump, buf, strlen(buf)); |
6670 } | 6942 } |
6671 plrDestroy(&plReader); | 6943 plrDestroy(&plReader); |
| 6944 if( rc!= SQLITE_OK ) break; |
6672 | 6945 |
6673 assert( dump.nData>0 ); | 6946 assert( dump.nData>0 ); |
6674 dump.nData--; /* Overwrite trailing space. */ | 6947 dump.nData--; /* Overwrite trailing space. */ |
6675 assert( dump.pData[dump.nData]==' '); | 6948 assert( dump.pData[dump.nData]==' '); |
6676 dataBufferAppend(&dump, "]] ", 3); | 6949 dataBufferAppend(&dump, "]] ", 3); |
6677 } | 6950 } |
6678 } | 6951 } |
6679 dlrDestroy(&dlReader); | 6952 dlrDestroy(&dlReader); |
| 6953 if( rc!=SQLITE_OK ){ |
| 6954 dataBufferDestroy(&dump); |
| 6955 return rc; |
| 6956 } |
6680 | 6957 |
6681 assert( dump.nData>0 ); | 6958 assert( dump.nData>0 ); |
6682 dump.nData--; /* Overwrite trailing space. */ | 6959 dump.nData--; /* Overwrite trailing space. */ |
6683 assert( dump.pData[dump.nData]==' '); | 6960 assert( dump.pData[dump.nData]==' '); |
6684 dump.pData[dump.nData] = '\0'; | 6961 dump.pData[dump.nData] = '\0'; |
6685 assert( dump.nData>0 ); | 6962 assert( dump.nData>0 ); |
6686 | 6963 |
6687 /* Passes ownership of dump's buffer to pContext. */ | 6964 /* Passes ownership of dump's buffer to pContext. */ |
6688 sqlite3_result_text(pContext, dump.pData, dump.nData, sqlite3_free); | 6965 sqlite3_result_text(pContext, dump.pData, dump.nData, sqlite3_free); |
6689 dump.pData = NULL; | 6966 dump.pData = NULL; |
6690 dump.nData = dump.nCapacity = 0; | 6967 dump.nData = dump.nCapacity = 0; |
| 6968 return SQLITE_OK; |
6691 } | 6969 } |
6692 | 6970 |
6693 /* Implements dump_doclist() for use in inspecting the fts2 index from | 6971 /* Implements dump_doclist() for use in inspecting the fts2 index from |
6694 ** tests. TEXT result containing a string representation of the | 6972 ** tests. TEXT result containing a string representation of the |
6695 ** doclist for the indicated term. dump_doclist(t, term, level, idx) | 6973 ** doclist for the indicated term. dump_doclist(t, term, level, idx) |
6696 ** dumps the doclist for term from the segment specified by level, idx | 6974 ** dumps the doclist for term from the segment specified by level, idx |
6697 ** (in %_segdir), while dump_doclist(t, term) dumps the logical | 6975 ** (in %_segdir), while dump_doclist(t, term) dumps the logical |
6698 ** doclist for the term across all segments. The per-segment doclist | 6976 ** doclist for the term across all segments. The per-segment doclist |
6699 ** can contain deletions, while the full-index doclist will not | 6977 ** can contain deletions, while the full-index doclist will not |
6700 ** (deletions are omitted). | 6978 ** (deletions are omitted). |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7002 sqlite3 *db, | 7280 sqlite3 *db, |
7003 char **pzErrMsg, | 7281 char **pzErrMsg, |
7004 const sqlite3_api_routines *pApi | 7282 const sqlite3_api_routines *pApi |
7005 ){ | 7283 ){ |
7006 SQLITE_EXTENSION_INIT2(pApi) | 7284 SQLITE_EXTENSION_INIT2(pApi) |
7007 return sqlite3Fts2Init(db); | 7285 return sqlite3Fts2Init(db); |
7008 } | 7286 } |
7009 #endif | 7287 #endif |
7010 | 7288 |
7011 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ | 7289 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ |
OLD | NEW |