| OLD | NEW |
| 1 diff -ru ext-orig/fts2/fts2.c ext/fts2/fts2.c | 1 From 106d71238a58d4dfbeb8cf1cba45a1c4e6f583e8 Mon Sep 17 00:00:00 2001 |
| 2 --- ext-orig/fts2/fts2.c» 2009-09-04 13:37:41.000000000 -0700 | 2 From: Chris Evans <cevans@chromium.org> |
| 3 +++ ext/fts2/fts2.c» 2009-09-30 14:48:14.000000000 -0700 | 3 Date: Wed, 30 Sep 2009 23:10:34 +0000 |
| 4 @@ -37,6 +37,20 @@ | 4 Subject: [PATCH 23/23] [fts2] Fix numerous out-of-bounds bugs reading corrupt |
| 5 ** This is an SQLite module implementing full-text search. | 5 database. |
| 6 */ | 6 |
| 7 | 7 Fix numerous bugs in fts2 where a corrupt fts2 database could cause |
| 8 +/* TODO(shess): To make it easier to spot changes without groveling | 8 out-of-bounds reads and writes. |
| 9 +** through changelogs, I've defined GEARS_FTS2_CHANGES to call them | 9 |
| 10 +** out, and I will document them here. On imports, these changes | 10 Original review URL is more descriptive: |
| 11 +** should be reviewed to make sure they are still present, or are | 11 http://codereview.chromium.org/216026 |
| 12 +** dropped as appropriate. | 12 --- |
| 13 +** | 13 third_party/sqlite/src/ext/fts2/fts2.c | 751 ++++++++++++++++++++++----------- |
| 14 +** SQLite core adds the custom function fts2_tokenizer() to be used | 14 1 file changed, 514 insertions(+), 237 deletions(-) |
| 15 +** for defining new tokenizers. The second parameter is a vtable | 15 |
| 16 +** pointer encoded as a blob. Obviously this cannot be exposed to | 16 diff --git a/third_party/sqlite/src/ext/fts2/fts2.c b/third_party/sqlite/src/ext
/fts2/fts2.c |
| 17 +** Gears callers for security reasons. It could be suppressed in the | 17 index d5587b3..36d14ff 100644 |
| 18 +** authorizer, but for now I have simply commented the definition out. | 18 --- a/third_party/sqlite/src/ext/fts2/fts2.c |
| 19 +*/ | 19 +++ b/third_party/sqlite/src/ext/fts2/fts2.c |
| 20 +#define GEARS_FTS2_CHANGES 1 | 20 @@ -447,30 +447,41 @@ static int putVarint(char *p, sqlite_int64 v){ |
| 21 + | |
| 22 /* | |
| 23 ** The code in this file is only compiled if: | |
| 24 ** | |
| 25 @@ -326,8 +326,10 @@ | |
| 26 #include "fts2_hash.h" | |
| 27 #include "fts2_tokenizer.h" | |
| 28 #include "sqlite3.h" | |
| 29 -#include "sqlite3ext.h" | |
| 30 -SQLITE_EXTENSION_INIT1 | |
| 31 +#ifndef SQLITE_CORE | |
| 32 +# include "sqlite3ext.h" | |
| 33 + SQLITE_EXTENSION_INIT1 | |
| 34 +#endif | |
| 35 | |
| 36 | |
| 37 /* TODO(shess) MAN, this thing needs some refactoring. At minimum, it | |
| 38 @@ -335,6 +349,16 @@ | |
| 39 # define TRACE(A) | |
| 40 #endif | |
| 41 | |
| 42 +#if 0 | |
| 43 +/* Useful to set breakpoints. See main.c sqlite3Corrupt(). */ | |
| 44 +static int fts2Corrupt(void){ | |
| 45 + return SQLITE_CORRUPT; | |
| 46 +} | |
| 47 +# define SQLITE_CORRUPT_BKPT fts2Corrupt() | |
| 48 +#else | |
| 49 +# define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT | |
| 50 +#endif | |
| 51 + | |
| 52 /* It is not safe to call isspace(), tolower(), or isalnum() on | |
| 53 ** hi-bit-set characters. This is the same solution used in the | |
| 54 ** tokenizer. | |
| 55 @@ -423,30 +447,41 @@ | |
| 56 /* Read a 64-bit variable-length integer from memory starting at p[0]. | 21 /* Read a 64-bit variable-length integer from memory starting at p[0]. |
| 57 * Return the number of bytes read, or 0 on error. | 22 * Return the number of bytes read, or 0 on error. |
| 58 * The value is stored in *v. */ | 23 * The value is stored in *v. */ |
| 59 -static int getVarint(const char *p, sqlite_int64 *v){ | 24 -static int getVarint(const char *p, sqlite_int64 *v){ |
| 60 +static int getVarintSafe(const char *p, sqlite_int64 *v, int max){ | 25 +static int getVarintSafe(const char *p, sqlite_int64 *v, int max){ |
| 61 const unsigned char *q = (const unsigned char *) p; | 26 const unsigned char *q = (const unsigned char *) p; |
| 62 sqlite_uint64 x = 0, y = 1; | 27 sqlite_uint64 x = 0, y = 1; |
| 63 - while( (*q & 0x80) == 0x80 ){ | 28 - while( (*q & 0x80) == 0x80 ){ |
| 64 + if( max>VARINT_MAX ) max = VARINT_MAX; | 29 + if( max>VARINT_MAX ) max = VARINT_MAX; |
| 65 + while( max && (*q & 0x80) == 0x80 ){ | 30 + while( max && (*q & 0x80) == 0x80 ){ |
| (...skipping 29 matching lines...) Expand all Loading... |
| 95 return ret; | 60 return ret; |
| 96 } | 61 } |
| 97 | 62 |
| 98 +static int getVarint32(const char* p, int *pi){ | 63 +static int getVarint32(const char* p, int *pi){ |
| 99 + return getVarint32Safe(p, pi, VARINT_MAX); | 64 + return getVarint32Safe(p, pi, VARINT_MAX); |
| 100 +} | 65 +} |
| 101 + | 66 + |
| 102 /*******************************************************************/ | 67 /*******************************************************************/ |
| 103 /* DataBuffer is used to collect data into a buffer in piecemeal | 68 /* DataBuffer is used to collect data into a buffer in piecemeal |
| 104 ** fashion. It implements the usual distinction between amount of | 69 ** fashion. It implements the usual distinction between amount of |
| 105 @@ -615,7 +650,7 @@ | 70 @@ -639,7 +650,7 @@ typedef struct DLReader { |
| 106 | 71 |
| 107 static int dlrAtEnd(DLReader *pReader){ | 72 static int dlrAtEnd(DLReader *pReader){ |
| 108 assert( pReader->nData>=0 ); | 73 assert( pReader->nData>=0 ); |
| 109 - return pReader->nData==0; | 74 - return pReader->nData==0; |
| 110 + return pReader->nData<=0; | 75 + return pReader->nData<=0; |
| 111 } | 76 } |
| 112 static sqlite_int64 dlrDocid(DLReader *pReader){ | 77 static sqlite_int64 dlrDocid(DLReader *pReader){ |
| 113 assert( !dlrAtEnd(pReader) ); | 78 assert( !dlrAtEnd(pReader) ); |
| 114 @@ -639,7 +674,8 @@ | 79 @@ -663,7 +674,8 @@ static int dlrAllDataBytes(DLReader *pReader){ |
| 115 */ | 80 */ |
| 116 static const char *dlrPosData(DLReader *pReader){ | 81 static const char *dlrPosData(DLReader *pReader){ |
| 117 sqlite_int64 iDummy; | 82 sqlite_int64 iDummy; |
| 118 - int n = getVarint(pReader->pData, &iDummy); | 83 - int n = getVarint(pReader->pData, &iDummy); |
| 119 + int n = getVarintSafe(pReader->pData, &iDummy, pReader->nElement); | 84 + int n = getVarintSafe(pReader->pData, &iDummy, pReader->nElement); |
| 120 + if( !n ) return NULL; | 85 + if( !n ) return NULL; |
| 121 assert( !dlrAtEnd(pReader) ); | 86 assert( !dlrAtEnd(pReader) ); |
| 122 return pReader->pData+n; | 87 return pReader->pData+n; |
| 123 } | 88 } |
| 124 @@ -649,7 +685,7 @@ | 89 @@ -673,7 +685,7 @@ static int dlrPosDataLen(DLReader *pReader){ |
| 125 assert( !dlrAtEnd(pReader) ); | 90 assert( !dlrAtEnd(pReader) ); |
| 126 return pReader->nElement-n; | 91 return pReader->nElement-n; |
| 127 } | 92 } |
| 128 -static void dlrStep(DLReader *pReader){ | 93 -static void dlrStep(DLReader *pReader){ |
| 129 +static int dlrStep(DLReader *pReader){ | 94 +static int dlrStep(DLReader *pReader){ |
| 130 assert( !dlrAtEnd(pReader) ); | 95 assert( !dlrAtEnd(pReader) ); |
| 131 | 96 |
| 132 /* Skip past current doclist element. */ | 97 /* Skip past current doclist element. */ |
| 133 @@ -658,32 +694,48 @@ | 98 @@ -682,32 +694,48 @@ static void dlrStep(DLReader *pReader){ |
| 134 pReader->nData -= pReader->nElement; | 99 pReader->nData -= pReader->nElement; |
| 135 | 100 |
| 136 /* If there is more data, read the next doclist element. */ | 101 /* If there is more data, read the next doclist element. */ |
| 137 - if( pReader->nData!=0 ){ | 102 - if( pReader->nData!=0 ){ |
| 138 + if( pReader->nData>0 ){ | 103 + if( pReader->nData>0 ){ |
| 139 sqlite_int64 iDocidDelta; | 104 sqlite_int64 iDocidDelta; |
| 140 - int iDummy, n = getVarint(pReader->pData, &iDocidDelta); | 105 - int iDummy, n = getVarint(pReader->pData, &iDocidDelta); |
| 141 + int nTotal = 0; | 106 + int nTotal = 0; |
| 142 + int iDummy, n = getVarintSafe(pReader->pData, &iDocidDelta, pReader->nData)
; | 107 + int iDummy, n = getVarintSafe(pReader->pData, &iDocidDelta, pReader->nData)
; |
| 143 + if( !n ) return SQLITE_CORRUPT_BKPT; | 108 + if( !n ) return SQLITE_CORRUPT_BKPT; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 - const char *pData, int nData){ | 150 - const char *pData, int nData){ |
| 186 +static void dlrDestroy(DLReader *pReader){ | 151 +static void dlrDestroy(DLReader *pReader){ |
| 187 + SCRAMBLE(pReader); | 152 + SCRAMBLE(pReader); |
| 188 +} | 153 +} |
| 189 +static int dlrInit(DLReader *pReader, DocListType iType, | 154 +static int dlrInit(DLReader *pReader, DocListType iType, |
| 190 + const char *pData, int nData){ | 155 + const char *pData, int nData){ |
| 191 + int rc; | 156 + int rc; |
| 192 assert( pData!=NULL && nData!=0 ); | 157 assert( pData!=NULL && nData!=0 ); |
| 193 pReader->iType = iType; | 158 pReader->iType = iType; |
| 194 pReader->pData = pData; | 159 pReader->pData = pData; |
| 195 @@ -692,10 +744,9 @@ | 160 @@ -716,10 +744,9 @@ static void dlrInit(DLReader *pReader, DocListType iType, |
| 196 pReader->iDocid = 0; | 161 pReader->iDocid = 0; |
| 197 | 162 |
| 198 /* Load the first element's data. There must be a first element. */ | 163 /* Load the first element's data. There must be a first element. */ |
| 199 - dlrStep(pReader); | 164 - dlrStep(pReader); |
| 200 -} | 165 -} |
| 201 -static void dlrDestroy(DLReader *pReader){ | 166 -static void dlrDestroy(DLReader *pReader){ |
| 202 - SCRAMBLE(pReader); | 167 - SCRAMBLE(pReader); |
| 203 + rc = dlrStep(pReader); | 168 + rc = dlrStep(pReader); |
| 204 + if( rc!=SQLITE_OK ) dlrDestroy(pReader); | 169 + if( rc!=SQLITE_OK ) dlrDestroy(pReader); |
| 205 + return rc; | 170 + return rc; |
| 206 } | 171 } |
| 207 | 172 |
| 208 #ifndef NDEBUG | 173 #ifndef NDEBUG |
| 209 @@ -782,9 +833,9 @@ | 174 @@ -806,9 +833,9 @@ static void dlwDestroy(DLWriter *pWriter){ |
| 210 /* TODO(shess) This has become just a helper for docListMerge. | 175 /* TODO(shess) This has become just a helper for docListMerge. |
| 211 ** Consider a refactor to make this cleaner. | 176 ** Consider a refactor to make this cleaner. |
| 212 */ | 177 */ |
| 213 -static void dlwAppend(DLWriter *pWriter, | 178 -static void dlwAppend(DLWriter *pWriter, |
| 214 - const char *pData, int nData, | 179 - const char *pData, int nData, |
| 215 - sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ | 180 - sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ |
| 216 +static int dlwAppend(DLWriter *pWriter, | 181 +static int dlwAppend(DLWriter *pWriter, |
| 217 + const char *pData, int nData, | 182 + const char *pData, int nData, |
| 218 + sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ | 183 + sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ |
| 219 sqlite_int64 iDocid = 0; | 184 sqlite_int64 iDocid = 0; |
| 220 char c[VARINT_MAX]; | 185 char c[VARINT_MAX]; |
| 221 int nFirstOld, nFirstNew; /* Old and new varint len of first docid. */ | 186 int nFirstOld, nFirstNew; /* Old and new varint len of first docid. */ |
| 222 @@ -793,7 +844,8 @@ | 187 @@ -817,7 +844,8 @@ static void dlwAppend(DLWriter *pWriter, |
| 223 #endif | 188 #endif |
| 224 | 189 |
| 225 /* Recode the initial docid as delta from iPrevDocid. */ | 190 /* Recode the initial docid as delta from iPrevDocid. */ |
| 226 - nFirstOld = getVarint(pData, &iDocid); | 191 - nFirstOld = getVarint(pData, &iDocid); |
| 227 + nFirstOld = getVarintSafe(pData, &iDocid, nData); | 192 + nFirstOld = getVarintSafe(pData, &iDocid, nData); |
| 228 + if( !nFirstOld ) return SQLITE_CORRUPT_BKPT; | 193 + if( !nFirstOld ) return SQLITE_CORRUPT_BKPT; |
| 229 assert( nFirstOld<nData || (nFirstOld==nData && pWriter->iType==DL_DOCIDS) ); | 194 assert( nFirstOld<nData || (nFirstOld==nData && pWriter->iType==DL_DOCIDS) ); |
| 230 nFirstNew = putVarint(c, iFirstDocid-pWriter->iPrevDocid); | 195 nFirstNew = putVarint(c, iFirstDocid-pWriter->iPrevDocid); |
| 231 | 196 |
| 232 @@ -814,10 +866,11 @@ | 197 @@ -838,10 +866,11 @@ static void dlwAppend(DLWriter *pWriter, |
| 233 dataBufferAppend(pWriter->b, c, nFirstNew); | 198 dataBufferAppend(pWriter->b, c, nFirstNew); |
| 234 } | 199 } |
| 235 pWriter->iPrevDocid = iLastDocid; | 200 pWriter->iPrevDocid = iLastDocid; |
| 236 + return SQLITE_OK; | 201 + return SQLITE_OK; |
| 237 } | 202 } |
| 238 -static void dlwCopy(DLWriter *pWriter, DLReader *pReader){ | 203 -static void dlwCopy(DLWriter *pWriter, DLReader *pReader){ |
| 239 - dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), | 204 - dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), |
| 240 - dlrDocid(pReader), dlrDocid(pReader)); | 205 - dlrDocid(pReader), dlrDocid(pReader)); |
| 241 +static int dlwCopy(DLWriter *pWriter, DLReader *pReader){ | 206 +static int dlwCopy(DLWriter *pWriter, DLReader *pReader){ |
| 242 + return dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), | 207 + return dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), |
| 243 + dlrDocid(pReader), dlrDocid(pReader)); | 208 + dlrDocid(pReader), dlrDocid(pReader)); |
| 244 } | 209 } |
| 245 static void dlwAdd(DLWriter *pWriter, sqlite_int64 iDocid){ | 210 static void dlwAdd(DLWriter *pWriter, sqlite_int64 iDocid){ |
| 246 char c[VARINT_MAX]; | 211 char c[VARINT_MAX]; |
| 247 @@ -878,45 +931,63 @@ | 212 @@ -902,45 +931,63 @@ static int plrEndOffset(PLReader *pReader){ |
| 248 assert( !plrAtEnd(pReader) ); | 213 assert( !plrAtEnd(pReader) ); |
| 249 return pReader->iEndOffset; | 214 return pReader->iEndOffset; |
| 250 } | 215 } |
| 251 -static void plrStep(PLReader *pReader){ | 216 -static void plrStep(PLReader *pReader){ |
| 252 - int i, n; | 217 - int i, n; |
| 253 +static int plrStep(PLReader *pReader){ | 218 +static int plrStep(PLReader *pReader){ |
| 254 + int i, n, nTotal = 0; | 219 + int i, n, nTotal = 0; |
| 255 | 220 |
| 256 assert( !plrAtEnd(pReader) ); | 221 assert( !plrAtEnd(pReader) ); |
| 257 | 222 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 -static void plrInit(PLReader *pReader, DLReader *pDLReader){ | 280 -static void plrInit(PLReader *pReader, DLReader *pDLReader){ |
| 316 +static void plrDestroy(PLReader *pReader){ | 281 +static void plrDestroy(PLReader *pReader){ |
| 317 + SCRAMBLE(pReader); | 282 + SCRAMBLE(pReader); |
| 318 +} | 283 +} |
| 319 + | 284 + |
| 320 +static int plrInit(PLReader *pReader, DLReader *pDLReader){ | 285 +static int plrInit(PLReader *pReader, DLReader *pDLReader){ |
| 321 + int rc; | 286 + int rc; |
| 322 pReader->pData = dlrPosData(pDLReader); | 287 pReader->pData = dlrPosData(pDLReader); |
| 323 pReader->nData = dlrPosDataLen(pDLReader); | 288 pReader->nData = dlrPosDataLen(pDLReader); |
| 324 pReader->iType = pDLReader->iType; | 289 pReader->iType = pDLReader->iType; |
| 325 @@ -924,10 +995,9 @@ | 290 @@ -948,10 +995,9 @@ static void plrInit(PLReader *pReader, DLReader *pDLReader)
{ |
| 326 pReader->iPosition = 0; | 291 pReader->iPosition = 0; |
| 327 pReader->iStartOffset = 0; | 292 pReader->iStartOffset = 0; |
| 328 pReader->iEndOffset = 0; | 293 pReader->iEndOffset = 0; |
| 329 - plrStep(pReader); | 294 - plrStep(pReader); |
| 330 -} | 295 -} |
| 331 -static void plrDestroy(PLReader *pReader){ | 296 -static void plrDestroy(PLReader *pReader){ |
| 332 - SCRAMBLE(pReader); | 297 - SCRAMBLE(pReader); |
| 333 + rc = plrStep(pReader); | 298 + rc = plrStep(pReader); |
| 334 + if( rc!=SQLITE_OK ) plrDestroy(pReader); | 299 + if( rc!=SQLITE_OK ) plrDestroy(pReader); |
| 335 + return rc; | 300 + return rc; |
| 336 } | 301 } |
| 337 | 302 |
| 338 /*******************************************************************/ | 303 /*******************************************************************/ |
| 339 @@ -1113,14 +1183,16 @@ | 304 @@ -1137,14 +1183,16 @@ static void dlcDelete(DLCollector *pCollector){ |
| 340 ** deletion will be trimmed, and will thus not effect a deletion | 305 ** deletion will be trimmed, and will thus not effect a deletion |
| 341 ** during the merge. | 306 ** during the merge. |
| 342 */ | 307 */ |
| 343 -static void docListTrim(DocListType iType, const char *pData, int nData, | 308 -static void docListTrim(DocListType iType, const char *pData, int nData, |
| 344 - int iColumn, DocListType iOutType, DataBuffer *out){ | 309 - int iColumn, DocListType iOutType, DataBuffer *out){ |
| 345 +static int docListTrim(DocListType iType, const char *pData, int nData, | 310 +static int docListTrim(DocListType iType, const char *pData, int nData, |
| 346 + int iColumn, DocListType iOutType, DataBuffer *out){ | 311 + int iColumn, DocListType iOutType, DataBuffer *out){ |
| 347 DLReader dlReader; | 312 DLReader dlReader; |
| 348 DLWriter dlWriter; | 313 DLWriter dlWriter; |
| 349 + int rc; | 314 + int rc; |
| 350 | 315 |
| 351 assert( iOutType<=iType ); | 316 assert( iOutType<=iType ); |
| 352 | 317 |
| 353 - dlrInit(&dlReader, iType, pData, nData); | 318 - dlrInit(&dlReader, iType, pData, nData); |
| 354 + rc = dlrInit(&dlReader, iType, pData, nData); | 319 + rc = dlrInit(&dlReader, iType, pData, nData); |
| 355 + if( rc!=SQLITE_OK ) return rc; | 320 + if( rc!=SQLITE_OK ) return rc; |
| 356 dlwInit(&dlWriter, iOutType, out); | 321 dlwInit(&dlWriter, iOutType, out); |
| 357 | 322 |
| 358 while( !dlrAtEnd(&dlReader) ){ | 323 while( !dlrAtEnd(&dlReader) ){ |
| 359 @@ -1128,7 +1200,8 @@ | 324 @@ -1152,7 +1200,8 @@ static void docListTrim(DocListType iType, const char *pDa
ta, int nData, |
| 360 PLWriter plWriter; | 325 PLWriter plWriter; |
| 361 int match = 0; | 326 int match = 0; |
| 362 | 327 |
| 363 - plrInit(&plReader, &dlReader); | 328 - plrInit(&plReader, &dlReader); |
| 364 + rc = plrInit(&plReader, &dlReader); | 329 + rc = plrInit(&plReader, &dlReader); |
| 365 + if( rc!=SQLITE_OK ) break; | 330 + if( rc!=SQLITE_OK ) break; |
| 366 | 331 |
| 367 while( !plrAtEnd(&plReader) ){ | 332 while( !plrAtEnd(&plReader) ){ |
| 368 if( iColumn==-1 || plrColumn(&plReader)==iColumn ){ | 333 if( iColumn==-1 || plrColumn(&plReader)==iColumn ){ |
| 369 @@ -1139,7 +1212,11 @@ | 334 @@ -1163,7 +1212,11 @@ static void docListTrim(DocListType iType, const char *pD
ata, int nData, |
| 370 plwAdd(&plWriter, plrColumn(&plReader), plrPosition(&plReader), | 335 plwAdd(&plWriter, plrColumn(&plReader), plrPosition(&plReader), |
| 371 plrStartOffset(&plReader), plrEndOffset(&plReader)); | 336 plrStartOffset(&plReader), plrEndOffset(&plReader)); |
| 372 } | 337 } |
| 373 - plrStep(&plReader); | 338 - plrStep(&plReader); |
| 374 + rc = plrStep(&plReader); | 339 + rc = plrStep(&plReader); |
| 375 + if( rc!=SQLITE_OK ){ | 340 + if( rc!=SQLITE_OK ){ |
| 376 + plrDestroy(&plReader); | 341 + plrDestroy(&plReader); |
| 377 + goto err; | 342 + goto err; |
| 378 + } | 343 + } |
| 379 } | 344 } |
| 380 if( match ){ | 345 if( match ){ |
| 381 plwTerminate(&plWriter); | 346 plwTerminate(&plWriter); |
| 382 @@ -1147,10 +1224,13 @@ | 347 @@ -1171,10 +1224,13 @@ static void docListTrim(DocListType iType, const char *p
Data, int nData, |
| 383 } | 348 } |
| 384 | 349 |
| 385 plrDestroy(&plReader); | 350 plrDestroy(&plReader); |
| 386 - dlrStep(&dlReader); | 351 - dlrStep(&dlReader); |
| 387 + rc = dlrStep(&dlReader); | 352 + rc = dlrStep(&dlReader); |
| 388 + if( rc!=SQLITE_OK ) break; | 353 + if( rc!=SQLITE_OK ) break; |
| 389 } | 354 } |
| 390 +err: | 355 +err: |
| 391 dlwDestroy(&dlWriter); | 356 dlwDestroy(&dlWriter); |
| 392 dlrDestroy(&dlReader); | 357 dlrDestroy(&dlReader); |
| 393 + return rc; | 358 + return rc; |
| 394 } | 359 } |
| 395 | 360 |
| 396 /* Used by docListMerge() to keep doclists in the ascending order by | 361 /* Used by docListMerge() to keep doclists in the ascending order by |
| 397 @@ -1207,19 +1287,20 @@ | 362 @@ -1231,19 +1287,20 @@ static void orderedDLReaderReorder(OrderedDLReader *p, i
nt n){ |
| 398 /* TODO(shess) nReaders must be <= MERGE_COUNT. This should probably | 363 /* TODO(shess) nReaders must be <= MERGE_COUNT. This should probably |
| 399 ** be fixed. | 364 ** be fixed. |
| 400 */ | 365 */ |
| 401 -static void docListMerge(DataBuffer *out, | 366 -static void docListMerge(DataBuffer *out, |
| 402 - DLReader *pReaders, int nReaders){ | 367 - DLReader *pReaders, int nReaders){ |
| 403 +static int docListMerge(DataBuffer *out, | 368 +static int docListMerge(DataBuffer *out, |
| 404 + DLReader *pReaders, int nReaders){ | 369 + DLReader *pReaders, int nReaders){ |
| 405 OrderedDLReader readers[MERGE_COUNT]; | 370 OrderedDLReader readers[MERGE_COUNT]; |
| 406 DLWriter writer; | 371 DLWriter writer; |
| 407 int i, n; | 372 int i, n; |
| 408 const char *pStart = 0; | 373 const char *pStart = 0; |
| 409 int nStart = 0; | 374 int nStart = 0; |
| 410 sqlite_int64 iFirstDocid = 0, iLastDocid = 0; | 375 sqlite_int64 iFirstDocid = 0, iLastDocid = 0; |
| 411 + int rc = SQLITE_OK; | 376 + int rc = SQLITE_OK; |
| 412 | 377 |
| 413 assert( nReaders>0 ); | 378 assert( nReaders>0 ); |
| 414 if( nReaders==1 ){ | 379 if( nReaders==1 ){ |
| 415 dataBufferAppend(out, dlrDocData(pReaders), dlrAllDataBytes(pReaders)); | 380 dataBufferAppend(out, dlrDocData(pReaders), dlrAllDataBytes(pReaders)); |
| 416 - return; | 381 - return; |
| 417 + return SQLITE_OK; | 382 + return SQLITE_OK; |
| 418 } | 383 } |
| 419 | 384 |
| 420 assert( nReaders<=MERGE_COUNT ); | 385 assert( nReaders<=MERGE_COUNT ); |
| 421 @@ -1252,20 +1333,23 @@ | 386 @@ -1276,20 +1333,23 @@ static void docListMerge(DataBuffer *out, |
| 422 nStart += dlrDocDataBytes(readers[0].pReader); | 387 nStart += dlrDocDataBytes(readers[0].pReader); |
| 423 }else{ | 388 }else{ |
| 424 if( pStart!=0 ){ | 389 if( pStart!=0 ){ |
| 425 - dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | 390 - dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); |
| 426 + rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | 391 + rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); |
| 427 + if( rc!=SQLITE_OK ) goto err; | 392 + if( rc!=SQLITE_OK ) goto err; |
| 428 } | 393 } |
| 429 pStart = dlrDocData(readers[0].pReader); | 394 pStart = dlrDocData(readers[0].pReader); |
| 430 nStart = dlrDocDataBytes(readers[0].pReader); | 395 nStart = dlrDocDataBytes(readers[0].pReader); |
| 431 iFirstDocid = iDocid; | 396 iFirstDocid = iDocid; |
| 432 } | 397 } |
| 433 iLastDocid = iDocid; | 398 iLastDocid = iDocid; |
| 434 - dlrStep(readers[0].pReader); | 399 - dlrStep(readers[0].pReader); |
| 435 + rc = dlrStep(readers[0].pReader); | 400 + rc = dlrStep(readers[0].pReader); |
| 436 + if( rc!=SQLITE_OK ) goto err; | 401 + if( rc!=SQLITE_OK ) goto err; |
| 437 | 402 |
| 438 /* Drop all of the older elements with the same docid. */ | 403 /* Drop all of the older elements with the same docid. */ |
| 439 for(i=1; i<nReaders && | 404 for(i=1; i<nReaders && |
| 440 !dlrAtEnd(readers[i].pReader) && | 405 !dlrAtEnd(readers[i].pReader) && |
| 441 dlrDocid(readers[i].pReader)==iDocid; i++){ | 406 dlrDocid(readers[i].pReader)==iDocid; i++){ |
| 442 - dlrStep(readers[i].pReader); | 407 - dlrStep(readers[i].pReader); |
| 443 + rc = dlrStep(readers[i].pReader); | 408 + rc = dlrStep(readers[i].pReader); |
| 444 + if( rc!=SQLITE_OK ) goto err; | 409 + if( rc!=SQLITE_OK ) goto err; |
| 445 } | 410 } |
| 446 | 411 |
| 447 /* Get the readers back into order. */ | 412 /* Get the readers back into order. */ |
| 448 @@ -1275,8 +1359,11 @@ | 413 @@ -1299,8 +1359,11 @@ static void docListMerge(DataBuffer *out, |
| 449 } | 414 } |
| 450 | 415 |
| 451 /* Copy over any remaining elements. */ | 416 /* Copy over any remaining elements. */ |
| 452 - if( nStart>0 ) dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | 417 - if( nStart>0 ) dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); |
| 453 + if( nStart>0 ) | 418 + if( nStart>0 ) |
| 454 + rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | 419 + rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); |
| 455 +err: | 420 +err: |
| 456 dlwDestroy(&writer); | 421 dlwDestroy(&writer); |
| 457 + return rc; | 422 + return rc; |
| 458 } | 423 } |
| 459 | 424 |
| 460 /* Helper function for posListUnion(). Compares the current position | 425 /* Helper function for posListUnion(). Compares the current position |
| 461 @@ -1312,30 +1399,40 @@ | 426 @@ -1336,30 +1399,40 @@ static int posListCmp(PLReader *pLeft, PLReader *pRight)
{ |
| 462 ** work with any doclist type, though both inputs and the output | 427 ** work with any doclist type, though both inputs and the output |
| 463 ** should be the same type. | 428 ** should be the same type. |
| 464 */ | 429 */ |
| 465 -static void posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ | 430 -static void posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ |
| 466 +static int posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ | 431 +static int posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ |
| 467 PLReader left, right; | 432 PLReader left, right; |
| 468 PLWriter writer; | 433 PLWriter writer; |
| 469 + int rc; | 434 + int rc; |
| 470 | 435 |
| 471 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); | 436 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 499 plwCopy(&writer, &left); | 464 plwCopy(&writer, &left); |
| 500 - plrStep(&left); | 465 - plrStep(&left); |
| 501 - plrStep(&right); | 466 - plrStep(&right); |
| 502 + rc = plrStep(&left); | 467 + rc = plrStep(&left); |
| 503 + if( rc != SQLITE_OK ) break; | 468 + if( rc != SQLITE_OK ) break; |
| 504 + rc = plrStep(&right); | 469 + rc = plrStep(&right); |
| 505 + if( rc != SQLITE_OK ) break; | 470 + if( rc != SQLITE_OK ) break; |
| 506 } | 471 } |
| 507 } | 472 } |
| 508 | 473 |
| 509 @@ -1343,56 +1440,75 @@ | 474 @@ -1367,56 +1440,75 @@ static void posListUnion(DLReader *pLeft, DLReader *pRig
ht, DLWriter *pOut){ |
| 510 plwDestroy(&writer); | 475 plwDestroy(&writer); |
| 511 plrDestroy(&left); | 476 plrDestroy(&left); |
| 512 plrDestroy(&right); | 477 plrDestroy(&right); |
| 513 + return rc; | 478 + return rc; |
| 514 } | 479 } |
| 515 | 480 |
| 516 /* Write the union of doclists in pLeft and pRight to pOut. For | 481 /* Write the union of doclists in pLeft and pRight to pOut. For |
| 517 ** docids in common between the inputs, the union of the position | 482 ** docids in common between the inputs, the union of the position |
| 518 ** lists is written. Inputs and outputs are always type DL_DEFAULT. | 483 ** lists is written. Inputs and outputs are always type DL_DEFAULT. |
| 519 */ | 484 */ |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 } | 556 } |
| 592 } | 557 } |
| 593 | 558 |
| 594 dlrDestroy(&left); | 559 dlrDestroy(&left); |
| 595 dlrDestroy(&right); | 560 dlrDestroy(&right); |
| 596 dlwDestroy(&writer); | 561 dlwDestroy(&writer); |
| 597 + return rc; | 562 + return rc; |
| 598 } | 563 } |
| 599 | 564 |
| 600 /* pLeft and pRight are DLReaders positioned to the same docid. | 565 /* pLeft and pRight are DLReaders positioned to the same docid. |
| 601 @@ -1407,35 +1523,47 @@ | 566 @@ -1431,35 +1523,47 @@ static void docListUnion( |
| 602 ** include the positions from pRight that are one more than a | 567 ** include the positions from pRight that are one more than a |
| 603 ** position in pLeft. In other words: pRight.iPos==pLeft.iPos+1. | 568 ** position in pLeft. In other words: pRight.iPos==pLeft.iPos+1. |
| 604 */ | 569 */ |
| 605 -static void posListPhraseMerge(DLReader *pLeft, DLReader *pRight, | 570 -static void posListPhraseMerge(DLReader *pLeft, DLReader *pRight, |
| 606 - DLWriter *pOut){ | 571 - DLWriter *pOut){ |
| 607 +static int posListPhraseMerge(DLReader *pLeft, DLReader *pRight, | 572 +static int posListPhraseMerge(DLReader *pLeft, DLReader *pRight, |
| 608 + DLWriter *pOut){ | 573 + DLWriter *pOut){ |
| 609 PLReader left, right; | 574 PLReader left, right; |
| 610 PLWriter writer; | 575 PLWriter writer; |
| 611 int match = 0; | 576 int match = 0; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 649 plwAdd(&writer, plrColumn(&right), plrPosition(&right), 0, 0); | 614 plwAdd(&writer, plrColumn(&right), plrPosition(&right), 0, 0); |
| 650 - plrStep(&left); | 615 - plrStep(&left); |
| 651 - plrStep(&right); | 616 - plrStep(&right); |
| 652 + rc = plrStep(&left); | 617 + rc = plrStep(&left); |
| 653 + if( rc!=SQLITE_OK ) break; | 618 + if( rc!=SQLITE_OK ) break; |
| 654 + rc = plrStep(&right); | 619 + rc = plrStep(&right); |
| 655 + if( rc!=SQLITE_OK ) break; | 620 + if( rc!=SQLITE_OK ) break; |
| 656 } | 621 } |
| 657 } | 622 } |
| 658 | 623 |
| 659 @@ -1446,6 +1574,7 @@ | 624 @@ -1470,6 +1574,7 @@ static void posListPhraseMerge(DLReader *pLeft, DLReader *
pRight, |
| 660 | 625 |
| 661 plrDestroy(&left); | 626 plrDestroy(&left); |
| 662 plrDestroy(&right); | 627 plrDestroy(&right); |
| 663 + return rc; | 628 + return rc; |
| 664 } | 629 } |
| 665 | 630 |
| 666 /* We have two doclists with positions: pLeft and pRight. | 631 /* We have two doclists with positions: pLeft and pRight. |
| 667 @@ -1457,7 +1586,7 @@ | 632 @@ -1481,7 +1586,7 @@ static void posListPhraseMerge(DLReader *pLeft, DLReader *
pRight, |
| 668 ** iType controls the type of data written to pOut. If iType is | 633 ** iType controls the type of data written to pOut. If iType is |
| 669 ** DL_POSITIONS, the positions are those from pRight. | 634 ** DL_POSITIONS, the positions are those from pRight. |
| 670 */ | 635 */ |
| 671 -static void docListPhraseMerge( | 636 -static void docListPhraseMerge( |
| 672 +static int docListPhraseMerge( | 637 +static int docListPhraseMerge( |
| 673 const char *pLeft, int nLeft, | 638 const char *pLeft, int nLeft, |
| 674 const char *pRight, int nRight, | 639 const char *pRight, int nRight, |
| 675 DocListType iType, | 640 DocListType iType, |
| 676 @@ -1465,152 +1594,198 @@ | 641 @@ -1489,152 +1594,198 @@ static void docListPhraseMerge( |
| 677 ){ | 642 ){ |
| 678 DLReader left, right; | 643 DLReader left, right; |
| 679 DLWriter writer; | 644 DLWriter writer; |
| 680 + int rc; | 645 + int rc; |
| 681 | 646 |
| 682 - if( nLeft==0 || nRight==0 ) return; | 647 - if( nLeft==0 || nRight==0 ) return; |
| 683 + if( nLeft==0 || nRight==0 ) return SQLITE_OK; | 648 + if( nLeft==0 || nRight==0 ) return SQLITE_OK; |
| 684 | 649 |
| 685 assert( iType!=DL_POSITIONS_OFFSETS ); | 650 assert( iType!=DL_POSITIONS_OFFSETS ); |
| 686 | 651 |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 899 } | 864 } |
| 900 | 865 |
| 901 +err: | 866 +err: |
| 902 dlrDestroy(&left); | 867 dlrDestroy(&left); |
| 903 dlrDestroy(&right); | 868 dlrDestroy(&right); |
| 904 dlwDestroy(&writer); | 869 dlwDestroy(&writer); |
| 905 + return rc; | 870 + return rc; |
| 906 } | 871 } |
| 907 | 872 |
| 908 static char *string_dup_n(const char *s, int n){ | 873 static char *string_dup_n(const char *s, int n){ |
| 909 @@ -1814,7 +1989,7 @@ | 874 @@ -3437,7 +3588,8 @@ static int fulltextNext(sqlite3_vtab_cursor *pCursor){ |
| 910 /* SEGDIR_MAX_INDEX */ "select max(idx) from %_segdir where level = ?", | |
| 911 /* SEGDIR_SET */ "insert into %_segdir values (?, ?, ?, ?, ?, ?)", | |
| 912 /* SEGDIR_SELECT_LEVEL */ | |
| 913 - "select start_block, leaves_end_block, root from %_segdir " | |
| 914 + "select start_block, leaves_end_block, root, idx from %_segdir " | |
| 915 " where level = ? order by idx", | |
| 916 /* SEGDIR_SPAN */ | |
| 917 "select min(start_block), max(end_block) from %_segdir " | |
| 918 @@ -3413,7 +3588,8 @@ | |
| 919 return SQLITE_OK; | 875 return SQLITE_OK; |
| 920 } | 876 } |
| 921 rc = sqlite3_bind_int64(c->pStmt, 1, dlrDocid(&c->reader)); | 877 rc = sqlite3_bind_int64(c->pStmt, 1, dlrDocid(&c->reader)); |
| 922 - dlrStep(&c->reader); | 878 - dlrStep(&c->reader); |
| 923 + if( rc!=SQLITE_OK ) return rc; | 879 + if( rc!=SQLITE_OK ) return rc; |
| 924 + rc = dlrStep(&c->reader); | 880 + rc = dlrStep(&c->reader); |
| 925 if( rc!=SQLITE_OK ) return rc; | 881 if( rc!=SQLITE_OK ) return rc; |
| 926 /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ | 882 /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ |
| 927 rc = sqlite3_step(c->pStmt); | 883 rc = sqlite3_step(c->pStmt); |
| 928 @@ -3421,8 +3597,11 @@ | 884 @@ -3497,14 +3649,18 @@ static int docListOfTerm( |
| 929 c->eof = 0; | |
| 930 return SQLITE_OK; | |
| 931 } | |
| 932 - /* an error occurred; abort */ | |
| 933 - return rc==SQLITE_DONE ? SQLITE_ERROR : rc; | |
| 934 + | |
| 935 + /* Corrupt if the index refers to missing document. */ | |
| 936 + if( rc==SQLITE_DONE ) return SQLITE_CORRUPT_BKPT; | |
| 937 + | |
| 938 + return rc; | |
| 939 } | |
| 940 } | |
| 941 | |
| 942 @@ -3470,14 +3649,18 @@ | |
| 943 return rc; | 885 return rc; |
| 944 } | 886 } |
| 945 dataBufferInit(&new, 0); | 887 dataBufferInit(&new, 0); |
| 946 - docListPhraseMerge(left.pData, left.nData, right.pData, right.nData, | 888 - docListPhraseMerge(left.pData, left.nData, right.pData, right.nData, |
| 947 - i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &new); | 889 - i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &new); |
| 948 + rc = docListPhraseMerge(left.pData, left.nData, right.pData, right.nData, | 890 + rc = docListPhraseMerge(left.pData, left.nData, right.pData, right.nData, |
| 949 + i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &new)
; | 891 + i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &new)
; |
| 950 dataBufferDestroy(&left); | 892 dataBufferDestroy(&left); |
| 951 dataBufferDestroy(&right); | 893 dataBufferDestroy(&right); |
| 952 + if( rc!=SQLITE_OK ){ | 894 + if( rc!=SQLITE_OK ){ |
| 953 + dataBufferDestroy(&new); | 895 + dataBufferDestroy(&new); |
| 954 + return rc; | 896 + return rc; |
| 955 + } | 897 + } |
| 956 left = new; | 898 left = new; |
| 957 } | 899 } |
| 958 *pResult = left; | 900 *pResult = left; |
| 959 - return SQLITE_OK; | 901 - return SQLITE_OK; |
| 960 + return rc; | 902 + return rc; |
| 961 } | 903 } |
| 962 | 904 |
| 963 /* Add a new term pTerm[0..nTerm-1] to the query *q. | 905 /* Add a new term pTerm[0..nTerm-1] to the query *q. |
| 964 @@ -3544,6 +3727,7 @@ | 906 @@ -3749,18 +3905,30 @@ static int fulltextQuery( |
| 965 int firstIndex = pQuery->nTerms; | |
| 966 int iCol; | |
| 967 int nTerm = 1; | |
| 968 + int iEndLast = -1; | |
| 969 | |
| 970 int rc = pModule->xOpen(pTokenizer, pSegment, nSegment, &pCursor); | |
| 971 if( rc!=SQLITE_OK ) return rc; | |
| 972 @@ -3568,6 +3752,20 @@ | |
| 973 pQuery->nextIsOr = 1; | |
| 974 continue; | |
| 975 } | |
| 976 + | |
| 977 + /* | |
| 978 + * The ICU tokenizer considers '*' a break character, so the code below | |
| 979 + * sets isPrefix correctly, but since that code doesn't eat the '*', the | |
| 980 + * ICU tokenizer returns it as the next token. So eat it here until a | |
| 981 + * better solution presents itself. | |
| 982 + */ | |
| 983 + if( pQuery->nTerms>0 && nToken==1 && pSegment[iBegin]=='*' && | |
| 984 + iEndLast==iBegin){ | |
| 985 + pQuery->pTerms[pQuery->nTerms-1].isPrefix = 1; | |
| 986 + continue; | |
| 987 + } | |
| 988 + iEndLast = iEnd; | |
| 989 + | |
| 990 queryAdd(pQuery, pToken, nToken); | |
| 991 if( !inPhrase && iBegin>0 && pSegment[iBegin-1]=='-' ){ | |
| 992 pQuery->pTerms[pQuery->nTerms-1].isNot = 1; | |
| 993 @@ -3707,18 +3905,30 @@ | |
| 994 return rc; | 907 return rc; |
| 995 } | 908 } |
| 996 dataBufferInit(&new, 0); | 909 dataBufferInit(&new, 0); |
| 997 - docListOrMerge(right.pData, right.nData, or.pData, or.nData, &new); | 910 - docListOrMerge(right.pData, right.nData, or.pData, or.nData, &new); |
| 998 + rc = docListOrMerge(right.pData, right.nData, or.pData, or.nData, &new); | 911 + rc = docListOrMerge(right.pData, right.nData, or.pData, or.nData, &new); |
| 999 dataBufferDestroy(&right); | 912 dataBufferDestroy(&right); |
| 1000 dataBufferDestroy(&or); | 913 dataBufferDestroy(&or); |
| 1001 + if( rc!=SQLITE_OK ){ | 914 + if( rc!=SQLITE_OK ){ |
| 1002 + if( i!=nNot ) dataBufferDestroy(&left); | 915 + if( i!=nNot ) dataBufferDestroy(&left); |
| 1003 + queryClear(pQuery); | 916 + queryClear(pQuery); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1016 dataBufferDestroy(&right); | 929 dataBufferDestroy(&right); |
| 1017 dataBufferDestroy(&left); | 930 dataBufferDestroy(&left); |
| 1018 + if( rc!=SQLITE_OK ){ | 931 + if( rc!=SQLITE_OK ){ |
| 1019 + queryClear(pQuery); | 932 + queryClear(pQuery); |
| 1020 + dataBufferDestroy(&new); | 933 + dataBufferDestroy(&new); |
| 1021 + return rc; | 934 + return rc; |
| 1022 + } | 935 + } |
| 1023 left = new; | 936 left = new; |
| 1024 } | 937 } |
| 1025 } | 938 } |
| 1026 @@ -3738,9 +3948,15 @@ | 939 @@ -3780,9 +3948,15 @@ static int fulltextQuery( |
| 1027 return rc; | 940 return rc; |
| 1028 } | 941 } |
| 1029 dataBufferInit(&new, 0); | 942 dataBufferInit(&new, 0); |
| 1030 - docListExceptMerge(left.pData, left.nData, right.pData, right.nData, &new); | 943 - docListExceptMerge(left.pData, left.nData, right.pData, right.nData, &new); |
| 1031 + rc = docListExceptMerge(left.pData, left.nData, | 944 + rc = docListExceptMerge(left.pData, left.nData, |
| 1032 + right.pData, right.nData, &new); | 945 + right.pData, right.nData, &new); |
| 1033 dataBufferDestroy(&right); | 946 dataBufferDestroy(&right); |
| 1034 dataBufferDestroy(&left); | 947 dataBufferDestroy(&left); |
| 1035 + if( rc!=SQLITE_OK ){ | 948 + if( rc!=SQLITE_OK ){ |
| 1036 + queryClear(pQuery); | 949 + queryClear(pQuery); |
| 1037 + dataBufferDestroy(&new); | 950 + dataBufferDestroy(&new); |
| 1038 + return rc; | 951 + return rc; |
| 1039 + } | 952 + } |
| 1040 left = new; | 953 left = new; |
| 1041 } | 954 } |
| 1042 | 955 |
| 1043 @@ -3834,7 +4050,8 @@ | 956 @@ -3876,7 +4050,8 @@ static int fulltextFilter( |
| 1044 rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &c->result, &c->
q); | 957 rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &c->result, &c->
q); |
| 1045 if( rc!=SQLITE_OK ) return rc; | 958 if( rc!=SQLITE_OK ) return rc; |
| 1046 if( c->result.nData!=0 ){ | 959 if( c->result.nData!=0 ){ |
| 1047 - dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData); | 960 - dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData); |
| 1048 + rc = dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData); | 961 + rc = dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData); |
| 1049 + if( rc!=SQLITE_OK ) return rc; | 962 + if( rc!=SQLITE_OK ) return rc; |
| 1050 } | 963 } |
| 1051 break; | 964 break; |
| 1052 } | 965 } |
| 1053 @@ -4335,22 +4552,19 @@ | 966 @@ -4377,22 +4552,19 @@ static void interiorReaderDestroy(InteriorReader *pReade
r){ |
| 1054 SCRAMBLE(pReader); | 967 SCRAMBLE(pReader); |
| 1055 } | 968 } |
| 1056 | 969 |
| 1057 -/* TODO(shess) The assertions are great, but what if we're in NDEBUG | 970 -/* TODO(shess) The assertions are great, but what if we're in NDEBUG |
| 1058 -** and the blob is empty or otherwise contains suspect data? | 971 -** and the blob is empty or otherwise contains suspect data? |
| 1059 -*/ | 972 -*/ |
| 1060 -static void interiorReaderInit(const char *pData, int nData, | 973 -static void interiorReaderInit(const char *pData, int nData, |
| 1061 - InteriorReader *pReader){ | 974 - InteriorReader *pReader){ |
| 1062 +static int interiorReaderInit(const char *pData, int nData, | 975 +static int interiorReaderInit(const char *pData, int nData, |
| 1063 + InteriorReader *pReader){ | 976 + InteriorReader *pReader){ |
| 1064 int n, nTerm; | 977 int n, nTerm; |
| 1065 | 978 |
| 1066 - /* Require at least the leading flag byte */ | 979 - /* Require at least the leading flag byte */ |
| 1067 + /* These conditions are checked and met by the callers. */ | 980 + /* These conditions are checked and met by the callers. */ |
| 1068 assert( nData>0 ); | 981 assert( nData>0 ); |
| 1069 assert( pData[0]!='\0' ); | 982 assert( pData[0]!='\0' ); |
| 1070 | 983 |
| 1071 CLEAR(pReader); | 984 CLEAR(pReader); |
| 1072 | 985 |
| 1073 /* Decode the base blockid, and set the cursor to the first term. */ | 986 /* Decode the base blockid, and set the cursor to the first term. */ |
| 1074 - n = getVarint(pData+1, &pReader->iBlockid); | 987 - n = getVarint(pData+1, &pReader->iBlockid); |
| 1075 - assert( 1+n<=nData ); | 988 - assert( 1+n<=nData ); |
| 1076 + n = getVarintSafe(pData+1, &pReader->iBlockid, nData-1); | 989 + n = getVarintSafe(pData+1, &pReader->iBlockid, nData-1); |
| 1077 + if( !n ) return SQLITE_CORRUPT_BKPT; | 990 + if( !n ) return SQLITE_CORRUPT_BKPT; |
| 1078 pReader->pData = pData+1+n; | 991 pReader->pData = pData+1+n; |
| 1079 pReader->nData = nData-(1+n); | 992 pReader->nData = nData-(1+n); |
| 1080 | 993 |
| 1081 @@ -4361,17 +4575,18 @@ | 994 @@ -4403,17 +4575,18 @@ static void interiorReaderInit(const char *pData, int nD
ata, |
| 1082 if( pReader->nData==0 ){ | 995 if( pReader->nData==0 ){ |
| 1083 dataBufferInit(&pReader->term, 0); | 996 dataBufferInit(&pReader->term, 0); |
| 1084 }else{ | 997 }else{ |
| 1085 - n = getVarint32(pReader->pData, &nTerm); | 998 - n = getVarint32(pReader->pData, &nTerm); |
| 1086 + n = getVarint32Safe(pReader->pData, &nTerm, pReader->nData); | 999 + n = getVarint32Safe(pReader->pData, &nTerm, pReader->nData); |
| 1087 + if( !n || nTerm<0 || nTerm>pReader->nData-n) return SQLITE_CORRUPT_BKPT; | 1000 + if( !n || nTerm<0 || nTerm>pReader->nData-n) return SQLITE_CORRUPT_BKPT; |
| 1088 dataBufferInit(&pReader->term, nTerm); | 1001 dataBufferInit(&pReader->term, nTerm); |
| 1089 dataBufferReplace(&pReader->term, pReader->pData+n, nTerm); | 1002 dataBufferReplace(&pReader->term, pReader->pData+n, nTerm); |
| 1090 - assert( n+nTerm<=pReader->nData ); | 1003 - assert( n+nTerm<=pReader->nData ); |
| 1091 pReader->pData += n+nTerm; | 1004 pReader->pData += n+nTerm; |
| 1092 pReader->nData -= n+nTerm; | 1005 pReader->nData -= n+nTerm; |
| 1093 } | 1006 } |
| 1094 + return SQLITE_OK; | 1007 + return SQLITE_OK; |
| 1095 } | 1008 } |
| 1096 | 1009 |
| 1097 static int interiorReaderAtEnd(InteriorReader *pReader){ | 1010 static int interiorReaderAtEnd(InteriorReader *pReader){ |
| 1098 - return pReader->term.nData==0; | 1011 - return pReader->term.nData==0; |
| 1099 + return pReader->term.nData<=0; | 1012 + return pReader->term.nData<=0; |
| 1100 } | 1013 } |
| 1101 | 1014 |
| 1102 static sqlite_int64 interiorReaderCurrentBlockid(InteriorReader *pReader){ | 1015 static sqlite_int64 interiorReaderCurrentBlockid(InteriorReader *pReader){ |
| 1103 @@ -4388,7 +4603,7 @@ | 1016 @@ -4430,7 +4603,7 @@ static const char *interiorReaderTerm(InteriorReader *pRea
der){ |
| 1104 } | 1017 } |
| 1105 | 1018 |
| 1106 /* Step forward to the next term in the node. */ | 1019 /* Step forward to the next term in the node. */ |
| 1107 -static void interiorReaderStep(InteriorReader *pReader){ | 1020 -static void interiorReaderStep(InteriorReader *pReader){ |
| 1108 +static int interiorReaderStep(InteriorReader *pReader){ | 1021 +static int interiorReaderStep(InteriorReader *pReader){ |
| 1109 assert( !interiorReaderAtEnd(pReader) ); | 1022 assert( !interiorReaderAtEnd(pReader) ); |
| 1110 | 1023 |
| 1111 /* If the last term has been read, signal eof, else construct the | 1024 /* If the last term has been read, signal eof, else construct the |
| 1112 @@ -4399,18 +4614,26 @@ | 1025 @@ -4441,18 +4614,26 @@ static void interiorReaderStep(InteriorReader *pReader){ |
| 1113 }else{ | 1026 }else{ |
| 1114 int n, nPrefix, nSuffix; | 1027 int n, nPrefix, nSuffix; |
| 1115 | 1028 |
| 1116 - n = getVarint32(pReader->pData, &nPrefix); | 1029 - n = getVarint32(pReader->pData, &nPrefix); |
| 1117 - n += getVarint32(pReader->pData+n, &nSuffix); | 1030 - n += getVarint32(pReader->pData+n, &nSuffix); |
| 1118 + n = getVarint32Safe(pReader->pData, &nPrefix, pReader->nData); | 1031 + n = getVarint32Safe(pReader->pData, &nPrefix, pReader->nData); |
| 1119 + if( !n ) return SQLITE_CORRUPT_BKPT; | 1032 + if( !n ) return SQLITE_CORRUPT_BKPT; |
| 1120 + pReader->nData -= n; | 1033 + pReader->nData -= n; |
| 1121 + pReader->pData += n; | 1034 + pReader->pData += n; |
| 1122 + n = getVarint32Safe(pReader->pData, &nSuffix, pReader->nData); | 1035 + n = getVarint32Safe(pReader->pData, &nSuffix, pReader->nData); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1135 - pReader->pData += n+nSuffix; | 1048 - pReader->pData += n+nSuffix; |
| 1136 - pReader->nData -= n+nSuffix; | 1049 - pReader->nData -= n+nSuffix; |
| 1137 + pReader->pData += nSuffix; | 1050 + pReader->pData += nSuffix; |
| 1138 + pReader->nData -= nSuffix; | 1051 + pReader->nData -= nSuffix; |
| 1139 } | 1052 } |
| 1140 pReader->iBlockid++; | 1053 pReader->iBlockid++; |
| 1141 + return SQLITE_OK; | 1054 + return SQLITE_OK; |
| 1142 } | 1055 } |
| 1143 | 1056 |
| 1144 /* Compare the current term to pTerm[nTerm], returning strcmp-style | 1057 /* Compare the current term to pTerm[nTerm], returning strcmp-style |
| 1145 @@ -4782,7 +5005,8 @@ | 1058 @@ -4824,7 +5005,8 @@ static int leafWriterStepMerge(fulltext_vtab *v, LeafWrite
r *pWriter, |
| 1146 n = putVarint(c, nData); | 1059 n = putVarint(c, nData); |
| 1147 dataBufferAppend(&pWriter->data, c, n); | 1060 dataBufferAppend(&pWriter->data, c, n); |
| 1148 | 1061 |
| 1149 - docListMerge(&pWriter->data, pReaders, nReaders); | 1062 - docListMerge(&pWriter->data, pReaders, nReaders); |
| 1150 + rc = docListMerge(&pWriter->data, pReaders, nReaders); | 1063 + rc = docListMerge(&pWriter->data, pReaders, nReaders); |
| 1151 + if( rc!= SQLITE_OK ) return rc; | 1064 + if( rc!= SQLITE_OK ) return rc; |
| 1152 ASSERT_VALID_DOCLIST(DL_DEFAULT, | 1065 ASSERT_VALID_DOCLIST(DL_DEFAULT, |
| 1153 pWriter->data.pData+iDoclistData+n, | 1066 pWriter->data.pData+iDoclistData+n, |
| 1154 pWriter->data.nData-iDoclistData-n, NULL); | 1067 pWriter->data.nData-iDoclistData-n, NULL); |
| 1155 @@ -4892,7 +5116,8 @@ | 1068 @@ -4934,7 +5116,8 @@ static int leafWriterStep(fulltext_vtab *v, LeafWriter *pW
riter, |
| 1156 int rc; | 1069 int rc; |
| 1157 DLReader reader; | 1070 DLReader reader; |
| 1158 | 1071 |
| 1159 - dlrInit(&reader, DL_DEFAULT, pData, nData); | 1072 - dlrInit(&reader, DL_DEFAULT, pData, nData); |
| 1160 + rc = dlrInit(&reader, DL_DEFAULT, pData, nData); | 1073 + rc = dlrInit(&reader, DL_DEFAULT, pData, nData); |
| 1161 + if( rc!=SQLITE_OK ) return rc; | 1074 + if( rc!=SQLITE_OK ) return rc; |
| 1162 rc = leafWriterStepMerge(v, pWriter, pTerm, nTerm, &reader, 1); | 1075 rc = leafWriterStepMerge(v, pWriter, pTerm, nTerm, &reader, 1); |
| 1163 dlrDestroy(&reader); | 1076 dlrDestroy(&reader); |
| 1164 | 1077 |
| 1165 @@ -4937,38 +5162,40 @@ | 1078 @@ -4979,38 +5162,40 @@ static int leafReaderDataBytes(LeafReader *pReader){ |
| 1166 static const char *leafReaderData(LeafReader *pReader){ | 1079 static const char *leafReaderData(LeafReader *pReader){ |
| 1167 int n, nData; | 1080 int n, nData; |
| 1168 assert( pReader->term.nData>0 ); | 1081 assert( pReader->term.nData>0 ); |
| 1169 - n = getVarint32(pReader->pData, &nData); | 1082 - n = getVarint32(pReader->pData, &nData); |
| 1170 + n = getVarint32Safe(pReader->pData, &nData, pReader->nData); | 1083 + n = getVarint32Safe(pReader->pData, &nData, pReader->nData); |
| 1171 + if( !n || nData>pReader->nData-n ) return NULL; | 1084 + if( !n || nData>pReader->nData-n ) return NULL; |
| 1172 return pReader->pData+n; | 1085 return pReader->pData+n; |
| 1173 } | 1086 } |
| 1174 | 1087 |
| 1175 -static void leafReaderInit(const char *pData, int nData, | 1088 -static void leafReaderInit(const char *pData, int nData, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1204 assert( !leafReaderAtEnd(pReader) ); | 1117 assert( !leafReaderAtEnd(pReader) ); |
| 1205 | 1118 |
| 1206 /* Skip previous entry's data block. */ | 1119 /* Skip previous entry's data block. */ |
| 1207 - n = getVarint32(pReader->pData, &nData); | 1120 - n = getVarint32(pReader->pData, &nData); |
| 1208 - assert( n+nData<=pReader->nData ); | 1121 - assert( n+nData<=pReader->nData ); |
| 1209 + n = getVarint32Safe(pReader->pData, &nData, pReader->nData); | 1122 + n = getVarint32Safe(pReader->pData, &nData, pReader->nData); |
| 1210 + if( !n || nData<0 || nData>pReader->nData-n ) return SQLITE_CORRUPT_BKPT; | 1123 + if( !n || nData<0 || nData>pReader->nData-n ) return SQLITE_CORRUPT_BKPT; |
| 1211 pReader->pData += n+nData; | 1124 pReader->pData += n+nData; |
| 1212 pReader->nData -= n+nData; | 1125 pReader->nData -= n+nData; |
| 1213 | 1126 |
| 1214 @@ -4976,15 +5203,23 @@ | 1127 @@ -5018,15 +5203,23 @@ static void leafReaderStep(LeafReader *pReader){ |
| 1215 /* Construct the new term using a prefix from the old term plus a | 1128 /* Construct the new term using a prefix from the old term plus a |
| 1216 ** suffix from the leaf data. | 1129 ** suffix from the leaf data. |
| 1217 */ | 1130 */ |
| 1218 - n = getVarint32(pReader->pData, &nPrefix); | 1131 - n = getVarint32(pReader->pData, &nPrefix); |
| 1219 - n += getVarint32(pReader->pData+n, &nSuffix); | 1132 - n += getVarint32(pReader->pData+n, &nSuffix); |
| 1220 - assert( n+nSuffix<pReader->nData ); | 1133 - assert( n+nSuffix<pReader->nData ); |
| 1221 + n = getVarint32Safe(pReader->pData, &nPrefix, pReader->nData); | 1134 + n = getVarint32Safe(pReader->pData, &nPrefix, pReader->nData); |
| 1222 + if( !n ) return SQLITE_CORRUPT_BKPT; | 1135 + if( !n ) return SQLITE_CORRUPT_BKPT; |
| 1223 + pReader->nData -= n; | 1136 + pReader->nData -= n; |
| 1224 + pReader->pData += n; | 1137 + pReader->pData += n; |
| 1225 + n = getVarint32Safe(pReader->pData, &nSuffix, pReader->nData); | 1138 + n = getVarint32Safe(pReader->pData, &nSuffix, pReader->nData); |
| 1226 + if( !n ) return SQLITE_CORRUPT_BKPT; | 1139 + if( !n ) return SQLITE_CORRUPT_BKPT; |
| 1227 + pReader->nData -= n; | 1140 + pReader->nData -= n; |
| 1228 + pReader->pData += n; | 1141 + pReader->pData += n; |
| 1229 + if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT; | 1142 + if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT; |
| 1230 + if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT; | 1143 + if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT; |
| 1231 pReader->term.nData = nPrefix; | 1144 pReader->term.nData = nPrefix; |
| 1232 - dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); | 1145 - dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); |
| 1233 + dataBufferAppend(&pReader->term, pReader->pData, nSuffix); | 1146 + dataBufferAppend(&pReader->term, pReader->pData, nSuffix); |
| 1234 | 1147 |
| 1235 - pReader->pData += n+nSuffix; | 1148 - pReader->pData += n+nSuffix; |
| 1236 - pReader->nData -= n+nSuffix; | 1149 - pReader->nData -= n+nSuffix; |
| 1237 + pReader->pData += nSuffix; | 1150 + pReader->pData += nSuffix; |
| 1238 + pReader->nData -= nSuffix; | 1151 + pReader->nData -= nSuffix; |
| 1239 } | 1152 } |
| 1240 + return SQLITE_OK; | 1153 + return SQLITE_OK; |
| 1241 } | 1154 } |
| 1242 | 1155 |
| 1243 /* strcmp-style comparison of pReader's current term against pTerm. | 1156 /* strcmp-style comparison of pReader's current term against pTerm. |
| 1244 @@ -5077,6 +5312,9 @@ | 1157 @@ -5133,14 +5326,19 @@ static int leavesReaderInit(fulltext_vtab *v, |
| 1245 ** the leaf data was entirely contained in the root), or from the | |
| 1246 ** stream of blocks between iStartBlockid and iEndBlockid, inclusive. | |
| 1247 */ | |
| 1248 +/* TODO(shess): Figure out a means of indicating how many leaves are | |
| 1249 +** expected, for purposes of detecting corruption. | |
| 1250 +*/ | |
| 1251 static int leavesReaderInit(fulltext_vtab *v, | |
| 1252 int idx, | |
| 1253 sqlite_int64 iStartBlockid, | |
| 1254 @@ -5088,32 +5326,67 @@ | |
| 1255 | 1158 |
| 1256 dataBufferInit(&pReader->rootData, 0); | 1159 dataBufferInit(&pReader->rootData, 0); |
| 1257 if( iStartBlockid==0 ){ | 1160 if( iStartBlockid==0 ){ |
| 1258 + int rc; | 1161 + int rc; |
| 1259 + /* Corrupt if this can't be a leaf node. */ | 1162 /* Corrupt if this can't be a leaf node. */ |
| 1260 + if( pRootData==NULL || nRootData<1 || pRootData[0]!='\0' ){ | 1163 if( pRootData==NULL || nRootData<1 || pRootData[0]!='\0' ){ |
| 1261 + return SQLITE_CORRUPT_BKPT; | 1164 return SQLITE_CORRUPT_BKPT; |
| 1262 + } | 1165 } |
| 1263 /* Entire leaf level fit in root data. */ | 1166 /* Entire leaf level fit in root data. */ |
| 1264 dataBufferReplace(&pReader->rootData, pRootData, nRootData); | 1167 dataBufferReplace(&pReader->rootData, pRootData, nRootData); |
| 1265 - leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, | 1168 - leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, |
| 1266 - &pReader->leafReader); | 1169 - &pReader->leafReader); |
| 1267 + rc = leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, | 1170 + rc = leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, |
| 1268 + &pReader->leafReader); | 1171 + &pReader->leafReader); |
| 1269 + if( rc!=SQLITE_OK ){ | 1172 + if( rc!=SQLITE_OK ){ |
| 1270 + dataBufferDestroy(&pReader->rootData); | 1173 + dataBufferDestroy(&pReader->rootData); |
| 1271 + return rc; | 1174 + return rc; |
| 1272 + } | 1175 + } |
| 1273 }else{ | 1176 }else{ |
| 1274 sqlite3_stmt *s; | 1177 sqlite3_stmt *s; |
| 1275 int rc = sql_get_leaf_statement(v, idx, &s); | 1178 int rc = sql_get_leaf_statement(v, idx, &s); |
| 1276 if( rc!=SQLITE_OK ) return rc; | 1179 @@ -5174,7 +5372,7 @@ static int leavesReaderInit(fulltext_vtab *v, |
| 1180 if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ |
| 1181 rc = SQLITE_CORRUPT_BKPT; |
| 1182 }else{ |
| 1183 - leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); |
| 1184 + rc = leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); |
| 1185 } |
| 1186 } |
| 1277 | 1187 |
| 1278 rc = sqlite3_bind_int64(s, 1, iStartBlockid); | 1188 @@ -5197,11 +5395,12 @@ static int leavesReaderInit(fulltext_vtab *v, |
| 1279 - if( rc!=SQLITE_OK ) return rc; | |
| 1280 + if( rc!=SQLITE_OK ) goto err; | |
| 1281 | |
| 1282 rc = sqlite3_bind_int64(s, 2, iEndBlockid); | |
| 1283 - if( rc!=SQLITE_OK ) return rc; | |
| 1284 + if( rc!=SQLITE_OK ) goto err; | |
| 1285 | |
| 1286 rc = sqlite3_step(s); | |
| 1287 + | |
| 1288 + /* Corrupt if interior node referenced missing leaf node. */ | |
| 1289 if( rc==SQLITE_DONE ){ | |
| 1290 - pReader->eof = 1; | |
| 1291 - return SQLITE_OK; | |
| 1292 + rc = SQLITE_CORRUPT_BKPT; | |
| 1293 + goto err; | |
| 1294 + } | |
| 1295 + | |
| 1296 + if( rc!=SQLITE_ROW ) goto err; | |
| 1297 + rc = SQLITE_OK; | |
| 1298 + | |
| 1299 + /* Corrupt if leaf data isn't a blob. */ | |
| 1300 + if( sqlite3_column_type(s, 0)!=SQLITE_BLOB ){ | |
| 1301 + rc = SQLITE_CORRUPT_BKPT; | |
| 1302 + }else{ | |
| 1303 + const char *pLeafData = sqlite3_column_blob(s, 0); | |
| 1304 + int nLeafData = sqlite3_column_bytes(s, 0); | |
| 1305 + | |
| 1306 + /* Corrupt if this can't be a leaf node. */ | |
| 1307 + if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ | |
| 1308 + rc = SQLITE_CORRUPT_BKPT; | |
| 1309 + }else{ | |
| 1310 + rc = leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); | |
| 1311 + } | |
| 1312 + } | |
| 1313 + | |
| 1314 + err: | |
| 1315 + if( rc!=SQLITE_OK ){ | |
| 1316 + if( idx==-1 ){ | |
| 1317 + sqlite3_finalize(s); | |
| 1318 + }else{ | |
| 1319 + sqlite3_reset(s); | |
| 1320 + } | |
| 1321 + return rc; | |
| 1322 } | |
| 1323 - if( rc!=SQLITE_ROW ) return rc; | |
| 1324 | |
| 1325 pReader->pStmt = s; | |
| 1326 - leafReaderInit(sqlite3_column_blob(pReader->pStmt, 0), | |
| 1327 - sqlite3_column_bytes(pReader->pStmt, 0), | |
| 1328 - &pReader->leafReader); | |
| 1329 } | |
| 1330 return SQLITE_OK; | |
| 1331 } | |
| 1332 @@ -5122,11 +5395,12 @@ | |
| 1333 ** end of the current leaf, step forward to the next leaf block. | 1189 ** end of the current leaf, step forward to the next leaf block. |
| 1334 */ | 1190 */ |
| 1335 static int leavesReaderStep(fulltext_vtab *v, LeavesReader *pReader){ | 1191 static int leavesReaderStep(fulltext_vtab *v, LeavesReader *pReader){ |
| 1336 + int rc; | 1192 + int rc; |
| 1337 assert( !leavesReaderAtEnd(pReader) ); | 1193 assert( !leavesReaderAtEnd(pReader) ); |
| 1338 - leafReaderStep(&pReader->leafReader); | 1194 - leafReaderStep(&pReader->leafReader); |
| 1339 + rc = leafReaderStep(&pReader->leafReader); | 1195 + rc = leafReaderStep(&pReader->leafReader); |
| 1340 + if( rc!=SQLITE_OK ) return rc; | 1196 + if( rc!=SQLITE_OK ) return rc; |
| 1341 | 1197 |
| 1342 if( leafReaderAtEnd(&pReader->leafReader) ){ | 1198 if( leafReaderAtEnd(&pReader->leafReader) ){ |
| 1343 - int rc; | 1199 - int rc; |
| 1344 if( pReader->rootData.pData ){ | 1200 if( pReader->rootData.pData ){ |
| 1345 pReader->eof = 1; | 1201 pReader->eof = 1; |
| 1346 return SQLITE_OK; | 1202 return SQLITE_OK; |
| 1347 @@ -5136,10 +5410,25 @@ | 1203 @@ -5216,6 +5415,7 @@ static int leavesReaderStep(fulltext_vtab *v, LeavesReader
*pReader){ |
| 1348 pReader->eof = 1; | 1204 if( sqlite3_column_type(pReader->pStmt, 0)!=SQLITE_BLOB ){ |
| 1349 return rc==SQLITE_DONE ? SQLITE_OK : rc; | 1205 return SQLITE_CORRUPT_BKPT; |
| 1350 } | 1206 }else{ |
| 1351 - leafReaderDestroy(&pReader->leafReader); | |
| 1352 - leafReaderInit(sqlite3_column_blob(pReader->pStmt, 0), | |
| 1353 - sqlite3_column_bytes(pReader->pStmt, 0), | |
| 1354 - &pReader->leafReader); | |
| 1355 + | |
| 1356 + /* Corrupt if leaf data isn't a blob. */ | |
| 1357 + if( sqlite3_column_type(pReader->pStmt, 0)!=SQLITE_BLOB ){ | |
| 1358 + return SQLITE_CORRUPT_BKPT; | |
| 1359 + }else{ | |
| 1360 + LeafReader tmp; | 1207 + LeafReader tmp; |
| 1361 + const char *pLeafData = sqlite3_column_blob(pReader->pStmt, 0); | 1208 const char *pLeafData = sqlite3_column_blob(pReader->pStmt, 0); |
| 1362 + int nLeafData = sqlite3_column_bytes(pReader->pStmt, 0); | 1209 int nLeafData = sqlite3_column_bytes(pReader->pStmt, 0); |
| 1363 + | 1210 |
| 1364 + /* Corrupt if this can't be a leaf node. */ | 1211 @@ -5224,8 +5424,10 @@ static int leavesReaderStep(fulltext_vtab *v, LeavesReade
r *pReader){ |
| 1365 + if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ | 1212 return SQLITE_CORRUPT_BKPT; |
| 1366 + return SQLITE_CORRUPT_BKPT; | 1213 } |
| 1367 + } | 1214 |
| 1368 + | |
| 1369 + rc = leafReaderInit(pLeafData, nLeafData, &tmp); | 1215 + rc = leafReaderInit(pLeafData, nLeafData, &tmp); |
| 1370 + if( rc!=SQLITE_OK ) return rc; | 1216 + if( rc!=SQLITE_OK ) return rc; |
| 1371 + leafReaderDestroy(&pReader->leafReader); | 1217 leafReaderDestroy(&pReader->leafReader); |
| 1218 - leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); |
| 1372 + pReader->leafReader = tmp; | 1219 + pReader->leafReader = tmp; |
| 1373 + } | 1220 } |
| 1374 } | 1221 } |
| 1375 return SQLITE_OK; | 1222 return SQLITE_OK; |
| 1376 } | 1223 @@ -5334,13 +5536,26 @@ static int leavesReadersMerge(fulltext_vtab *v, |
| 1377 @@ -5200,8 +5489,19 @@ | |
| 1378 sqlite_int64 iEnd = sqlite3_column_int64(s, 1); | |
| 1379 const char *pRootData = sqlite3_column_blob(s, 2); | |
| 1380 int nRootData = sqlite3_column_bytes(s, 2); | |
| 1381 + sqlite_int64 iIndex = sqlite3_column_int64(s, 3); | |
| 1382 + | |
| 1383 + /* Corrupt if we get back different types than we stored. */ | |
| 1384 + /* Also corrupt if the index is not sequential starting at 0. */ | |
| 1385 + if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER || | |
| 1386 + sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
| 1387 + sqlite3_column_type(s, 2)!=SQLITE_BLOB || | |
| 1388 + i!=iIndex || | |
| 1389 + i>=MERGE_COUNT ){ | |
| 1390 + rc = SQLITE_CORRUPT_BKPT; | |
| 1391 + break; | |
| 1392 + } | |
| 1393 | |
| 1394 - assert( i<MERGE_COUNT ); | |
| 1395 rc = leavesReaderInit(v, i, iStart, iEnd, pRootData, nRootData, | |
| 1396 &pReaders[i]); | |
| 1397 if( rc!=SQLITE_OK ) break; | |
| 1398 @@ -5212,6 +5512,7 @@ | |
| 1399 while( i-->0 ){ | |
| 1400 leavesReaderDestroy(&pReaders[i]); | |
| 1401 } | |
| 1402 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
| 1403 return rc; | |
| 1404 } | |
| 1405 | |
| 1406 @@ -5235,13 +5536,26 @@ | |
| 1407 DLReader dlReaders[MERGE_COUNT]; | 1224 DLReader dlReaders[MERGE_COUNT]; |
| 1408 const char *pTerm = leavesReaderTerm(pReaders); | 1225 const char *pTerm = leavesReaderTerm(pReaders); |
| 1409 int i, nTerm = leavesReaderTermBytes(pReaders); | 1226 int i, nTerm = leavesReaderTermBytes(pReaders); |
| 1410 + int rc; | 1227 + int rc; |
| 1411 | 1228 |
| 1412 assert( nReaders<=MERGE_COUNT ); | 1229 assert( nReaders<=MERGE_COUNT ); |
| 1413 | 1230 |
| 1414 for(i=0; i<nReaders; i++){ | 1231 for(i=0; i<nReaders; i++){ |
| 1415 - dlrInit(&dlReaders[i], DL_DEFAULT, | 1232 - dlrInit(&dlReaders[i], DL_DEFAULT, |
| 1416 - leavesReaderData(pReaders+i), | 1233 - leavesReaderData(pReaders+i), |
| 1417 - leavesReaderDataBytes(pReaders+i)); | 1234 - leavesReaderDataBytes(pReaders+i)); |
| 1418 + const char *pData = leavesReaderData(pReaders+i); | 1235 + const char *pData = leavesReaderData(pReaders+i); |
| 1419 + if( pData==NULL ){ | 1236 + if( pData==NULL ){ |
| 1420 + rc = SQLITE_CORRUPT_BKPT; | 1237 + rc = SQLITE_CORRUPT_BKPT; |
| 1421 + break; | 1238 + break; |
| 1422 + } | 1239 + } |
| 1423 + rc = dlrInit(&dlReaders[i], DL_DEFAULT, | 1240 + rc = dlrInit(&dlReaders[i], DL_DEFAULT, |
| 1424 + pData, | 1241 + pData, |
| 1425 + leavesReaderDataBytes(pReaders+i)); | 1242 + leavesReaderDataBytes(pReaders+i)); |
| 1426 + if( rc!=SQLITE_OK ) break; | 1243 + if( rc!=SQLITE_OK ) break; |
| 1427 + } | 1244 + } |
| 1428 + if( rc!=SQLITE_OK ){ | 1245 + if( rc!=SQLITE_OK ){ |
| 1429 + while( i-->0 ){ | 1246 + while( i-->0 ){ |
| 1430 + dlrDestroy(&dlReaders[i]); | 1247 + dlrDestroy(&dlReaders[i]); |
| 1431 + } | 1248 + } |
| 1432 + return rc; | 1249 + return rc; |
| 1433 } | 1250 } |
| 1434 | 1251 |
| 1435 return leafWriterStepMerge(v, pWriter, pTerm, nTerm, dlReaders, nReaders); | 1252 return leafWriterStepMerge(v, pWriter, pTerm, nTerm, dlReaders, nReaders); |
| 1436 @@ -5295,10 +5609,14 @@ | 1253 @@ -5444,12 +5659,14 @@ static int segmentMerge(fulltext_vtab *v, int iLevel){ |
| 1437 memset(&lrs, '\0', sizeof(lrs)); | |
| 1438 rc = leavesReadersInit(v, iLevel, lrs, &i); | |
| 1439 if( rc!=SQLITE_OK ) return rc; | |
| 1440 - assert( i==MERGE_COUNT ); | |
| 1441 | |
| 1442 leafWriterInit(iLevel+1, idx, &writer); | |
| 1443 | |
| 1444 + if( i!=MERGE_COUNT ){ | |
| 1445 + rc = SQLITE_CORRUPT_BKPT; | |
| 1446 + goto err; | |
| 1447 + } | |
| 1448 + | |
| 1449 /* Since leavesReaderReorder() pushes readers at eof to the end, | |
| 1450 ** when the first reader is empty, all will be empty. | |
| 1451 */ | |
| 1452 @@ -5341,12 +5659,14 @@ | |
| 1453 } | 1254 } |
| 1454 | 1255 |
| 1455 /* Accumulate the union of *acc and *pData into *acc. */ | 1256 /* Accumulate the union of *acc and *pData into *acc. */ |
| 1456 -static void docListAccumulateUnion(DataBuffer *acc, | 1257 -static void docListAccumulateUnion(DataBuffer *acc, |
| 1457 - const char *pData, int nData) { | 1258 - const char *pData, int nData) { |
| 1458 +static int docListAccumulateUnion(DataBuffer *acc, | 1259 +static int docListAccumulateUnion(DataBuffer *acc, |
| 1459 + const char *pData, int nData) { | 1260 + const char *pData, int nData) { |
| 1460 DataBuffer tmp = *acc; | 1261 DataBuffer tmp = *acc; |
| 1461 + int rc; | 1262 + int rc; |
| 1462 dataBufferInit(acc, tmp.nData+nData); | 1263 dataBufferInit(acc, tmp.nData+nData); |
| 1463 - docListUnion(tmp.pData, tmp.nData, pData, nData, acc); | 1264 - docListUnion(tmp.pData, tmp.nData, pData, nData, acc); |
| 1464 + rc = docListUnion(tmp.pData, tmp.nData, pData, nData, acc); | 1265 + rc = docListUnion(tmp.pData, tmp.nData, pData, nData, acc); |
| 1465 dataBufferDestroy(&tmp); | 1266 dataBufferDestroy(&tmp); |
| 1466 + return rc; | 1267 + return rc; |
| 1467 } | 1268 } |
| 1468 | 1269 |
| 1469 /* TODO(shess) It might be interesting to explore different merge | 1270 /* TODO(shess) It might be interesting to explore different merge |
| 1470 @@ -5388,8 +5708,13 @@ | 1271 @@ -5491,8 +5708,13 @@ static int loadSegmentLeavesInt(fulltext_vtab *v, LeavesR
eader *pReader, |
| 1471 int c = leafReaderTermCmp(&pReader->leafReader, pTerm, nTerm, isPrefix); | 1272 int c = leafReaderTermCmp(&pReader->leafReader, pTerm, nTerm, isPrefix); |
| 1472 if( c>0 ) break; /* Past any possible matches. */ | 1273 if( c>0 ) break; /* Past any possible matches. */ |
| 1473 if( c==0 ){ | 1274 if( c==0 ){ |
| 1474 + int iBuffer, nData; | 1275 + int iBuffer, nData; |
| 1475 const char *pData = leavesReaderData(pReader); | 1276 const char *pData = leavesReaderData(pReader); |
| 1476 - int iBuffer, nData = leavesReaderDataBytes(pReader); | 1277 - int iBuffer, nData = leavesReaderDataBytes(pReader); |
| 1477 + if( pData==NULL ){ | 1278 + if( pData==NULL ){ |
| 1478 + rc = SQLITE_CORRUPT_BKPT; | 1279 + rc = SQLITE_CORRUPT_BKPT; |
| 1479 + break; | 1280 + break; |
| 1480 + } | 1281 + } |
| 1481 + nData = leavesReaderDataBytes(pReader); | 1282 + nData = leavesReaderDataBytes(pReader); |
| 1482 | 1283 |
| 1483 /* Find the first empty buffer. */ | 1284 /* Find the first empty buffer. */ |
| 1484 for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){ | 1285 for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){ |
| 1485 @@ -5435,11 +5760,13 @@ | 1286 @@ -5538,11 +5760,13 @@ static int loadSegmentLeavesInt(fulltext_vtab *v, Leaves
Reader *pReader, |
| 1486 ** with pData/nData. | 1287 ** with pData/nData. |
| 1487 */ | 1288 */ |
| 1488 dataBufferSwap(p, pAcc); | 1289 dataBufferSwap(p, pAcc); |
| 1489 - docListAccumulateUnion(pAcc, pData, nData); | 1290 - docListAccumulateUnion(pAcc, pData, nData); |
| 1490 + rc = docListAccumulateUnion(pAcc, pData, nData); | 1291 + rc = docListAccumulateUnion(pAcc, pData, nData); |
| 1491 + if( rc!=SQLITE_OK ) goto err; | 1292 + if( rc!=SQLITE_OK ) goto err; |
| 1492 | 1293 |
| 1493 /* Accumulate remaining doclists into pAcc. */ | 1294 /* Accumulate remaining doclists into pAcc. */ |
| 1494 for(++p; p<pAcc; ++p){ | 1295 for(++p; p<pAcc; ++p){ |
| 1495 - docListAccumulateUnion(pAcc, p->pData, p->nData); | 1296 - docListAccumulateUnion(pAcc, p->pData, p->nData); |
| 1496 + rc = docListAccumulateUnion(pAcc, p->pData, p->nData); | 1297 + rc = docListAccumulateUnion(pAcc, p->pData, p->nData); |
| 1497 + if( rc!=SQLITE_OK ) goto err; | 1298 + if( rc!=SQLITE_OK ) goto err; |
| 1498 | 1299 |
| 1499 /* dataBufferReset() could allow a large doclist to blow up | 1300 /* dataBufferReset() could allow a large doclist to blow up |
| 1500 ** our memory requirements. | 1301 ** our memory requirements. |
| 1501 @@ -5464,13 +5791,15 @@ | 1302 @@ -5567,13 +5791,15 @@ static int loadSegmentLeavesInt(fulltext_vtab *v, Leaves
Reader *pReader, |
| 1502 if( out->nData==0 ){ | 1303 if( out->nData==0 ){ |
| 1503 dataBufferSwap(out, &(pBuffers[iBuffer])); | 1304 dataBufferSwap(out, &(pBuffers[iBuffer])); |
| 1504 }else{ | 1305 }else{ |
| 1505 - docListAccumulateUnion(out, pBuffers[iBuffer].pData, | 1306 - docListAccumulateUnion(out, pBuffers[iBuffer].pData, |
| 1506 - pBuffers[iBuffer].nData); | 1307 - pBuffers[iBuffer].nData); |
| 1507 + rc = docListAccumulateUnion(out, pBuffers[iBuffer].pData, | 1308 + rc = docListAccumulateUnion(out, pBuffers[iBuffer].pData, |
| 1508 + pBuffers[iBuffer].nData); | 1309 + pBuffers[iBuffer].nData); |
| 1509 + if( rc!=SQLITE_OK ) break; | 1310 + if( rc!=SQLITE_OK ) break; |
| 1510 } | 1311 } |
| 1511 } | 1312 } |
| 1512 } | 1313 } |
| 1513 } | 1314 } |
| 1514 | 1315 |
| 1515 +err: | 1316 +err: |
| 1516 while( nBuffers-- ){ | 1317 while( nBuffers-- ){ |
| 1517 dataBufferDestroy(&(pBuffers[nBuffers])); | 1318 dataBufferDestroy(&(pBuffers[nBuffers])); |
| 1518 } | 1319 } |
| 1519 @@ -5529,20 +5858,26 @@ | 1320 @@ -5632,20 +5858,26 @@ static int loadSegmentLeaves(fulltext_vtab *v, |
| 1520 ** node. Consider whether breaking symmetry is worthwhile. I suspect | 1321 ** node. Consider whether breaking symmetry is worthwhile. I suspect |
| 1521 ** it is not worthwhile. | 1322 ** it is not worthwhile. |
| 1522 */ | 1323 */ |
| 1523 -static void getChildrenContaining(const char *pData, int nData, | 1324 -static void getChildrenContaining(const char *pData, int nData, |
| 1524 - const char *pTerm, int nTerm, int isPrefix, | 1325 - const char *pTerm, int nTerm, int isPrefix, |
| 1525 - sqlite_int64 *piStartChild, | 1326 - sqlite_int64 *piStartChild, |
| 1526 - sqlite_int64 *piEndChild){ | 1327 - sqlite_int64 *piEndChild){ |
| 1527 +static int getChildrenContaining(const char *pData, int nData, | 1328 +static int getChildrenContaining(const char *pData, int nData, |
| 1528 + const char *pTerm, int nTerm, int isPrefix, | 1329 + const char *pTerm, int nTerm, int isPrefix, |
| 1529 + sqlite_int64 *piStartChild, | 1330 + sqlite_int64 *piStartChild, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1542 if( interiorReaderTermCmp(&reader, pTerm, nTerm, 0)>0 ) break; | 1343 if( interiorReaderTermCmp(&reader, pTerm, nTerm, 0)>0 ) break; |
| 1543 - interiorReaderStep(&reader); | 1344 - interiorReaderStep(&reader); |
| 1544 + rc = interiorReaderStep(&reader); | 1345 + rc = interiorReaderStep(&reader); |
| 1545 + if( rc!=SQLITE_OK ){ | 1346 + if( rc!=SQLITE_OK ){ |
| 1546 + interiorReaderDestroy(&reader); | 1347 + interiorReaderDestroy(&reader); |
| 1547 + return rc; | 1348 + return rc; |
| 1548 + } | 1349 + } |
| 1549 } | 1350 } |
| 1550 *piStartChild = interiorReaderCurrentBlockid(&reader); | 1351 *piStartChild = interiorReaderCurrentBlockid(&reader); |
| 1551 | 1352 |
| 1552 @@ -5552,7 +5887,11 @@ | 1353 @@ -5655,7 +5887,11 @@ static void getChildrenContaining(const char *pData, int
nData, |
| 1553 */ | 1354 */ |
| 1554 while( !interiorReaderAtEnd(&reader) ){ | 1355 while( !interiorReaderAtEnd(&reader) ){ |
| 1555 if( interiorReaderTermCmp(&reader, pTerm, nTerm, isPrefix)>0 ) break; | 1356 if( interiorReaderTermCmp(&reader, pTerm, nTerm, isPrefix)>0 ) break; |
| 1556 - interiorReaderStep(&reader); | 1357 - interiorReaderStep(&reader); |
| 1557 + rc = interiorReaderStep(&reader); | 1358 + rc = interiorReaderStep(&reader); |
| 1558 + if( rc!=SQLITE_OK ){ | 1359 + if( rc!=SQLITE_OK ){ |
| 1559 + interiorReaderDestroy(&reader); | 1360 + interiorReaderDestroy(&reader); |
| 1560 + return rc; | 1361 + return rc; |
| 1561 + } | 1362 + } |
| 1562 } | 1363 } |
| 1563 *piEndChild = interiorReaderCurrentBlockid(&reader); | 1364 *piEndChild = interiorReaderCurrentBlockid(&reader); |
| 1564 | 1365 |
| 1565 @@ -5561,6 +5900,7 @@ | 1366 @@ -5664,6 +5900,7 @@ static void getChildrenContaining(const char *pData, int n
Data, |
| 1566 /* Children must ascend, and if !prefix, both must be the same. */ | 1367 /* Children must ascend, and if !prefix, both must be the same. */ |
| 1567 assert( *piEndChild>=*piStartChild ); | 1368 assert( *piEndChild>=*piStartChild ); |
| 1568 assert( isPrefix || *piStartChild==*piEndChild ); | 1369 assert( isPrefix || *piStartChild==*piEndChild ); |
| 1569 + return rc; | 1370 + return rc; |
| 1570 } | 1371 } |
| 1571 | 1372 |
| 1572 /* Read block at iBlockid and pass it with other params to | 1373 /* Read block at iBlockid and pass it with other params to |
| 1573 @@ -5588,11 +5928,31 @@ | 1374 @@ -5709,8 +5946,12 @@ static int loadAndGetChildrenContaining( |
| 1574 if( rc!=SQLITE_OK ) return rc; | 1375 return SQLITE_CORRUPT_BKPT; |
| 1376 } |
| 1575 | 1377 |
| 1576 rc = sqlite3_step(s); | 1378 - getChildrenContaining(pData, nData, pTerm, nTerm, |
| 1577 - if( rc==SQLITE_DONE ) return SQLITE_ERROR; | 1379 - isPrefix, piStartChild, piEndChild); |
| 1578 + /* Corrupt if interior node references missing child node. */ | |
| 1579 + if( rc==SQLITE_DONE ) return SQLITE_CORRUPT_BKPT; | |
| 1580 if( rc!=SQLITE_ROW ) return rc; | |
| 1581 | |
| 1582 - getChildrenContaining(sqlite3_column_blob(s, 0), sqlite3_column_bytes(s, 0), | |
| 1583 - pTerm, nTerm, isPrefix, piStartChild, piEndChild); | |
| 1584 + /* Corrupt if child node isn't a blob. */ | |
| 1585 + if( sqlite3_column_type(s, 0)!=SQLITE_BLOB ){ | |
| 1586 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
| 1587 + return SQLITE_CORRUPT_BKPT; | |
| 1588 + }else{ | |
| 1589 + const char *pData = sqlite3_column_blob(s, 0); | |
| 1590 + int nData = sqlite3_column_bytes(s, 0); | |
| 1591 + | |
| 1592 + /* Corrupt if child is not a valid interior node. */ | |
| 1593 + if( pData==NULL || nData<1 || pData[0]=='\0' ){ | |
| 1594 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
| 1595 + return SQLITE_CORRUPT_BKPT; | |
| 1596 + } | |
| 1597 + | |
| 1598 + rc = getChildrenContaining(pData, nData, pTerm, nTerm, | 1380 + rc = getChildrenContaining(pData, nData, pTerm, nTerm, |
| 1599 + isPrefix, piStartChild, piEndChild); | 1381 + isPrefix, piStartChild, piEndChild); |
| 1600 + if( rc!=SQLITE_OK ){ | 1382 + if( rc!=SQLITE_OK ){ |
| 1601 + sqlite3_reset(s); | 1383 + sqlite3_reset(s); |
| 1602 + return rc; | 1384 + return rc; |
| 1603 + } | 1385 + } |
| 1604 + } | 1386 } |
| 1605 | 1387 |
| 1606 /* We expect only one row. We must execute another sqlite3_step() | 1388 /* We expect only one row. We must execute another sqlite3_step() |
| 1607 * to complete the iteration; otherwise the table will remain | 1389 @@ -5741,8 +5982,9 @@ static int loadSegmentInt(fulltext_vtab *v, const char *pD
ata, int nData, |
| 1608 @@ -5622,8 +5982,9 @@ | |
| 1609 /* Process pData as an interior node, then loop down the tree | 1390 /* Process pData as an interior node, then loop down the tree |
| 1610 ** until we find the set of leaf nodes to scan for the term. | 1391 ** until we find the set of leaf nodes to scan for the term. |
| 1611 */ | 1392 */ |
| 1612 - getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, | 1393 - getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, |
| 1613 - &iStartChild, &iEndChild); | 1394 - &iStartChild, &iEndChild); |
| 1614 + rc = getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, | 1395 + rc = getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, |
| 1615 + &iStartChild, &iEndChild); | 1396 + &iStartChild, &iEndChild); |
| 1616 + if( rc!=SQLITE_OK ) return rc; | 1397 + if( rc!=SQLITE_OK ) return rc; |
| 1617 while( iStartChild>iLeavesEnd ){ | 1398 while( iStartChild>iLeavesEnd ){ |
| 1618 sqlite_int64 iNextStart, iNextEnd; | 1399 sqlite_int64 iNextStart, iNextEnd; |
| 1619 rc = loadAndGetChildrenContaining(v, iStartChild, pTerm, nTerm, isPrefix, | 1400 rc = loadAndGetChildrenContaining(v, iStartChild, pTerm, nTerm, isPrefix, |
| 1620 @@ -5675,7 +6036,8 @@ | 1401 @@ -5812,16 +6054,21 @@ static int loadSegment(fulltext_vtab *v, const char *pDa
ta, int nData, |
| 1621 DataBuffer result; | |
| 1622 int rc; | |
| 1623 | |
| 1624 - assert( nData>1 ); | |
| 1625 + /* Corrupt if segment root can't be valid. */ | |
| 1626 + if( pData==NULL || nData<1 ) return SQLITE_CORRUPT_BKPT; | |
| 1627 | |
| 1628 /* This code should never be called with buffered updates. */ | |
| 1629 assert( v->nPendingData<0 ); | |
| 1630 @@ -5692,16 +6054,21 @@ | |
| 1631 DataBuffer merged; | 1402 DataBuffer merged; |
| 1632 DLReader readers[2]; | 1403 DLReader readers[2]; |
| 1633 | 1404 |
| 1634 - dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); | 1405 - dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); |
| 1635 - dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); | 1406 - dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); |
| 1636 - dataBufferInit(&merged, out->nData+result.nData); | 1407 - dataBufferInit(&merged, out->nData+result.nData); |
| 1637 - docListMerge(&merged, readers, 2); | 1408 - docListMerge(&merged, readers, 2); |
| 1638 - dataBufferDestroy(out); | 1409 - dataBufferDestroy(out); |
| 1639 - *out = merged; | 1410 - *out = merged; |
| 1640 - dlrDestroy(&readers[0]); | 1411 - dlrDestroy(&readers[0]); |
| 1641 - dlrDestroy(&readers[1]); | 1412 - dlrDestroy(&readers[1]); |
| 1642 + rc = dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); | 1413 + rc = dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); |
| 1643 + if( rc==SQLITE_OK ){ | 1414 + if( rc==SQLITE_OK ){ |
| 1644 + rc = dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); | 1415 + rc = dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); |
| 1645 + if( rc==SQLITE_OK ){ | 1416 + if( rc==SQLITE_OK ){ |
| 1646 + dataBufferInit(&merged, out->nData+result.nData); | 1417 + dataBufferInit(&merged, out->nData+result.nData); |
| 1647 + rc = docListMerge(&merged, readers, 2); | 1418 + rc = docListMerge(&merged, readers, 2); |
| 1648 + dataBufferDestroy(out); | 1419 + dataBufferDestroy(out); |
| 1649 + *out = merged; | 1420 + *out = merged; |
| 1650 + dlrDestroy(&readers[1]); | 1421 + dlrDestroy(&readers[1]); |
| 1651 + } | 1422 + } |
| 1652 + dlrDestroy(&readers[0]); | 1423 + dlrDestroy(&readers[0]); |
| 1653 + } | 1424 + } |
| 1654 } | 1425 } |
| 1655 } | 1426 } |
| 1656 + | 1427 + |
| 1657 dataBufferDestroy(&result); | 1428 dataBufferDestroy(&result); |
| 1658 return rc; | 1429 return rc; |
| 1659 } | 1430 } |
| 1660 @@ -5729,11 +6096,20 @@ | 1431 @@ -5862,6 +6109,7 @@ static int termSelect(fulltext_vtab *v, int iColumn, |
| 1661 const char *pData = sqlite3_column_blob(s, 2); | |
| 1662 const int nData = sqlite3_column_bytes(s, 2); | |
| 1663 const sqlite_int64 iLeavesEnd = sqlite3_column_int64(s, 1); | |
| 1664 + | |
| 1665 + /* Corrupt if we get back different types than we stored. */ | |
| 1666 + if( sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
| 1667 + sqlite3_column_type(s, 2)!=SQLITE_BLOB ){ | |
| 1668 + rc = SQLITE_CORRUPT_BKPT; | |
| 1669 + goto err; | |
| 1670 + } | |
| 1671 + | |
| 1672 rc = loadSegment(v, pData, nData, iLeavesEnd, pTerm, nTerm, isPrefix, | |
| 1673 &doclist); | |
| 1674 if( rc!=SQLITE_OK ) goto err; | 1432 if( rc!=SQLITE_OK ) goto err; |
| 1675 } | 1433 } |
| 1676 if( rc==SQLITE_DONE ){ | 1434 if( rc==SQLITE_DONE ){ |
| 1677 + rc = SQLITE_OK; | 1435 + rc = SQLITE_OK; |
| 1678 if( doclist.nData!=0 ){ | 1436 if( doclist.nData!=0 ){ |
| 1679 /* TODO(shess) The old term_select_all() code applied the column | 1437 /* TODO(shess) The old term_select_all() code applied the column |
| 1680 ** restrict as we merged segments, leading to smaller buffers. | 1438 ** restrict as we merged segments, leading to smaller buffers. |
| 1681 @@ -5741,13 +6117,13 @@ | 1439 @@ -5869,10 +6117,9 @@ static int termSelect(fulltext_vtab *v, int iColumn, |
| 1682 ** system is checked in. | 1440 ** system is checked in. |
| 1683 */ | 1441 */ |
| 1684 if( iColumn==v->nColumn) iColumn = -1; | 1442 if( iColumn==v->nColumn) iColumn = -1; |
| 1685 - docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | 1443 - docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, |
| 1686 - iColumn, iType, out); | 1444 - iColumn, iType, out); |
| 1687 + rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | 1445 + rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, |
| 1688 + iColumn, iType, out); | 1446 + iColumn, iType, out); |
| 1689 } | 1447 } |
| 1690 - rc = SQLITE_OK; | 1448 - rc = SQLITE_OK; |
| 1691 } | 1449 } |
| 1692 | 1450 |
| 1693 err: | 1451 err: |
| 1694 + sqlite3_reset(s); /* So we don't leave a lock. */ | 1452 @@ -6218,6 +6465,7 @@ static int optimizeInternal(fulltext_vtab *v, |
| 1695 dataBufferDestroy(&doclist); | |
| 1696 return rc; | |
| 1697 } | |
| 1698 @@ -6089,6 +6465,7 @@ | |
| 1699 LeafWriter *pWriter){ | 1453 LeafWriter *pWriter){ |
| 1700 int i, rc = SQLITE_OK; | 1454 int i, rc = SQLITE_OK; |
| 1701 DataBuffer doclist, merged, tmp; | 1455 DataBuffer doclist, merged, tmp; |
| 1702 + const char *pData; | 1456 + const char *pData; |
| 1703 | 1457 |
| 1704 /* Order the readers. */ | 1458 /* Order the readers. */ |
| 1705 i = nReaders; | 1459 i = nReaders; |
| 1706 @@ -6109,14 +6486,21 @@ | 1460 @@ -6238,14 +6486,21 @@ static int optimizeInternal(fulltext_vtab *v, |
| 1707 if( 0!=optLeavesReaderTermCmp(&readers[0], &readers[i]) ) break; | 1461 if( 0!=optLeavesReaderTermCmp(&readers[0], &readers[i]) ) break; |
| 1708 } | 1462 } |
| 1709 | 1463 |
| 1710 + pData = optLeavesReaderData(&readers[0]); | 1464 + pData = optLeavesReaderData(&readers[0]); |
| 1711 + if( pData==NULL ){ | 1465 + if( pData==NULL ){ |
| 1712 + rc = SQLITE_CORRUPT_BKPT; | 1466 + rc = SQLITE_CORRUPT_BKPT; |
| 1713 + break; | 1467 + break; |
| 1714 + } | 1468 + } |
| 1715 + | 1469 + |
| 1716 /* Special-case for no merge. */ | 1470 /* Special-case for no merge. */ |
| 1717 if( i==1 ){ | 1471 if( i==1 ){ |
| 1718 /* Trim deletions from the doclist. */ | 1472 /* Trim deletions from the doclist. */ |
| 1719 dataBufferReset(&merged); | 1473 dataBufferReset(&merged); |
| 1720 - docListTrim(DL_DEFAULT, | 1474 - docListTrim(DL_DEFAULT, |
| 1721 - optLeavesReaderData(&readers[0]), | 1475 - optLeavesReaderData(&readers[0]), |
| 1722 - optLeavesReaderDataBytes(&readers[0]), | 1476 - optLeavesReaderDataBytes(&readers[0]), |
| 1723 - -1, DL_DEFAULT, &merged); | 1477 - -1, DL_DEFAULT, &merged); |
| 1724 + rc = docListTrim(DL_DEFAULT, | 1478 + rc = docListTrim(DL_DEFAULT, |
| 1725 + pData, | 1479 + pData, |
| 1726 + optLeavesReaderDataBytes(&readers[0]), | 1480 + optLeavesReaderDataBytes(&readers[0]), |
| 1727 + -1, DL_DEFAULT, &merged); | 1481 + -1, DL_DEFAULT, &merged); |
| 1728 + if( rc!= SQLITE_OK ) break; | 1482 + if( rc!= SQLITE_OK ) break; |
| 1729 }else{ | 1483 }else{ |
| 1730 DLReader dlReaders[MERGE_COUNT]; | 1484 DLReader dlReaders[MERGE_COUNT]; |
| 1731 int iReader, nReaders; | 1485 int iReader, nReaders; |
| 1732 @@ -6124,9 +6508,10 @@ | 1486 @@ -6253,9 +6508,10 @@ static int optimizeInternal(fulltext_vtab *v, |
| 1733 /* Prime the pipeline with the first reader's doclist. After | 1487 /* Prime the pipeline with the first reader's doclist. After |
| 1734 ** one pass index 0 will reference the accumulated doclist. | 1488 ** one pass index 0 will reference the accumulated doclist. |
| 1735 */ | 1489 */ |
| 1736 - dlrInit(&dlReaders[0], DL_DEFAULT, | 1490 - dlrInit(&dlReaders[0], DL_DEFAULT, |
| 1737 - optLeavesReaderData(&readers[0]), | 1491 - optLeavesReaderData(&readers[0]), |
| 1738 - optLeavesReaderDataBytes(&readers[0])); | 1492 - optLeavesReaderDataBytes(&readers[0])); |
| 1739 + rc = dlrInit(&dlReaders[0], DL_DEFAULT, | 1493 + rc = dlrInit(&dlReaders[0], DL_DEFAULT, |
| 1740 + pData, | 1494 + pData, |
| 1741 + optLeavesReaderDataBytes(&readers[0])); | 1495 + optLeavesReaderDataBytes(&readers[0])); |
| 1742 + if( rc!=SQLITE_OK ) break; | 1496 + if( rc!=SQLITE_OK ) break; |
| 1743 iReader = 1; | 1497 iReader = 1; |
| 1744 | 1498 |
| 1745 assert( iReader<i ); /* Must execute the loop at least once. */ | 1499 assert( iReader<i ); /* Must execute the loop at least once. */ |
| 1746 @@ -6134,24 +6519,35 @@ | 1500 @@ -6263,24 +6519,35 @@ static int optimizeInternal(fulltext_vtab *v, |
| 1747 /* Merge 16 inputs per pass. */ | 1501 /* Merge 16 inputs per pass. */ |
| 1748 for( nReaders=1; iReader<i && nReaders<MERGE_COUNT; | 1502 for( nReaders=1; iReader<i && nReaders<MERGE_COUNT; |
| 1749 iReader++, nReaders++ ){ | 1503 iReader++, nReaders++ ){ |
| 1750 - dlrInit(&dlReaders[nReaders], DL_DEFAULT, | 1504 - dlrInit(&dlReaders[nReaders], DL_DEFAULT, |
| 1751 - optLeavesReaderData(&readers[iReader]), | 1505 - optLeavesReaderData(&readers[iReader]), |
| 1752 - optLeavesReaderDataBytes(&readers[iReader])); | 1506 - optLeavesReaderDataBytes(&readers[iReader])); |
| 1753 + pData = optLeavesReaderData(&readers[iReader]); | 1507 + pData = optLeavesReaderData(&readers[iReader]); |
| 1754 + if( pData == NULL ){ | 1508 + if( pData == NULL ){ |
| 1755 + rc = SQLITE_CORRUPT_BKPT; | 1509 + rc = SQLITE_CORRUPT_BKPT; |
| 1756 + break; | 1510 + break; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1781 | 1535 |
| 1782 + if( rc!=SQLITE_OK ) goto err; | 1536 + if( rc!=SQLITE_OK ) goto err; |
| 1783 + | 1537 + |
| 1784 /* Accumulated doclist to reader 0 for next pass. */ | 1538 /* Accumulated doclist to reader 0 for next pass. */ |
| 1785 - dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); | 1539 - dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); |
| 1786 + rc = dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); | 1540 + rc = dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); |
| 1787 + if( rc!=SQLITE_OK ) goto err; | 1541 + if( rc!=SQLITE_OK ) goto err; |
| 1788 } | 1542 } |
| 1789 | 1543 |
| 1790 /* Destroy reader that was left in the pipeline. */ | 1544 /* Destroy reader that was left in the pipeline. */ |
| 1791 @@ -6159,8 +6555,9 @@ | 1545 @@ -6288,8 +6555,9 @@ static int optimizeInternal(fulltext_vtab *v, |
| 1792 | 1546 |
| 1793 /* Trim deletions from the doclist. */ | 1547 /* Trim deletions from the doclist. */ |
| 1794 dataBufferReset(&merged); | 1548 dataBufferReset(&merged); |
| 1795 - docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | 1549 - docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, |
| 1796 - -1, DL_DEFAULT, &merged); | 1550 - -1, DL_DEFAULT, &merged); |
| 1797 + rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | 1551 + rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, |
| 1798 + -1, DL_DEFAULT, &merged); | 1552 + -1, DL_DEFAULT, &merged); |
| 1799 + if( rc!=SQLITE_OK ) goto err; | 1553 + if( rc!=SQLITE_OK ) goto err; |
| 1800 } | 1554 } |
| 1801 | 1555 |
| 1802 /* Only pass doclists with hits (skip if all hits deleted). */ | 1556 /* Only pass doclists with hits (skip if all hits deleted). */ |
| 1803 @@ -6240,6 +6637,14 @@ | 1557 @@ -6628,16 +6896,19 @@ static void createDoclistResult(sqlite3_context *pContex
t, |
| 1804 const char *pRootData = sqlite3_column_blob(s, 2); | |
| 1805 int nRootData = sqlite3_column_bytes(s, 2); | |
| 1806 | |
| 1807 + /* Corrupt if we get back different types than we stored. */ | |
| 1808 + if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER || | |
| 1809 + sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
| 1810 + sqlite3_column_type(s, 2)!=SQLITE_BLOB ){ | |
| 1811 + rc = SQLITE_CORRUPT_BKPT; | |
| 1812 + break; | |
| 1813 + } | |
| 1814 + | |
| 1815 assert( i<nReaders ); | |
| 1816 rc = leavesReaderInit(v, -1, iStart, iEnd, pRootData, nRootData, | |
| 1817 &readers[i].reader); | |
| 1818 @@ -6253,6 +6658,8 @@ | |
| 1819 if( rc==SQLITE_DONE ){ | |
| 1820 assert( i==nReaders ); | |
| 1821 rc = optimizeInternal(v, readers, nReaders, &writer); | |
| 1822 + }else{ | |
| 1823 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
| 1824 } | |
| 1825 | |
| 1826 while( i-- > 0 ){ | |
| 1827 @@ -6316,9 +6723,18 @@ | |
| 1828 const sqlite_int64 iEndBlockid = sqlite3_column_int64(s, 1); | |
| 1829 const char *pRootData = sqlite3_column_blob(s, 2); | |
| 1830 const int nRootData = sqlite3_column_bytes(s, 2); | |
| 1831 + int rc; | |
| 1832 LeavesReader reader; | |
| 1833 - int rc = leavesReaderInit(v, 0, iStartBlockid, iEndBlockid, | |
| 1834 - pRootData, nRootData, &reader); | |
| 1835 + | |
| 1836 + /* Corrupt if we get back different types than we stored. */ | |
| 1837 + if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER || | |
| 1838 + sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
| 1839 + sqlite3_column_type(s, 2)!=SQLITE_BLOB ){ | |
| 1840 + return SQLITE_CORRUPT_BKPT; | |
| 1841 + } | |
| 1842 + | |
| 1843 + rc = leavesReaderInit(v, 0, iStartBlockid, iEndBlockid, | |
| 1844 + pRootData, nRootData, &reader); | |
| 1845 if( rc!=SQLITE_OK ) return rc; | |
| 1846 | |
| 1847 while( rc==SQLITE_OK && !leavesReaderAtEnd(&reader) ){ | |
| 1848 @@ -6480,16 +6896,19 @@ | |
| 1849 const char *pData, int nData){ | 1558 const char *pData, int nData){ |
| 1850 DataBuffer dump; | 1559 DataBuffer dump; |
| 1851 DLReader dlReader; | 1560 DLReader dlReader; |
| 1852 + int rc; | 1561 + int rc; |
| 1853 | 1562 |
| 1854 assert( pData!=NULL && nData>0 ); | 1563 assert( pData!=NULL && nData>0 ); |
| 1855 | 1564 |
| 1856 + rc = dlrInit(&dlReader, DL_DEFAULT, pData, nData); | 1565 + rc = dlrInit(&dlReader, DL_DEFAULT, pData, nData); |
| 1857 + if( rc!=SQLITE_OK ) return rc; | 1566 + if( rc!=SQLITE_OK ) return; |
| 1858 dataBufferInit(&dump, 0); | 1567 dataBufferInit(&dump, 0); |
| 1859 - dlrInit(&dlReader, DL_DEFAULT, pData, nData); | 1568 - dlrInit(&dlReader, DL_DEFAULT, pData, nData); |
| 1860 - for( ; !dlrAtEnd(&dlReader); dlrStep(&dlReader) ){ | 1569 - for( ; !dlrAtEnd(&dlReader); dlrStep(&dlReader) ){ |
| 1861 + for( ; rc==SQLITE_OK && !dlrAtEnd(&dlReader); rc = dlrStep(&dlReader) ){ | 1570 + for( ; rc==SQLITE_OK && !dlrAtEnd(&dlReader); rc = dlrStep(&dlReader) ){ |
| 1862 char buf[256]; | 1571 char buf[256]; |
| 1863 PLReader plReader; | 1572 PLReader plReader; |
| 1864 | 1573 |
| 1865 - plrInit(&plReader, &dlReader); | 1574 - plrInit(&plReader, &dlReader); |
| 1866 + rc = plrInit(&plReader, &dlReader); | 1575 + rc = plrInit(&plReader, &dlReader); |
| 1867 + if( rc!=SQLITE_OK ) break; | 1576 + if( rc!=SQLITE_OK ) break; |
| 1868 if( DL_DEFAULT==DL_DOCIDS || plrAtEnd(&plReader) ){ | 1577 if( DL_DEFAULT==DL_DOCIDS || plrAtEnd(&plReader) ){ |
| 1869 sqlite3_snprintf(sizeof(buf), buf, "[%lld] ", dlrDocid(&dlReader)); | 1578 sqlite3_snprintf(sizeof(buf), buf, "[%lld] ", dlrDocid(&dlReader)); |
| 1870 dataBufferAppend(&dump, buf, strlen(buf)); | 1579 dataBufferAppend(&dump, buf, strlen(buf)); |
| 1871 @@ -6500,7 +6919,8 @@ | 1580 @@ -6648,7 +6919,8 @@ static void createDoclistResult(sqlite3_context *pContext, |
| 1872 dlrDocid(&dlReader), iColumn); | 1581 dlrDocid(&dlReader), iColumn); |
| 1873 dataBufferAppend(&dump, buf, strlen(buf)); | 1582 dataBufferAppend(&dump, buf, strlen(buf)); |
| 1874 | 1583 |
| 1875 - for( ; !plrAtEnd(&plReader); plrStep(&plReader) ){ | 1584 - for( ; !plrAtEnd(&plReader); plrStep(&plReader) ){ |
| 1876 + for( ; !plrAtEnd(&plReader); rc = plrStep(&plReader) ){ | 1585 + for( ; !plrAtEnd(&plReader); rc = plrStep(&plReader) ){ |
| 1877 + if( rc!=SQLITE_OK ) break; | 1586 + if( rc!=SQLITE_OK ) break; |
| 1878 if( plrColumn(&plReader)!=iColumn ){ | 1587 if( plrColumn(&plReader)!=iColumn ){ |
| 1879 iColumn = plrColumn(&plReader); | 1588 iColumn = plrColumn(&plReader); |
| 1880 sqlite3_snprintf(sizeof(buf), buf, "] %d[", iColumn); | 1589 sqlite3_snprintf(sizeof(buf), buf, "] %d[", iColumn); |
| 1881 @@ -6521,6 +6941,7 @@ | 1590 @@ -6669,6 +6941,7 @@ static void createDoclistResult(sqlite3_context *pContext, |
| 1882 dataBufferAppend(&dump, buf, strlen(buf)); | 1591 dataBufferAppend(&dump, buf, strlen(buf)); |
| 1883 } | 1592 } |
| 1884 plrDestroy(&plReader); | 1593 plrDestroy(&plReader); |
| 1885 + if( rc!= SQLITE_OK ) break; | 1594 + if( rc!= SQLITE_OK ) break; |
| 1886 | 1595 |
| 1887 assert( dump.nData>0 ); | 1596 assert( dump.nData>0 ); |
| 1888 dump.nData--; /* Overwrite trailing space. */ | 1597 dump.nData--; /* Overwrite trailing space. */ |
| 1889 @@ -6529,6 +6950,10 @@ | 1598 @@ -6677,6 +6950,10 @@ static void createDoclistResult(sqlite3_context *pContext
, |
| 1890 } | 1599 } |
| 1891 } | 1600 } |
| 1892 dlrDestroy(&dlReader); | 1601 dlrDestroy(&dlReader); |
| 1893 + if( rc!=SQLITE_OK ){ | 1602 + if( rc!=SQLITE_OK ){ |
| 1894 + dataBufferDestroy(&dump); | 1603 + dataBufferDestroy(&dump); |
| 1895 + return rc; | 1604 + return; |
| 1896 + } | 1605 + } |
| 1897 | 1606 |
| 1898 assert( dump.nData>0 ); | 1607 assert( dump.nData>0 ); |
| 1899 dump.nData--; /* Overwrite trailing space. */ | 1608 dump.nData--; /* Overwrite trailing space. */ |
| 1900 @@ -6540,6 +6965,7 @@ | 1609 -- |
| 1901 sqlite3_result_text(pContext, dump.pData, dump.nData, sqlite3_free); | 1610 2.2.1 |
| 1902 dump.pData = NULL; | 1611 |
| 1903 dump.nData = dump.nCapacity = 0; | |
| 1904 + return SQLITE_OK; | |
| 1905 } | |
| 1906 | |
| 1907 /* Implements dump_doclist() for use in inspecting the fts2 index from | |
| 1908 @@ -6822,7 +7248,11 @@ | |
| 1909 ** module with sqlite. | |
| 1910 */ | |
| 1911 if( SQLITE_OK==rc | |
| 1912 +#if GEARS_FTS2_CHANGES && !SQLITE_TEST | |
| 1913 + /* fts2_tokenizer() disabled for security reasons. */ | |
| 1914 +#else | |
| 1915 && SQLITE_OK==(rc = sqlite3Fts2InitHashTable(db, pHash, "fts2_tokenizer")) | |
| 1916 +#endif | |
| 1917 && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1)) | |
| 1918 && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", -1)) | |
| 1919 && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", -1)) | |
| 1920 diff -ru ext-orig/fts2/fts2_icu.c ext/fts2/fts2_icu.c | |
| 1921 --- ext-orig/fts2/fts2_icu.c» 2009-09-03 13:32:06.000000000 -0700 | |
| 1922 +++ ext/fts2/fts2_icu.c»2009-09-18 14:39:41.000000000 -0700 | |
| 1923 @@ -198,7 +198,7 @@ | |
| 1924 | |
| 1925 while( iStart<iEnd ){ | |
| 1926 int iWhite = iStart; | |
| 1927 - U8_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c); | |
| 1928 + U16_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c); | |
| 1929 if( u_isspace(c) ){ | |
| 1930 iStart = iWhite; | |
| 1931 }else{ | |
| 1932 diff -ru ext-orig/fts2/fts2_tokenizer.c ext/fts2/fts2_tokenizer.c | |
| 1933 --- ext-orig/fts2/fts2_tokenizer.c» 2009-09-03 13:32:06.000000000 -0700 | |
| 1934 +++ ext/fts2/fts2_tokenizer.c» 2009-09-18 14:39:41.000000000 -0700 | |
| 1935 @@ -28,11 +28,14 @@ | |
| 1936 | |
| 1937 #include "sqlite3.h" | |
| 1938 #include "sqlite3ext.h" | |
| 1939 -SQLITE_EXTENSION_INIT1 | |
| 1940 +#ifndef SQLITE_CORE | |
| 1941 + SQLITE_EXTENSION_INIT1 | |
| 1942 +#endif | |
| 1943 | |
| 1944 #include "fts2_hash.h" | |
| 1945 #include "fts2_tokenizer.h" | |
| 1946 #include <assert.h> | |
| 1947 +#include <stddef.h> | |
| 1948 | |
| 1949 /* | |
| 1950 ** Implementation of the SQL scalar function for accessing the underlying | |
| OLD | NEW |