Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix various problems in fts5 revealed by fault-injection tests. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | fts5 |
Files: | files | file ages | folders |
SHA1: |
e358c3de5c916f2c851ab9324ceaae4e |
User & Date: | dan 2014-12-18 18:25:48.377 |
Context
2014-12-18
| ||
20:01 | Fix a problem with prefix queries and the AND operator. (check-in: 38b3c65e3e user: dan tags: fts5) | |
18:25 | Fix various problems in fts5 revealed by fault-injection tests. (check-in: e358c3de5c user: dan tags: fts5) | |
2014-12-03
| ||
17:27 | Begin testing fts5 OOM and IO error handling. (check-in: 2037dba62f user: dan tags: fts5) | |
Changes
Changes to ext/fts5/fts5.c.
︙ | |||
219 220 221 222 223 224 225 | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | - + | case FTS5_COMMIT: assert( p->ts.eState==2 ); p->ts.eState = 0; break; case FTS5_ROLLBACK: |
︙ |
Changes to ext/fts5/fts5_config.c.
︙ | |||
70 71 72 73 74 75 76 77 78 79 | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | + + - + + + - - + - + - + - + - + | static int fts5ConfigParseSpecial( Fts5Config *pConfig, /* Configuration object to update */ char *zCmd, /* Special command to parse */ char *zArg, /* Argument to parse */ char **pzErr /* OUT: Error message */ ){ if( sqlite3_stricmp(zCmd, "prefix")==0 ){ const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES; int rc = SQLITE_OK; char *p; if( pConfig->aPrefix ){ *pzErr = sqlite3_mprintf("multiple prefix=... directives"); |
︙ | |||
187 188 189 190 191 192 193 | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | - + | rc = fts5ConfigParseSpecial(pRet, zDup, zArg, pzErr); sqlite3_free(zDup); zDup = 0; } } /* If it is not a special directive, it must be a column name. In |
︙ |
Changes to ext/fts5/fts5_expr.c.
︙ | |||
209 210 211 212 213 214 215 216 217 218 219 220 221 222 | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | + | sqlite3Fts5ParserFree(pEngine, fts5ParseFree); assert( sParse.pExpr==0 || (sParse.rc==SQLITE_OK && sParse.zErr==0) ); if( sParse.rc==SQLITE_OK ){ *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr)); if( pNew==0 ){ sParse.rc = SQLITE_NOMEM; sqlite3Fts5ParseNodeFree(sParse.pExpr); }else{ pNew->pRoot = sParse.pExpr; pNew->pIndex = 0; pNew->apExprPhrase = sParse.apPhrase; pNew->nPhrase = sParse.nPhrase; sParse.apPhrase = 0; } |
︙ | |||
767 768 769 770 771 772 773 | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 | + - + | pTerm = &pPhrase->aTerm[j]; rc = sqlite3Fts5IndexQuery( pExpr->pIndex, pTerm->zTerm, strlen(pTerm->zTerm), (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | (pExpr->bAsc ? FTS5INDEX_QUERY_ASC : 0), &pTerm->pIter ); assert( rc==SQLITE_OK || pTerm->pIter==0 ); |
︙ | |||
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 | 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 | + + + - + + + + + - - - + + + - - - - + + | int bPrefix /* True if there is a trailing "*" */ ){ Fts5Config *pConfig = pParse->pConfig; TokenCtx sCtx; /* Context object passed to callback */ int rc; /* Tokenize return code */ char *z = 0; memset(&sCtx, 0, sizeof(TokenCtx)); sCtx.pPhrase = pPhrase; if( pPhrase==0 ){ if( (pParse->nPhrase % 8)==0 ){ int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); Fts5ExprPhrase **apNew; apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte); |
︙ |
Changes to ext/fts5/fts5_index.c.
︙ | |||
598 599 600 601 602 603 604 | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 | - - - - - - - + + + + + + + + | /* ** Allocate and return a buffer at least nByte bytes in size. ** ** If an OOM error is encountered, return NULL and set the error code in ** the Fts5Index handle passed as the first argument. */ static void *fts5IdxMalloc(Fts5Index *p, int nByte){ |
︙ | |||
658 659 660 661 662 663 664 | 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 | - + + | /* ** Close the read-only blob handle, if it is open. */ static void fts5CloseReader(Fts5Index *p){ if( p->pReader ){ |
︙ | |||
703 704 705 706 707 708 709 | 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 | - - - + + + + | ); } if( rc==SQLITE_OK ){ int nByte = sqlite3_blob_bytes(p->pReader); if( pBuf ){ fts5BufferZero(pBuf); |
︙ | |||
849 850 851 852 853 854 855 856 857 858 859 860 861 862 | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 | + + + + + + + + + + + + + + | ** Remove all records associated with segment iSegid in index iIdx. */ static void fts5DataRemoveSegment(Fts5Index *p, int iIdx, int iSegid){ i64 iFirst = FTS5_SEGMENT_ROWID(iIdx, iSegid, 0, 0); i64 iLast = FTS5_SEGMENT_ROWID(iIdx, iSegid+1, 0, 0)-1; fts5DataDelete(p, iFirst, iLast); } /* ** Release a reference to an Fts5Structure object returned by an earlier ** call to fts5StructureRead() or fts5StructureDecode(). */ static void fts5StructureRelease(Fts5Structure *pStruct){ if( pStruct ){ int i; for(i=0; i<pStruct->nLevel; i++){ sqlite3_free(pStruct->aLevel[i].aSeg); } sqlite3_free(pStruct); } } /* ** Deserialize and return the structure record currently stored in serialized ** form within buffer pData/nData. ** ** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array ** are over-allocated by one slot. This allows the structure contents |
︙ | |||
914 915 916 917 918 919 920 921 922 923 924 925 926 927 | 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 | + + + | pLvl->nSeg = nTotal; for(iSeg=0; iSeg<nTotal; iSeg++){ i += getVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid); i += getVarint32(&pData[i], pLvl->aSeg[iSeg].nHeight); i += getVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst); i += getVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast); } }else{ fts5StructureRelease(pRet); pRet = 0; } } } *ppOut = pRet; return rc; } |
︙ | |||
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 | 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 | + + + + - - - - - - - - - - - - | p->rc = fts5StructureDecode(pData->p, pData->n, &iCookie, &pRet); if( p->rc==SQLITE_OK && p->pConfig->iCookie!=iCookie ){ p->rc = sqlite3Fts5ConfigLoad(p->pConfig, iCookie); } fts5DataRelease(pData); if( p->rc!=SQLITE_OK ){ fts5StructureRelease(pRet); pRet = 0; } return pRet; } |
︙ | |||
1041 1042 1043 1044 1045 1046 1047 | 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 | + - - - - + + + + - - + + - - - - + + + + - - - + + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - + + + | /* ** Serialize and store the "structure" record for index iIdx. ** ** If an error occurs, leave an error code in the Fts5Index object. If an ** error has already occurred, this function is a no-op. */ static void fts5StructureWrite(Fts5Index *p, int iIdx, Fts5Structure *pStruct){ if( p->rc==SQLITE_OK ){ |
︙ | |||
1860 1861 1862 1863 1864 1865 1866 | 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 | - + - + | int res; pIter->iLeafOffset = fts5GetU16(&pIter->pLeaf->p[2]); fts5SegIterLoadTerm(p, pIter, 0); do { res = fts5BufferCompareBlob(&pIter->term, pTerm, nTerm); if( res>=0 ) break; fts5SegIterNext(p, pIter); |
︙ | |||
2418 2419 2420 2421 2422 2423 2424 | 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 | - + | */ static void fts5IndexDiscardData(Fts5Index *p){ assert( p->apHash || p->nPendingData==0 ); if( p->apHash ){ Fts5Config *pConfig = p->pConfig; int i; for(i=0; i<=pConfig->nPrefix; i++){ |
︙ | |||
2605 2606 2607 2608 2609 2610 2611 | 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 | - - + + | Fts5Index *p, Fts5SegWriter *pWriter, int nTerm, const u8 *pTerm ){ int nPrefix; /* Bytes of prefix compression for term */ Fts5PageWriter *pPage = &pWriter->aWriter[0]; |
︙ | |||
2656 2657 2658 2659 2660 2661 2662 | 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 | + - + - - - - - - - + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - + + + + + - - - - - + + + + + + | ** Append a docid to the writers output. */ static void fts5WriteAppendRowid( Fts5Index *p, Fts5SegWriter *pWriter, i64 iRowid ){ if( p->rc==SQLITE_OK ){ |
︙ | |||
2740 2741 2742 2743 2744 2745 2746 | 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 | + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + - - + + + | static void fts5WriteFinish( Fts5Index *p, Fts5SegWriter *pWriter, /* Writer object */ int *pnHeight, /* OUT: Height of the b-tree */ int *pnLeaf /* OUT: Number of leaf pages in b-tree */ ){ int i; if( p->rc==SQLITE_OK ){ |
︙ | |||
3021 3022 3023 3024 3025 3026 3027 | 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 | + - - - - + + + + - - - - - + + + + + - - - - + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - + + + - - - - - - - - - + + + + + + + + + + | */ static void fts5IndexWork( Fts5Index *p, /* FTS5 backend object */ int iIdx, /* Index to work on */ Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */ int nLeaf /* Number of output leaves just written */ ){ if( p->rc==SQLITE_OK ){ |
︙ | |||
3119 3120 3121 3122 3123 3124 3125 | 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 | - + - + - + - - + + | static int fts5FlushNewEntry( void *pCtx, i64 iRowid, const u8 *aPoslist, int nPoslist ){ Fts5FlushCtx *p = (Fts5FlushCtx*)pCtx; |
︙ | |||
3481 3482 3483 3484 3485 3486 3487 | 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 | + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + | */ static void fts5MultiIterPoslist( Fts5Index *p, Fts5MultiSegIter *pMulti, int bSz, Fts5Buffer *pBuf ){ if( p->rc==SQLITE_OK ){ |
︙ |
Changes to src/vtab.c.
︙ | |||
785 786 787 788 789 790 791 792 | 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 | + + - + - + - | ** the offset of the method to call in the sqlite3_module structure. ** ** The array is cleared after invoking the callbacks. */ static void callFinaliser(sqlite3 *db, int offset){ int i; if( db->aVTrans ){ VTable **aVTrans = db->aVTrans; db->aVTrans = 0; for(i=0; i<db->nVTrans; i++){ |
︙ |
Changes to test/fts5fault1.test.
︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | + + + + + + + + + + - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | set testprefix fts5fault1 # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts5 { finish_test return } # Simple tests: # # 1: CREATE VIRTUAL TABLE # 2: INSERT statement # 3: DELETE statement # 4: MATCH expressions # if 1 { faultsim_save_and_close do_faultsim_test 1 -prep { faultsim_restore_and_reopen } -body { |
Changes to test/malloc_common.tcl.
︙ | |||
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | + + - + + | if {$n != "interrupt"} {lappend DEFAULT(-faults) $n} } set DEFAULT(-prep) "" set DEFAULT(-body) "" set DEFAULT(-test) "" set DEFAULT(-install) "" set DEFAULT(-uninstall) "" set DEFAULT(-start) 1 set DEFAULT(-end) 0 fix_testname name array set O [array get DEFAULT] array set O $args foreach o [array names O] { if {[info exists DEFAULT($o)]==0} { error "unknown option: $o" } } set faultlist [list] foreach f $O(-faults) { set flist [array names FAULTSIM $f] if {[llength $flist]==0} { error "unknown fault: $f" } set faultlist [concat $faultlist $flist] } set testspec [list -prep $O(-prep) -body $O(-body) \ |
︙ | |||
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | + + + + - + + + + | # # -prep Script to execute before -body. # # -body Script to execute (with fault injection). # # -test Script to execute after -body. # # -start Index of first fault to inject (default 1) # proc do_one_faultsim_test {testname args} { set DEFAULT(-injectstart) "expr" set DEFAULT(-injectstop) "expr 0" set DEFAULT(-injecterrlist) [list] set DEFAULT(-injectinstall) "" set DEFAULT(-injectuninstall) "" set DEFAULT(-prep) "" set DEFAULT(-body) "" set DEFAULT(-test) "" set DEFAULT(-install) "" set DEFAULT(-uninstall) "" set DEFAULT(-start) 1 set DEFAULT(-end) 0 array set O [array get DEFAULT] array set O $args foreach o [array names O] { if {[info exists DEFAULT($o)]==0} { error "unknown option: $o" } } proc faultsim_test_proc {testrc testresult testnfail} $O(-test) proc faultsim_test_result {args} " uplevel faultsim_test_result_int \$args [list $O(-injecterrlist)] " eval $O(-injectinstall) eval $O(-install) set stop 0 |
︙ |