| OLD | NEW |
| (Empty) |
| 1 From 106d71238a58d4dfbeb8cf1cba45a1c4e6f583e8 Mon Sep 17 00:00:00 2001 | |
| 2 From: Chris Evans <cevans@chromium.org> | |
| 3 Date: Wed, 30 Sep 2009 23:10:34 +0000 | |
| 4 Subject: [PATCH 23/23] [fts2] Fix numerous out-of-bounds bugs reading corrupt | |
| 5 database. | |
| 6 | |
| 7 Fix numerous bugs in fts2 where a corrupt fts2 database could cause | |
| 8 out-of-bounds reads and writes. | |
| 9 | |
| 10 Original review URL is more descriptive: | |
| 11 http://codereview.chromium.org/216026 | |
| 12 --- | |
| 13 third_party/sqlite/src/ext/fts2/fts2.c | 751 ++++++++++++++++++++++----------- | |
| 14 1 file changed, 514 insertions(+), 237 deletions(-) | |
| 15 | |
| 16 diff --git a/third_party/sqlite/src/ext/fts2/fts2.c b/third_party/sqlite/src/ext
/fts2/fts2.c | |
| 17 index d5587b3..36d14ff 100644 | |
| 18 --- a/third_party/sqlite/src/ext/fts2/fts2.c | |
| 19 +++ b/third_party/sqlite/src/ext/fts2/fts2.c | |
| 20 @@ -447,30 +447,41 @@ static int putVarint(char *p, sqlite_int64 v){ | |
| 21 /* Read a 64-bit variable-length integer from memory starting at p[0]. | |
| 22 * Return the number of bytes read, or 0 on error. | |
| 23 * The value is stored in *v. */ | |
| 24 -static int getVarint(const char *p, sqlite_int64 *v){ | |
| 25 +static int getVarintSafe(const char *p, sqlite_int64 *v, int max){ | |
| 26 const unsigned char *q = (const unsigned char *) p; | |
| 27 sqlite_uint64 x = 0, y = 1; | |
| 28 - while( (*q & 0x80) == 0x80 ){ | |
| 29 + if( max>VARINT_MAX ) max = VARINT_MAX; | |
| 30 + while( max && (*q & 0x80) == 0x80 ){ | |
| 31 + max--; | |
| 32 x += y * (*q++ & 0x7f); | |
| 33 y <<= 7; | |
| 34 - if( q - (unsigned char *)p >= VARINT_MAX ){ /* bad data */ | |
| 35 - assert( 0 ); | |
| 36 - return 0; | |
| 37 - } | |
| 38 + } | |
| 39 + if ( !max ){ | |
| 40 + assert( 0 ); | |
| 41 + return 0; /* tried to read too much; bad data */ | |
| 42 } | |
| 43 x += y * (*q++); | |
| 44 *v = (sqlite_int64) x; | |
| 45 return (int) (q - (unsigned char *)p); | |
| 46 } | |
| 47 | |
| 48 -static int getVarint32(const char *p, int *pi){ | |
| 49 +static int getVarint(const char *p, sqlite_int64 *v){ | |
| 50 + return getVarintSafe(p, v, VARINT_MAX); | |
| 51 +} | |
| 52 + | |
| 53 +static int getVarint32Safe(const char *p, int *pi, int max){ | |
| 54 sqlite_int64 i; | |
| 55 - int ret = getVarint(p, &i); | |
| 56 + int ret = getVarintSafe(p, &i, max); | |
| 57 + if( !ret ) return ret; | |
| 58 *pi = (int) i; | |
| 59 assert( *pi==i ); | |
| 60 return ret; | |
| 61 } | |
| 62 | |
| 63 +static int getVarint32(const char* p, int *pi){ | |
| 64 + return getVarint32Safe(p, pi, VARINT_MAX); | |
| 65 +} | |
| 66 + | |
| 67 /*******************************************************************/ | |
| 68 /* DataBuffer is used to collect data into a buffer in piecemeal | |
| 69 ** fashion. It implements the usual distinction between amount of | |
| 70 @@ -639,7 +650,7 @@ typedef struct DLReader { | |
| 71 | |
| 72 static int dlrAtEnd(DLReader *pReader){ | |
| 73 assert( pReader->nData>=0 ); | |
| 74 - return pReader->nData==0; | |
| 75 + return pReader->nData<=0; | |
| 76 } | |
| 77 static sqlite_int64 dlrDocid(DLReader *pReader){ | |
| 78 assert( !dlrAtEnd(pReader) ); | |
| 79 @@ -663,7 +674,8 @@ static int dlrAllDataBytes(DLReader *pReader){ | |
| 80 */ | |
| 81 static const char *dlrPosData(DLReader *pReader){ | |
| 82 sqlite_int64 iDummy; | |
| 83 - int n = getVarint(pReader->pData, &iDummy); | |
| 84 + int n = getVarintSafe(pReader->pData, &iDummy, pReader->nElement); | |
| 85 + if( !n ) return NULL; | |
| 86 assert( !dlrAtEnd(pReader) ); | |
| 87 return pReader->pData+n; | |
| 88 } | |
| 89 @@ -673,7 +685,7 @@ static int dlrPosDataLen(DLReader *pReader){ | |
| 90 assert( !dlrAtEnd(pReader) ); | |
| 91 return pReader->nElement-n; | |
| 92 } | |
| 93 -static void dlrStep(DLReader *pReader){ | |
| 94 +static int dlrStep(DLReader *pReader){ | |
| 95 assert( !dlrAtEnd(pReader) ); | |
| 96 | |
| 97 /* Skip past current doclist element. */ | |
| 98 @@ -682,32 +694,48 @@ static void dlrStep(DLReader *pReader){ | |
| 99 pReader->nData -= pReader->nElement; | |
| 100 | |
| 101 /* If there is more data, read the next doclist element. */ | |
| 102 - if( pReader->nData!=0 ){ | |
| 103 + if( pReader->nData>0 ){ | |
| 104 sqlite_int64 iDocidDelta; | |
| 105 - int iDummy, n = getVarint(pReader->pData, &iDocidDelta); | |
| 106 + int nTotal = 0; | |
| 107 + int iDummy, n = getVarintSafe(pReader->pData, &iDocidDelta, pReader->nData)
; | |
| 108 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 109 + nTotal += n; | |
| 110 pReader->iDocid += iDocidDelta; | |
| 111 if( pReader->iType>=DL_POSITIONS ){ | |
| 112 - assert( n<pReader->nData ); | |
| 113 while( 1 ){ | |
| 114 - n += getVarint32(pReader->pData+n, &iDummy); | |
| 115 - assert( n<=pReader->nData ); | |
| 116 + n = getVarint32Safe(pReader->pData+nTotal, &iDummy, | |
| 117 + pReader->nData-nTotal); | |
| 118 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 119 + nTotal += n; | |
| 120 if( iDummy==POS_END ) break; | |
| 121 if( iDummy==POS_COLUMN ){ | |
| 122 - n += getVarint32(pReader->pData+n, &iDummy); | |
| 123 - assert( n<pReader->nData ); | |
| 124 + n = getVarint32Safe(pReader->pData+nTotal, &iDummy, | |
| 125 + pReader->nData-nTotal); | |
| 126 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 127 + nTotal += n; | |
| 128 }else if( pReader->iType==DL_POSITIONS_OFFSETS ){ | |
| 129 - n += getVarint32(pReader->pData+n, &iDummy); | |
| 130 - n += getVarint32(pReader->pData+n, &iDummy); | |
| 131 - assert( n<pReader->nData ); | |
| 132 + n = getVarint32Safe(pReader->pData+nTotal, &iDummy, | |
| 133 + pReader->nData-nTotal); | |
| 134 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 135 + nTotal += n; | |
| 136 + n = getVarint32Safe(pReader->pData+nTotal, &iDummy, | |
| 137 + pReader->nData-nTotal); | |
| 138 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 139 + nTotal += n; | |
| 140 } | |
| 141 } | |
| 142 } | |
| 143 - pReader->nElement = n; | |
| 144 + pReader->nElement = nTotal; | |
| 145 assert( pReader->nElement<=pReader->nData ); | |
| 146 } | |
| 147 + return SQLITE_OK; | |
| 148 } | |
| 149 -static void dlrInit(DLReader *pReader, DocListType iType, | |
| 150 - const char *pData, int nData){ | |
| 151 +static void dlrDestroy(DLReader *pReader){ | |
| 152 + SCRAMBLE(pReader); | |
| 153 +} | |
| 154 +static int dlrInit(DLReader *pReader, DocListType iType, | |
| 155 + const char *pData, int nData){ | |
| 156 + int rc; | |
| 157 assert( pData!=NULL && nData!=0 ); | |
| 158 pReader->iType = iType; | |
| 159 pReader->pData = pData; | |
| 160 @@ -716,10 +744,9 @@ static void dlrInit(DLReader *pReader, DocListType iType, | |
| 161 pReader->iDocid = 0; | |
| 162 | |
| 163 /* Load the first element's data. There must be a first element. */ | |
| 164 - dlrStep(pReader); | |
| 165 -} | |
| 166 -static void dlrDestroy(DLReader *pReader){ | |
| 167 - SCRAMBLE(pReader); | |
| 168 + rc = dlrStep(pReader); | |
| 169 + if( rc!=SQLITE_OK ) dlrDestroy(pReader); | |
| 170 + return rc; | |
| 171 } | |
| 172 | |
| 173 #ifndef NDEBUG | |
| 174 @@ -806,9 +833,9 @@ static void dlwDestroy(DLWriter *pWriter){ | |
| 175 /* TODO(shess) This has become just a helper for docListMerge. | |
| 176 ** Consider a refactor to make this cleaner. | |
| 177 */ | |
| 178 -static void dlwAppend(DLWriter *pWriter, | |
| 179 - const char *pData, int nData, | |
| 180 - sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ | |
| 181 +static int dlwAppend(DLWriter *pWriter, | |
| 182 + const char *pData, int nData, | |
| 183 + sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ | |
| 184 sqlite_int64 iDocid = 0; | |
| 185 char c[VARINT_MAX]; | |
| 186 int nFirstOld, nFirstNew; /* Old and new varint len of first docid. */ | |
| 187 @@ -817,7 +844,8 @@ static void dlwAppend(DLWriter *pWriter, | |
| 188 #endif | |
| 189 | |
| 190 /* Recode the initial docid as delta from iPrevDocid. */ | |
| 191 - nFirstOld = getVarint(pData, &iDocid); | |
| 192 + nFirstOld = getVarintSafe(pData, &iDocid, nData); | |
| 193 + if( !nFirstOld ) return SQLITE_CORRUPT_BKPT; | |
| 194 assert( nFirstOld<nData || (nFirstOld==nData && pWriter->iType==DL_DOCIDS) ); | |
| 195 nFirstNew = putVarint(c, iFirstDocid-pWriter->iPrevDocid); | |
| 196 | |
| 197 @@ -838,10 +866,11 @@ static void dlwAppend(DLWriter *pWriter, | |
| 198 dataBufferAppend(pWriter->b, c, nFirstNew); | |
| 199 } | |
| 200 pWriter->iPrevDocid = iLastDocid; | |
| 201 + return SQLITE_OK; | |
| 202 } | |
| 203 -static void dlwCopy(DLWriter *pWriter, DLReader *pReader){ | |
| 204 - dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), | |
| 205 - dlrDocid(pReader), dlrDocid(pReader)); | |
| 206 +static int dlwCopy(DLWriter *pWriter, DLReader *pReader){ | |
| 207 + return dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), | |
| 208 + dlrDocid(pReader), dlrDocid(pReader)); | |
| 209 } | |
| 210 static void dlwAdd(DLWriter *pWriter, sqlite_int64 iDocid){ | |
| 211 char c[VARINT_MAX]; | |
| 212 @@ -902,45 +931,63 @@ static int plrEndOffset(PLReader *pReader){ | |
| 213 assert( !plrAtEnd(pReader) ); | |
| 214 return pReader->iEndOffset; | |
| 215 } | |
| 216 -static void plrStep(PLReader *pReader){ | |
| 217 - int i, n; | |
| 218 +static int plrStep(PLReader *pReader){ | |
| 219 + int i, n, nTotal = 0; | |
| 220 | |
| 221 assert( !plrAtEnd(pReader) ); | |
| 222 | |
| 223 - if( pReader->nData==0 ){ | |
| 224 + if( pReader->nData<=0 ){ | |
| 225 pReader->pData = NULL; | |
| 226 - return; | |
| 227 + return SQLITE_OK; | |
| 228 } | |
| 229 | |
| 230 - n = getVarint32(pReader->pData, &i); | |
| 231 + n = getVarint32Safe(pReader->pData, &i, pReader->nData); | |
| 232 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 233 + nTotal += n; | |
| 234 if( i==POS_COLUMN ){ | |
| 235 - n += getVarint32(pReader->pData+n, &pReader->iColumn); | |
| 236 + n = getVarint32Safe(pReader->pData+nTotal, &pReader->iColumn, | |
| 237 + pReader->nData-nTotal); | |
| 238 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 239 + nTotal += n; | |
| 240 pReader->iPosition = 0; | |
| 241 pReader->iStartOffset = 0; | |
| 242 - n += getVarint32(pReader->pData+n, &i); | |
| 243 + n = getVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); | |
| 244 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 245 + nTotal += n; | |
| 246 } | |
| 247 /* Should never see adjacent column changes. */ | |
| 248 assert( i!=POS_COLUMN ); | |
| 249 | |
| 250 if( i==POS_END ){ | |
| 251 + assert( nTotal<=pReader->nData ); | |
| 252 pReader->nData = 0; | |
| 253 pReader->pData = NULL; | |
| 254 - return; | |
| 255 + return SQLITE_OK; | |
| 256 } | |
| 257 | |
| 258 pReader->iPosition += i-POS_BASE; | |
| 259 if( pReader->iType==DL_POSITIONS_OFFSETS ){ | |
| 260 - n += getVarint32(pReader->pData+n, &i); | |
| 261 + n = getVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); | |
| 262 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 263 + nTotal += n; | |
| 264 pReader->iStartOffset += i; | |
| 265 - n += getVarint32(pReader->pData+n, &i); | |
| 266 + n = getVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); | |
| 267 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 268 + nTotal += n; | |
| 269 pReader->iEndOffset = pReader->iStartOffset+i; | |
| 270 } | |
| 271 - assert( n<=pReader->nData ); | |
| 272 - pReader->pData += n; | |
| 273 - pReader->nData -= n; | |
| 274 + assert( nTotal<=pReader->nData ); | |
| 275 + pReader->pData += nTotal; | |
| 276 + pReader->nData -= nTotal; | |
| 277 + return SQLITE_OK; | |
| 278 } | |
| 279 | |
| 280 -static void plrInit(PLReader *pReader, DLReader *pDLReader){ | |
| 281 +static void plrDestroy(PLReader *pReader){ | |
| 282 + SCRAMBLE(pReader); | |
| 283 +} | |
| 284 + | |
| 285 +static int plrInit(PLReader *pReader, DLReader *pDLReader){ | |
| 286 + int rc; | |
| 287 pReader->pData = dlrPosData(pDLReader); | |
| 288 pReader->nData = dlrPosDataLen(pDLReader); | |
| 289 pReader->iType = pDLReader->iType; | |
| 290 @@ -948,10 +995,9 @@ static void plrInit(PLReader *pReader, DLReader *pDLReader)
{ | |
| 291 pReader->iPosition = 0; | |
| 292 pReader->iStartOffset = 0; | |
| 293 pReader->iEndOffset = 0; | |
| 294 - plrStep(pReader); | |
| 295 -} | |
| 296 -static void plrDestroy(PLReader *pReader){ | |
| 297 - SCRAMBLE(pReader); | |
| 298 + rc = plrStep(pReader); | |
| 299 + if( rc!=SQLITE_OK ) plrDestroy(pReader); | |
| 300 + return rc; | |
| 301 } | |
| 302 | |
| 303 /*******************************************************************/ | |
| 304 @@ -1137,14 +1183,16 @@ static void dlcDelete(DLCollector *pCollector){ | |
| 305 ** deletion will be trimmed, and will thus not effect a deletion | |
| 306 ** during the merge. | |
| 307 */ | |
| 308 -static void docListTrim(DocListType iType, const char *pData, int nData, | |
| 309 - int iColumn, DocListType iOutType, DataBuffer *out){ | |
| 310 +static int docListTrim(DocListType iType, const char *pData, int nData, | |
| 311 + int iColumn, DocListType iOutType, DataBuffer *out){ | |
| 312 DLReader dlReader; | |
| 313 DLWriter dlWriter; | |
| 314 + int rc; | |
| 315 | |
| 316 assert( iOutType<=iType ); | |
| 317 | |
| 318 - dlrInit(&dlReader, iType, pData, nData); | |
| 319 + rc = dlrInit(&dlReader, iType, pData, nData); | |
| 320 + if( rc!=SQLITE_OK ) return rc; | |
| 321 dlwInit(&dlWriter, iOutType, out); | |
| 322 | |
| 323 while( !dlrAtEnd(&dlReader) ){ | |
| 324 @@ -1152,7 +1200,8 @@ static void docListTrim(DocListType iType, const char *pDa
ta, int nData, | |
| 325 PLWriter plWriter; | |
| 326 int match = 0; | |
| 327 | |
| 328 - plrInit(&plReader, &dlReader); | |
| 329 + rc = plrInit(&plReader, &dlReader); | |
| 330 + if( rc!=SQLITE_OK ) break; | |
| 331 | |
| 332 while( !plrAtEnd(&plReader) ){ | |
| 333 if( iColumn==-1 || plrColumn(&plReader)==iColumn ){ | |
| 334 @@ -1163,7 +1212,11 @@ static void docListTrim(DocListType iType, const char *pD
ata, int nData, | |
| 335 plwAdd(&plWriter, plrColumn(&plReader), plrPosition(&plReader), | |
| 336 plrStartOffset(&plReader), plrEndOffset(&plReader)); | |
| 337 } | |
| 338 - plrStep(&plReader); | |
| 339 + rc = plrStep(&plReader); | |
| 340 + if( rc!=SQLITE_OK ){ | |
| 341 + plrDestroy(&plReader); | |
| 342 + goto err; | |
| 343 + } | |
| 344 } | |
| 345 if( match ){ | |
| 346 plwTerminate(&plWriter); | |
| 347 @@ -1171,10 +1224,13 @@ static void docListTrim(DocListType iType, const char *p
Data, int nData, | |
| 348 } | |
| 349 | |
| 350 plrDestroy(&plReader); | |
| 351 - dlrStep(&dlReader); | |
| 352 + rc = dlrStep(&dlReader); | |
| 353 + if( rc!=SQLITE_OK ) break; | |
| 354 } | |
| 355 +err: | |
| 356 dlwDestroy(&dlWriter); | |
| 357 dlrDestroy(&dlReader); | |
| 358 + return rc; | |
| 359 } | |
| 360 | |
| 361 /* Used by docListMerge() to keep doclists in the ascending order by | |
| 362 @@ -1231,19 +1287,20 @@ static void orderedDLReaderReorder(OrderedDLReader *p, i
nt n){ | |
| 363 /* TODO(shess) nReaders must be <= MERGE_COUNT. This should probably | |
| 364 ** be fixed. | |
| 365 */ | |
| 366 -static void docListMerge(DataBuffer *out, | |
| 367 - DLReader *pReaders, int nReaders){ | |
| 368 +static int docListMerge(DataBuffer *out, | |
| 369 + DLReader *pReaders, int nReaders){ | |
| 370 OrderedDLReader readers[MERGE_COUNT]; | |
| 371 DLWriter writer; | |
| 372 int i, n; | |
| 373 const char *pStart = 0; | |
| 374 int nStart = 0; | |
| 375 sqlite_int64 iFirstDocid = 0, iLastDocid = 0; | |
| 376 + int rc = SQLITE_OK; | |
| 377 | |
| 378 assert( nReaders>0 ); | |
| 379 if( nReaders==1 ){ | |
| 380 dataBufferAppend(out, dlrDocData(pReaders), dlrAllDataBytes(pReaders)); | |
| 381 - return; | |
| 382 + return SQLITE_OK; | |
| 383 } | |
| 384 | |
| 385 assert( nReaders<=MERGE_COUNT ); | |
| 386 @@ -1276,20 +1333,23 @@ static void docListMerge(DataBuffer *out, | |
| 387 nStart += dlrDocDataBytes(readers[0].pReader); | |
| 388 }else{ | |
| 389 if( pStart!=0 ){ | |
| 390 - dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | |
| 391 + rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | |
| 392 + if( rc!=SQLITE_OK ) goto err; | |
| 393 } | |
| 394 pStart = dlrDocData(readers[0].pReader); | |
| 395 nStart = dlrDocDataBytes(readers[0].pReader); | |
| 396 iFirstDocid = iDocid; | |
| 397 } | |
| 398 iLastDocid = iDocid; | |
| 399 - dlrStep(readers[0].pReader); | |
| 400 + rc = dlrStep(readers[0].pReader); | |
| 401 + if( rc!=SQLITE_OK ) goto err; | |
| 402 | |
| 403 /* Drop all of the older elements with the same docid. */ | |
| 404 for(i=1; i<nReaders && | |
| 405 !dlrAtEnd(readers[i].pReader) && | |
| 406 dlrDocid(readers[i].pReader)==iDocid; i++){ | |
| 407 - dlrStep(readers[i].pReader); | |
| 408 + rc = dlrStep(readers[i].pReader); | |
| 409 + if( rc!=SQLITE_OK ) goto err; | |
| 410 } | |
| 411 | |
| 412 /* Get the readers back into order. */ | |
| 413 @@ -1299,8 +1359,11 @@ static void docListMerge(DataBuffer *out, | |
| 414 } | |
| 415 | |
| 416 /* Copy over any remaining elements. */ | |
| 417 - if( nStart>0 ) dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | |
| 418 + if( nStart>0 ) | |
| 419 + rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | |
| 420 +err: | |
| 421 dlwDestroy(&writer); | |
| 422 + return rc; | |
| 423 } | |
| 424 | |
| 425 /* Helper function for posListUnion(). Compares the current position | |
| 426 @@ -1336,30 +1399,40 @@ static int posListCmp(PLReader *pLeft, PLReader *pRight)
{ | |
| 427 ** work with any doclist type, though both inputs and the output | |
| 428 ** should be the same type. | |
| 429 */ | |
| 430 -static void posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ | |
| 431 +static int posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ | |
| 432 PLReader left, right; | |
| 433 PLWriter writer; | |
| 434 + int rc; | |
| 435 | |
| 436 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); | |
| 437 assert( pLeft->iType==pRight->iType ); | |
| 438 assert( pLeft->iType==pOut->iType ); | |
| 439 | |
| 440 - plrInit(&left, pLeft); | |
| 441 - plrInit(&right, pRight); | |
| 442 + rc = plrInit(&left, pLeft); | |
| 443 + if( rc != SQLITE_OK ) return rc; | |
| 444 + rc = plrInit(&right, pRight); | |
| 445 + if( rc != SQLITE_OK ){ | |
| 446 + plrDestroy(&left); | |
| 447 + return rc; | |
| 448 + } | |
| 449 plwInit(&writer, pOut, dlrDocid(pLeft)); | |
| 450 | |
| 451 while( !plrAtEnd(&left) || !plrAtEnd(&right) ){ | |
| 452 int c = posListCmp(&left, &right); | |
| 453 if( c<0 ){ | |
| 454 plwCopy(&writer, &left); | |
| 455 - plrStep(&left); | |
| 456 + rc = plrStep(&left); | |
| 457 + if( rc != SQLITE_OK ) break; | |
| 458 }else if( c>0 ){ | |
| 459 plwCopy(&writer, &right); | |
| 460 - plrStep(&right); | |
| 461 + rc = plrStep(&right); | |
| 462 + if( rc != SQLITE_OK ) break; | |
| 463 }else{ | |
| 464 plwCopy(&writer, &left); | |
| 465 - plrStep(&left); | |
| 466 - plrStep(&right); | |
| 467 + rc = plrStep(&left); | |
| 468 + if( rc != SQLITE_OK ) break; | |
| 469 + rc = plrStep(&right); | |
| 470 + if( rc != SQLITE_OK ) break; | |
| 471 } | |
| 472 } | |
| 473 | |
| 474 @@ -1367,56 +1440,75 @@ static void posListUnion(DLReader *pLeft, DLReader *pRig
ht, DLWriter *pOut){ | |
| 475 plwDestroy(&writer); | |
| 476 plrDestroy(&left); | |
| 477 plrDestroy(&right); | |
| 478 + return rc; | |
| 479 } | |
| 480 | |
| 481 /* Write the union of doclists in pLeft and pRight to pOut. For | |
| 482 ** docids in common between the inputs, the union of the position | |
| 483 ** lists is written. Inputs and outputs are always type DL_DEFAULT. | |
| 484 */ | |
| 485 -static void docListUnion( | |
| 486 +static int docListUnion( | |
| 487 const char *pLeft, int nLeft, | |
| 488 const char *pRight, int nRight, | |
| 489 DataBuffer *pOut /* Write the combined doclist here */ | |
| 490 ){ | |
| 491 DLReader left, right; | |
| 492 DLWriter writer; | |
| 493 + int rc; | |
| 494 | |
| 495 if( nLeft==0 ){ | |
| 496 if( nRight!=0) dataBufferAppend(pOut, pRight, nRight); | |
| 497 - return; | |
| 498 + return SQLITE_OK; | |
| 499 } | |
| 500 if( nRight==0 ){ | |
| 501 dataBufferAppend(pOut, pLeft, nLeft); | |
| 502 - return; | |
| 503 + return SQLITE_OK; | |
| 504 } | |
| 505 | |
| 506 - dlrInit(&left, DL_DEFAULT, pLeft, nLeft); | |
| 507 - dlrInit(&right, DL_DEFAULT, pRight, nRight); | |
| 508 + rc = dlrInit(&left, DL_DEFAULT, pLeft, nLeft); | |
| 509 + if( rc!=SQLITE_OK ) return rc; | |
| 510 + rc = dlrInit(&right, DL_DEFAULT, pRight, nRight); | |
| 511 + if( rc!=SQLITE_OK ){ | |
| 512 + dlrDestroy(&left); | |
| 513 + return rc; | |
| 514 + } | |
| 515 dlwInit(&writer, DL_DEFAULT, pOut); | |
| 516 | |
| 517 while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ | |
| 518 if( dlrAtEnd(&right) ){ | |
| 519 - dlwCopy(&writer, &left); | |
| 520 - dlrStep(&left); | |
| 521 + rc = dlwCopy(&writer, &left); | |
| 522 + if( rc!=SQLITE_OK ) break; | |
| 523 + rc = dlrStep(&left); | |
| 524 + if( rc!=SQLITE_OK ) break; | |
| 525 }else if( dlrAtEnd(&left) ){ | |
| 526 - dlwCopy(&writer, &right); | |
| 527 - dlrStep(&right); | |
| 528 + rc = dlwCopy(&writer, &right); | |
| 529 + if( rc!=SQLITE_OK ) break; | |
| 530 + rc = dlrStep(&right); | |
| 531 + if( rc!=SQLITE_OK ) break; | |
| 532 }else if( dlrDocid(&left)<dlrDocid(&right) ){ | |
| 533 - dlwCopy(&writer, &left); | |
| 534 - dlrStep(&left); | |
| 535 + rc = dlwCopy(&writer, &left); | |
| 536 + if( rc!=SQLITE_OK ) break; | |
| 537 + rc = dlrStep(&left); | |
| 538 + if( rc!=SQLITE_OK ) break; | |
| 539 }else if( dlrDocid(&left)>dlrDocid(&right) ){ | |
| 540 - dlwCopy(&writer, &right); | |
| 541 - dlrStep(&right); | |
| 542 + rc = dlwCopy(&writer, &right); | |
| 543 + if( rc!=SQLITE_OK ) break; | |
| 544 + rc = dlrStep(&right); | |
| 545 + if( rc!=SQLITE_OK ) break; | |
| 546 }else{ | |
| 547 - posListUnion(&left, &right, &writer); | |
| 548 - dlrStep(&left); | |
| 549 - dlrStep(&right); | |
| 550 + rc = posListUnion(&left, &right, &writer); | |
| 551 + if( rc!=SQLITE_OK ) break; | |
| 552 + rc = dlrStep(&left); | |
| 553 + if( rc!=SQLITE_OK ) break; | |
| 554 + rc = dlrStep(&right); | |
| 555 + if( rc!=SQLITE_OK ) break; | |
| 556 } | |
| 557 } | |
| 558 | |
| 559 dlrDestroy(&left); | |
| 560 dlrDestroy(&right); | |
| 561 dlwDestroy(&writer); | |
| 562 + return rc; | |
| 563 } | |
| 564 | |
| 565 /* pLeft and pRight are DLReaders positioned to the same docid. | |
| 566 @@ -1431,35 +1523,47 @@ static void docListUnion( | |
| 567 ** include the positions from pRight that are one more than a | |
| 568 ** position in pLeft. In other words: pRight.iPos==pLeft.iPos+1. | |
| 569 */ | |
| 570 -static void posListPhraseMerge(DLReader *pLeft, DLReader *pRight, | |
| 571 - DLWriter *pOut){ | |
| 572 +static int posListPhraseMerge(DLReader *pLeft, DLReader *pRight, | |
| 573 + DLWriter *pOut){ | |
| 574 PLReader left, right; | |
| 575 PLWriter writer; | |
| 576 int match = 0; | |
| 577 + int rc; | |
| 578 | |
| 579 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); | |
| 580 assert( pOut->iType!=DL_POSITIONS_OFFSETS ); | |
| 581 | |
| 582 - plrInit(&left, pLeft); | |
| 583 - plrInit(&right, pRight); | |
| 584 + rc = plrInit(&left, pLeft); | |
| 585 + if( rc!=SQLITE_OK ) return rc; | |
| 586 + rc = plrInit(&right, pRight); | |
| 587 + if( rc!=SQLITE_OK ){ | |
| 588 + plrDestroy(&left); | |
| 589 + return rc; | |
| 590 + } | |
| 591 | |
| 592 while( !plrAtEnd(&left) && !plrAtEnd(&right) ){ | |
| 593 if( plrColumn(&left)<plrColumn(&right) ){ | |
| 594 - plrStep(&left); | |
| 595 + rc = plrStep(&left); | |
| 596 + if( rc!=SQLITE_OK ) break; | |
| 597 }else if( plrColumn(&left)>plrColumn(&right) ){ | |
| 598 - plrStep(&right); | |
| 599 + rc = plrStep(&right); | |
| 600 + if( rc!=SQLITE_OK ) break; | |
| 601 }else if( plrPosition(&left)+1<plrPosition(&right) ){ | |
| 602 - plrStep(&left); | |
| 603 + rc = plrStep(&left); | |
| 604 + if( rc!=SQLITE_OK ) break; | |
| 605 }else if( plrPosition(&left)+1>plrPosition(&right) ){ | |
| 606 - plrStep(&right); | |
| 607 + rc = plrStep(&right); | |
| 608 + if( rc!=SQLITE_OK ) break; | |
| 609 }else{ | |
| 610 if( !match ){ | |
| 611 plwInit(&writer, pOut, dlrDocid(pLeft)); | |
| 612 match = 1; | |
| 613 } | |
| 614 plwAdd(&writer, plrColumn(&right), plrPosition(&right), 0, 0); | |
| 615 - plrStep(&left); | |
| 616 - plrStep(&right); | |
| 617 + rc = plrStep(&left); | |
| 618 + if( rc!=SQLITE_OK ) break; | |
| 619 + rc = plrStep(&right); | |
| 620 + if( rc!=SQLITE_OK ) break; | |
| 621 } | |
| 622 } | |
| 623 | |
| 624 @@ -1470,6 +1574,7 @@ static void posListPhraseMerge(DLReader *pLeft, DLReader *
pRight, | |
| 625 | |
| 626 plrDestroy(&left); | |
| 627 plrDestroy(&right); | |
| 628 + return rc; | |
| 629 } | |
| 630 | |
| 631 /* We have two doclists with positions: pLeft and pRight. | |
| 632 @@ -1481,7 +1586,7 @@ static void posListPhraseMerge(DLReader *pLeft, DLReader *
pRight, | |
| 633 ** iType controls the type of data written to pOut. If iType is | |
| 634 ** DL_POSITIONS, the positions are those from pRight. | |
| 635 */ | |
| 636 -static void docListPhraseMerge( | |
| 637 +static int docListPhraseMerge( | |
| 638 const char *pLeft, int nLeft, | |
| 639 const char *pRight, int nRight, | |
| 640 DocListType iType, | |
| 641 @@ -1489,152 +1594,198 @@ static void docListPhraseMerge( | |
| 642 ){ | |
| 643 DLReader left, right; | |
| 644 DLWriter writer; | |
| 645 + int rc; | |
| 646 | |
| 647 - if( nLeft==0 || nRight==0 ) return; | |
| 648 + if( nLeft==0 || nRight==0 ) return SQLITE_OK; | |
| 649 | |
| 650 assert( iType!=DL_POSITIONS_OFFSETS ); | |
| 651 | |
| 652 - dlrInit(&left, DL_POSITIONS, pLeft, nLeft); | |
| 653 - dlrInit(&right, DL_POSITIONS, pRight, nRight); | |
| 654 + rc = dlrInit(&left, DL_POSITIONS, pLeft, nLeft); | |
| 655 + if( rc!=SQLITE_OK ) return rc; | |
| 656 + rc = dlrInit(&right, DL_POSITIONS, pRight, nRight); | |
| 657 + if( rc!=SQLITE_OK ){ | |
| 658 + dlrDestroy(&left); | |
| 659 + return rc; | |
| 660 + } | |
| 661 dlwInit(&writer, iType, pOut); | |
| 662 | |
| 663 while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ | |
| 664 if( dlrDocid(&left)<dlrDocid(&right) ){ | |
| 665 - dlrStep(&left); | |
| 666 + rc = dlrStep(&left); | |
| 667 + if( rc!=SQLITE_OK ) break; | |
| 668 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | |
| 669 - dlrStep(&right); | |
| 670 + rc = dlrStep(&right); | |
| 671 + if( rc!=SQLITE_OK ) break; | |
| 672 }else{ | |
| 673 - posListPhraseMerge(&left, &right, &writer); | |
| 674 - dlrStep(&left); | |
| 675 - dlrStep(&right); | |
| 676 + rc = posListPhraseMerge(&left, &right, &writer); | |
| 677 + if( rc!=SQLITE_OK ) break; | |
| 678 + rc = dlrStep(&left); | |
| 679 + if( rc!=SQLITE_OK ) break; | |
| 680 + rc = dlrStep(&right); | |
| 681 + if( rc!=SQLITE_OK ) break; | |
| 682 } | |
| 683 } | |
| 684 | |
| 685 dlrDestroy(&left); | |
| 686 dlrDestroy(&right); | |
| 687 dlwDestroy(&writer); | |
| 688 + return rc; | |
| 689 } | |
| 690 | |
| 691 /* We have two DL_DOCIDS doclists: pLeft and pRight. | |
| 692 ** Write the intersection of these two doclists into pOut as a | |
| 693 ** DL_DOCIDS doclist. | |
| 694 */ | |
| 695 -static void docListAndMerge( | |
| 696 +static int docListAndMerge( | |
| 697 const char *pLeft, int nLeft, | |
| 698 const char *pRight, int nRight, | |
| 699 DataBuffer *pOut /* Write the combined doclist here */ | |
| 700 ){ | |
| 701 DLReader left, right; | |
| 702 DLWriter writer; | |
| 703 + int rc; | |
| 704 | |
| 705 - if( nLeft==0 || nRight==0 ) return; | |
| 706 + if( nLeft==0 || nRight==0 ) return SQLITE_OK; | |
| 707 | |
| 708 - dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 709 - dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 710 + rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 711 + if( rc!=SQLITE_OK ) return rc; | |
| 712 + rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 713 + if( rc!=SQLITE_OK ){ | |
| 714 + dlrDestroy(&left); | |
| 715 + return rc; | |
| 716 + } | |
| 717 dlwInit(&writer, DL_DOCIDS, pOut); | |
| 718 | |
| 719 while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ | |
| 720 if( dlrDocid(&left)<dlrDocid(&right) ){ | |
| 721 - dlrStep(&left); | |
| 722 + rc = dlrStep(&left); | |
| 723 + if( rc!=SQLITE_OK ) break; | |
| 724 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | |
| 725 - dlrStep(&right); | |
| 726 + rc = dlrStep(&right); | |
| 727 + if( rc!=SQLITE_OK ) break; | |
| 728 }else{ | |
| 729 dlwAdd(&writer, dlrDocid(&left)); | |
| 730 - dlrStep(&left); | |
| 731 - dlrStep(&right); | |
| 732 + rc = dlrStep(&left); | |
| 733 + if( rc!=SQLITE_OK ) break; | |
| 734 + rc = dlrStep(&right); | |
| 735 + if( rc!=SQLITE_OK ) break; | |
| 736 } | |
| 737 } | |
| 738 | |
| 739 dlrDestroy(&left); | |
| 740 dlrDestroy(&right); | |
| 741 dlwDestroy(&writer); | |
| 742 + return rc; | |
| 743 } | |
| 744 | |
| 745 /* We have two DL_DOCIDS doclists: pLeft and pRight. | |
| 746 ** Write the union of these two doclists into pOut as a | |
| 747 ** DL_DOCIDS doclist. | |
| 748 */ | |
| 749 -static void docListOrMerge( | |
| 750 +static int docListOrMerge( | |
| 751 const char *pLeft, int nLeft, | |
| 752 const char *pRight, int nRight, | |
| 753 DataBuffer *pOut /* Write the combined doclist here */ | |
| 754 ){ | |
| 755 DLReader left, right; | |
| 756 DLWriter writer; | |
| 757 + int rc; | |
| 758 | |
| 759 if( nLeft==0 ){ | |
| 760 if( nRight!=0 ) dataBufferAppend(pOut, pRight, nRight); | |
| 761 - return; | |
| 762 + return SQLITE_OK; | |
| 763 } | |
| 764 if( nRight==0 ){ | |
| 765 dataBufferAppend(pOut, pLeft, nLeft); | |
| 766 - return; | |
| 767 + return SQLITE_OK; | |
| 768 } | |
| 769 | |
| 770 - dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 771 - dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 772 + rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 773 + if( rc!=SQLITE_OK ) return rc; | |
| 774 + rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 775 + if( rc!=SQLITE_OK ){ | |
| 776 + dlrDestroy(&left); | |
| 777 + return rc; | |
| 778 + } | |
| 779 dlwInit(&writer, DL_DOCIDS, pOut); | |
| 780 | |
| 781 while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ | |
| 782 if( dlrAtEnd(&right) ){ | |
| 783 dlwAdd(&writer, dlrDocid(&left)); | |
| 784 - dlrStep(&left); | |
| 785 + rc = dlrStep(&left); | |
| 786 + if( rc!=SQLITE_OK ) break; | |
| 787 }else if( dlrAtEnd(&left) ){ | |
| 788 dlwAdd(&writer, dlrDocid(&right)); | |
| 789 - dlrStep(&right); | |
| 790 + rc = dlrStep(&right); | |
| 791 + if( rc!=SQLITE_OK ) break; | |
| 792 }else if( dlrDocid(&left)<dlrDocid(&right) ){ | |
| 793 dlwAdd(&writer, dlrDocid(&left)); | |
| 794 - dlrStep(&left); | |
| 795 + rc = dlrStep(&left); | |
| 796 + if( rc!=SQLITE_OK ) break; | |
| 797 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | |
| 798 dlwAdd(&writer, dlrDocid(&right)); | |
| 799 - dlrStep(&right); | |
| 800 + rc = dlrStep(&right); | |
| 801 + if( rc!=SQLITE_OK ) break; | |
| 802 }else{ | |
| 803 dlwAdd(&writer, dlrDocid(&left)); | |
| 804 - dlrStep(&left); | |
| 805 - dlrStep(&right); | |
| 806 + rc = dlrStep(&left); | |
| 807 + if( rc!=SQLITE_OK ) break; | |
| 808 + rc = dlrStep(&right); | |
| 809 + if( rc!=SQLITE_OK ) break; | |
| 810 } | |
| 811 } | |
| 812 | |
| 813 dlrDestroy(&left); | |
| 814 dlrDestroy(&right); | |
| 815 dlwDestroy(&writer); | |
| 816 + return rc; | |
| 817 } | |
| 818 | |
| 819 /* We have two DL_DOCIDS doclists: pLeft and pRight. | |
| 820 ** Write into pOut as DL_DOCIDS doclist containing all documents that | |
| 821 ** occur in pLeft but not in pRight. | |
| 822 */ | |
| 823 -static void docListExceptMerge( | |
| 824 +static int docListExceptMerge( | |
| 825 const char *pLeft, int nLeft, | |
| 826 const char *pRight, int nRight, | |
| 827 DataBuffer *pOut /* Write the combined doclist here */ | |
| 828 ){ | |
| 829 DLReader left, right; | |
| 830 DLWriter writer; | |
| 831 + int rc; | |
| 832 | |
| 833 - if( nLeft==0 ) return; | |
| 834 + if( nLeft==0 ) return SQLITE_OK; | |
| 835 if( nRight==0 ){ | |
| 836 dataBufferAppend(pOut, pLeft, nLeft); | |
| 837 - return; | |
| 838 + return SQLITE_OK; | |
| 839 } | |
| 840 | |
| 841 - dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 842 - dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 843 + rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 844 + if( rc!=SQLITE_OK ) return rc; | |
| 845 + rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 846 + if( rc!=SQLITE_OK ){ | |
| 847 + dlrDestroy(&left); | |
| 848 + return rc; | |
| 849 + } | |
| 850 dlwInit(&writer, DL_DOCIDS, pOut); | |
| 851 | |
| 852 while( !dlrAtEnd(&left) ){ | |
| 853 while( !dlrAtEnd(&right) && dlrDocid(&right)<dlrDocid(&left) ){ | |
| 854 - dlrStep(&right); | |
| 855 + rc = dlrStep(&right); | |
| 856 + if( rc!=SQLITE_OK ) goto err; | |
| 857 } | |
| 858 if( dlrAtEnd(&right) || dlrDocid(&left)<dlrDocid(&right) ){ | |
| 859 dlwAdd(&writer, dlrDocid(&left)); | |
| 860 } | |
| 861 - dlrStep(&left); | |
| 862 + rc = dlrStep(&left); | |
| 863 + if( rc!=SQLITE_OK ) break; | |
| 864 } | |
| 865 | |
| 866 +err: | |
| 867 dlrDestroy(&left); | |
| 868 dlrDestroy(&right); | |
| 869 dlwDestroy(&writer); | |
| 870 + return rc; | |
| 871 } | |
| 872 | |
| 873 static char *string_dup_n(const char *s, int n){ | |
| 874 @@ -3437,7 +3588,8 @@ static int fulltextNext(sqlite3_vtab_cursor *pCursor){ | |
| 875 return SQLITE_OK; | |
| 876 } | |
| 877 rc = sqlite3_bind_int64(c->pStmt, 1, dlrDocid(&c->reader)); | |
| 878 - dlrStep(&c->reader); | |
| 879 + if( rc!=SQLITE_OK ) return rc; | |
| 880 + rc = dlrStep(&c->reader); | |
| 881 if( rc!=SQLITE_OK ) return rc; | |
| 882 /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ | |
| 883 rc = sqlite3_step(c->pStmt); | |
| 884 @@ -3497,14 +3649,18 @@ static int docListOfTerm( | |
| 885 return rc; | |
| 886 } | |
| 887 dataBufferInit(&new, 0); | |
| 888 - docListPhraseMerge(left.pData, left.nData, right.pData, right.nData, | |
| 889 - i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &new); | |
| 890 + rc = docListPhraseMerge(left.pData, left.nData, right.pData, right.nData, | |
| 891 + i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &new)
; | |
| 892 dataBufferDestroy(&left); | |
| 893 dataBufferDestroy(&right); | |
| 894 + if( rc!=SQLITE_OK ){ | |
| 895 + dataBufferDestroy(&new); | |
| 896 + return rc; | |
| 897 + } | |
| 898 left = new; | |
| 899 } | |
| 900 *pResult = left; | |
| 901 - return SQLITE_OK; | |
| 902 + return rc; | |
| 903 } | |
| 904 | |
| 905 /* Add a new term pTerm[0..nTerm-1] to the query *q. | |
| 906 @@ -3749,18 +3905,30 @@ static int fulltextQuery( | |
| 907 return rc; | |
| 908 } | |
| 909 dataBufferInit(&new, 0); | |
| 910 - docListOrMerge(right.pData, right.nData, or.pData, or.nData, &new); | |
| 911 + rc = docListOrMerge(right.pData, right.nData, or.pData, or.nData, &new); | |
| 912 dataBufferDestroy(&right); | |
| 913 dataBufferDestroy(&or); | |
| 914 + if( rc!=SQLITE_OK ){ | |
| 915 + if( i!=nNot ) dataBufferDestroy(&left); | |
| 916 + queryClear(pQuery); | |
| 917 + dataBufferDestroy(&new); | |
| 918 + return rc; | |
| 919 + } | |
| 920 right = new; | |
| 921 } | |
| 922 if( i==nNot ){ /* first term processed. */ | |
| 923 left = right; | |
| 924 }else{ | |
| 925 dataBufferInit(&new, 0); | |
| 926 - docListAndMerge(left.pData, left.nData, right.pData, right.nData, &new); | |
| 927 + rc = docListAndMerge(left.pData, left.nData, | |
| 928 + right.pData, right.nData, &new); | |
| 929 dataBufferDestroy(&right); | |
| 930 dataBufferDestroy(&left); | |
| 931 + if( rc!=SQLITE_OK ){ | |
| 932 + queryClear(pQuery); | |
| 933 + dataBufferDestroy(&new); | |
| 934 + return rc; | |
| 935 + } | |
| 936 left = new; | |
| 937 } | |
| 938 } | |
| 939 @@ -3780,9 +3948,15 @@ static int fulltextQuery( | |
| 940 return rc; | |
| 941 } | |
| 942 dataBufferInit(&new, 0); | |
| 943 - docListExceptMerge(left.pData, left.nData, right.pData, right.nData, &new); | |
| 944 + rc = docListExceptMerge(left.pData, left.nData, | |
| 945 + right.pData, right.nData, &new); | |
| 946 dataBufferDestroy(&right); | |
| 947 dataBufferDestroy(&left); | |
| 948 + if( rc!=SQLITE_OK ){ | |
| 949 + queryClear(pQuery); | |
| 950 + dataBufferDestroy(&new); | |
| 951 + return rc; | |
| 952 + } | |
| 953 left = new; | |
| 954 } | |
| 955 | |
| 956 @@ -3876,7 +4050,8 @@ static int fulltextFilter( | |
| 957 rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &c->result, &c->
q); | |
| 958 if( rc!=SQLITE_OK ) return rc; | |
| 959 if( c->result.nData!=0 ){ | |
| 960 - dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData); | |
| 961 + rc = dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData); | |
| 962 + if( rc!=SQLITE_OK ) return rc; | |
| 963 } | |
| 964 break; | |
| 965 } | |
| 966 @@ -4377,22 +4552,19 @@ static void interiorReaderDestroy(InteriorReader *pReade
r){ | |
| 967 SCRAMBLE(pReader); | |
| 968 } | |
| 969 | |
| 970 -/* TODO(shess) The assertions are great, but what if we're in NDEBUG | |
| 971 -** and the blob is empty or otherwise contains suspect data? | |
| 972 -*/ | |
| 973 -static void interiorReaderInit(const char *pData, int nData, | |
| 974 - InteriorReader *pReader){ | |
| 975 +static int interiorReaderInit(const char *pData, int nData, | |
| 976 + InteriorReader *pReader){ | |
| 977 int n, nTerm; | |
| 978 | |
| 979 - /* Require at least the leading flag byte */ | |
| 980 + /* These conditions are checked and met by the callers. */ | |
| 981 assert( nData>0 ); | |
| 982 assert( pData[0]!='\0' ); | |
| 983 | |
| 984 CLEAR(pReader); | |
| 985 | |
| 986 /* Decode the base blockid, and set the cursor to the first term. */ | |
| 987 - n = getVarint(pData+1, &pReader->iBlockid); | |
| 988 - assert( 1+n<=nData ); | |
| 989 + n = getVarintSafe(pData+1, &pReader->iBlockid, nData-1); | |
| 990 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 991 pReader->pData = pData+1+n; | |
| 992 pReader->nData = nData-(1+n); | |
| 993 | |
| 994 @@ -4403,17 +4575,18 @@ static void interiorReaderInit(const char *pData, int nD
ata, | |
| 995 if( pReader->nData==0 ){ | |
| 996 dataBufferInit(&pReader->term, 0); | |
| 997 }else{ | |
| 998 - n = getVarint32(pReader->pData, &nTerm); | |
| 999 + n = getVarint32Safe(pReader->pData, &nTerm, pReader->nData); | |
| 1000 + if( !n || nTerm<0 || nTerm>pReader->nData-n) return SQLITE_CORRUPT_BKPT; | |
| 1001 dataBufferInit(&pReader->term, nTerm); | |
| 1002 dataBufferReplace(&pReader->term, pReader->pData+n, nTerm); | |
| 1003 - assert( n+nTerm<=pReader->nData ); | |
| 1004 pReader->pData += n+nTerm; | |
| 1005 pReader->nData -= n+nTerm; | |
| 1006 } | |
| 1007 + return SQLITE_OK; | |
| 1008 } | |
| 1009 | |
| 1010 static int interiorReaderAtEnd(InteriorReader *pReader){ | |
| 1011 - return pReader->term.nData==0; | |
| 1012 + return pReader->term.nData<=0; | |
| 1013 } | |
| 1014 | |
| 1015 static sqlite_int64 interiorReaderCurrentBlockid(InteriorReader *pReader){ | |
| 1016 @@ -4430,7 +4603,7 @@ static const char *interiorReaderTerm(InteriorReader *pRea
der){ | |
| 1017 } | |
| 1018 | |
| 1019 /* Step forward to the next term in the node. */ | |
| 1020 -static void interiorReaderStep(InteriorReader *pReader){ | |
| 1021 +static int interiorReaderStep(InteriorReader *pReader){ | |
| 1022 assert( !interiorReaderAtEnd(pReader) ); | |
| 1023 | |
| 1024 /* If the last term has been read, signal eof, else construct the | |
| 1025 @@ -4441,18 +4614,26 @@ static void interiorReaderStep(InteriorReader *pReader){ | |
| 1026 }else{ | |
| 1027 int n, nPrefix, nSuffix; | |
| 1028 | |
| 1029 - n = getVarint32(pReader->pData, &nPrefix); | |
| 1030 - n += getVarint32(pReader->pData+n, &nSuffix); | |
| 1031 + n = getVarint32Safe(pReader->pData, &nPrefix, pReader->nData); | |
| 1032 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 1033 + pReader->nData -= n; | |
| 1034 + pReader->pData += n; | |
| 1035 + n = getVarint32Safe(pReader->pData, &nSuffix, pReader->nData); | |
| 1036 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 1037 + pReader->nData -= n; | |
| 1038 + pReader->pData += n; | |
| 1039 + if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT; | |
| 1040 + if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT; | |
| 1041 | |
| 1042 /* Truncate the current term and append suffix data. */ | |
| 1043 pReader->term.nData = nPrefix; | |
| 1044 - dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); | |
| 1045 + dataBufferAppend(&pReader->term, pReader->pData, nSuffix); | |
| 1046 | |
| 1047 - assert( n+nSuffix<=pReader->nData ); | |
| 1048 - pReader->pData += n+nSuffix; | |
| 1049 - pReader->nData -= n+nSuffix; | |
| 1050 + pReader->pData += nSuffix; | |
| 1051 + pReader->nData -= nSuffix; | |
| 1052 } | |
| 1053 pReader->iBlockid++; | |
| 1054 + return SQLITE_OK; | |
| 1055 } | |
| 1056 | |
| 1057 /* Compare the current term to pTerm[nTerm], returning strcmp-style | |
| 1058 @@ -4824,7 +5005,8 @@ static int leafWriterStepMerge(fulltext_vtab *v, LeafWrite
r *pWriter, | |
| 1059 n = putVarint(c, nData); | |
| 1060 dataBufferAppend(&pWriter->data, c, n); | |
| 1061 | |
| 1062 - docListMerge(&pWriter->data, pReaders, nReaders); | |
| 1063 + rc = docListMerge(&pWriter->data, pReaders, nReaders); | |
| 1064 + if( rc!= SQLITE_OK ) return rc; | |
| 1065 ASSERT_VALID_DOCLIST(DL_DEFAULT, | |
| 1066 pWriter->data.pData+iDoclistData+n, | |
| 1067 pWriter->data.nData-iDoclistData-n, NULL); | |
| 1068 @@ -4934,7 +5116,8 @@ static int leafWriterStep(fulltext_vtab *v, LeafWriter *pW
riter, | |
| 1069 int rc; | |
| 1070 DLReader reader; | |
| 1071 | |
| 1072 - dlrInit(&reader, DL_DEFAULT, pData, nData); | |
| 1073 + rc = dlrInit(&reader, DL_DEFAULT, pData, nData); | |
| 1074 + if( rc!=SQLITE_OK ) return rc; | |
| 1075 rc = leafWriterStepMerge(v, pWriter, pTerm, nTerm, &reader, 1); | |
| 1076 dlrDestroy(&reader); | |
| 1077 | |
| 1078 @@ -4979,38 +5162,40 @@ static int leafReaderDataBytes(LeafReader *pReader){ | |
| 1079 static const char *leafReaderData(LeafReader *pReader){ | |
| 1080 int n, nData; | |
| 1081 assert( pReader->term.nData>0 ); | |
| 1082 - n = getVarint32(pReader->pData, &nData); | |
| 1083 + n = getVarint32Safe(pReader->pData, &nData, pReader->nData); | |
| 1084 + if( !n || nData>pReader->nData-n ) return NULL; | |
| 1085 return pReader->pData+n; | |
| 1086 } | |
| 1087 | |
| 1088 -static void leafReaderInit(const char *pData, int nData, | |
| 1089 - LeafReader *pReader){ | |
| 1090 +static int leafReaderInit(const char *pData, int nData, LeafReader *pReader){ | |
| 1091 int nTerm, n; | |
| 1092 | |
| 1093 + /* All callers check this precondition. */ | |
| 1094 assert( nData>0 ); | |
| 1095 assert( pData[0]=='\0' ); | |
| 1096 | |
| 1097 CLEAR(pReader); | |
| 1098 | |
| 1099 /* Read the first term, skipping the header byte. */ | |
| 1100 - n = getVarint32(pData+1, &nTerm); | |
| 1101 + n = getVarint32Safe(pData+1, &nTerm, nData-1); | |
| 1102 + if( !n || nTerm<0 || nTerm>nData-1-n ) return SQLITE_CORRUPT_BKPT; | |
| 1103 dataBufferInit(&pReader->term, nTerm); | |
| 1104 dataBufferReplace(&pReader->term, pData+1+n, nTerm); | |
| 1105 | |
| 1106 /* Position after the first term. */ | |
| 1107 - assert( 1+n+nTerm<nData ); | |
| 1108 pReader->pData = pData+1+n+nTerm; | |
| 1109 pReader->nData = nData-1-n-nTerm; | |
| 1110 + return SQLITE_OK; | |
| 1111 } | |
| 1112 | |
| 1113 /* Step the reader forward to the next term. */ | |
| 1114 -static void leafReaderStep(LeafReader *pReader){ | |
| 1115 +static int leafReaderStep(LeafReader *pReader){ | |
| 1116 int n, nData, nPrefix, nSuffix; | |
| 1117 assert( !leafReaderAtEnd(pReader) ); | |
| 1118 | |
| 1119 /* Skip previous entry's data block. */ | |
| 1120 - n = getVarint32(pReader->pData, &nData); | |
| 1121 - assert( n+nData<=pReader->nData ); | |
| 1122 + n = getVarint32Safe(pReader->pData, &nData, pReader->nData); | |
| 1123 + if( !n || nData<0 || nData>pReader->nData-n ) return SQLITE_CORRUPT_BKPT; | |
| 1124 pReader->pData += n+nData; | |
| 1125 pReader->nData -= n+nData; | |
| 1126 | |
| 1127 @@ -5018,15 +5203,23 @@ static void leafReaderStep(LeafReader *pReader){ | |
| 1128 /* Construct the new term using a prefix from the old term plus a | |
| 1129 ** suffix from the leaf data. | |
| 1130 */ | |
| 1131 - n = getVarint32(pReader->pData, &nPrefix); | |
| 1132 - n += getVarint32(pReader->pData+n, &nSuffix); | |
| 1133 - assert( n+nSuffix<pReader->nData ); | |
| 1134 + n = getVarint32Safe(pReader->pData, &nPrefix, pReader->nData); | |
| 1135 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 1136 + pReader->nData -= n; | |
| 1137 + pReader->pData += n; | |
| 1138 + n = getVarint32Safe(pReader->pData, &nSuffix, pReader->nData); | |
| 1139 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 1140 + pReader->nData -= n; | |
| 1141 + pReader->pData += n; | |
| 1142 + if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT; | |
| 1143 + if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT; | |
| 1144 pReader->term.nData = nPrefix; | |
| 1145 - dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); | |
| 1146 + dataBufferAppend(&pReader->term, pReader->pData, nSuffix); | |
| 1147 | |
| 1148 - pReader->pData += n+nSuffix; | |
| 1149 - pReader->nData -= n+nSuffix; | |
| 1150 + pReader->pData += nSuffix; | |
| 1151 + pReader->nData -= nSuffix; | |
| 1152 } | |
| 1153 + return SQLITE_OK; | |
| 1154 } | |
| 1155 | |
| 1156 /* strcmp-style comparison of pReader's current term against pTerm. | |
| 1157 @@ -5133,14 +5326,19 @@ static int leavesReaderInit(fulltext_vtab *v, | |
| 1158 | |
| 1159 dataBufferInit(&pReader->rootData, 0); | |
| 1160 if( iStartBlockid==0 ){ | |
| 1161 + int rc; | |
| 1162 /* Corrupt if this can't be a leaf node. */ | |
| 1163 if( pRootData==NULL || nRootData<1 || pRootData[0]!='\0' ){ | |
| 1164 return SQLITE_CORRUPT_BKPT; | |
| 1165 } | |
| 1166 /* Entire leaf level fit in root data. */ | |
| 1167 dataBufferReplace(&pReader->rootData, pRootData, nRootData); | |
| 1168 - leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, | |
| 1169 - &pReader->leafReader); | |
| 1170 + rc = leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, | |
| 1171 + &pReader->leafReader); | |
| 1172 + if( rc!=SQLITE_OK ){ | |
| 1173 + dataBufferDestroy(&pReader->rootData); | |
| 1174 + return rc; | |
| 1175 + } | |
| 1176 }else{ | |
| 1177 sqlite3_stmt *s; | |
| 1178 int rc = sql_get_leaf_statement(v, idx, &s); | |
| 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 } | |
| 1187 | |
| 1188 @@ -5197,11 +5395,12 @@ static int leavesReaderInit(fulltext_vtab *v, | |
| 1189 ** end of the current leaf, step forward to the next leaf block. | |
| 1190 */ | |
| 1191 static int leavesReaderStep(fulltext_vtab *v, LeavesReader *pReader){ | |
| 1192 + int rc; | |
| 1193 assert( !leavesReaderAtEnd(pReader) ); | |
| 1194 - leafReaderStep(&pReader->leafReader); | |
| 1195 + rc = leafReaderStep(&pReader->leafReader); | |
| 1196 + if( rc!=SQLITE_OK ) return rc; | |
| 1197 | |
| 1198 if( leafReaderAtEnd(&pReader->leafReader) ){ | |
| 1199 - int rc; | |
| 1200 if( pReader->rootData.pData ){ | |
| 1201 pReader->eof = 1; | |
| 1202 return SQLITE_OK; | |
| 1203 @@ -5216,6 +5415,7 @@ static int leavesReaderStep(fulltext_vtab *v, LeavesReader
*pReader){ | |
| 1204 if( sqlite3_column_type(pReader->pStmt, 0)!=SQLITE_BLOB ){ | |
| 1205 return SQLITE_CORRUPT_BKPT; | |
| 1206 }else{ | |
| 1207 + LeafReader tmp; | |
| 1208 const char *pLeafData = sqlite3_column_blob(pReader->pStmt, 0); | |
| 1209 int nLeafData = sqlite3_column_bytes(pReader->pStmt, 0); | |
| 1210 | |
| 1211 @@ -5224,8 +5424,10 @@ static int leavesReaderStep(fulltext_vtab *v, LeavesReade
r *pReader){ | |
| 1212 return SQLITE_CORRUPT_BKPT; | |
| 1213 } | |
| 1214 | |
| 1215 + rc = leafReaderInit(pLeafData, nLeafData, &tmp); | |
| 1216 + if( rc!=SQLITE_OK ) return rc; | |
| 1217 leafReaderDestroy(&pReader->leafReader); | |
| 1218 - leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); | |
| 1219 + pReader->leafReader = tmp; | |
| 1220 } | |
| 1221 } | |
| 1222 return SQLITE_OK; | |
| 1223 @@ -5334,13 +5536,26 @@ static int leavesReadersMerge(fulltext_vtab *v, | |
| 1224 DLReader dlReaders[MERGE_COUNT]; | |
| 1225 const char *pTerm = leavesReaderTerm(pReaders); | |
| 1226 int i, nTerm = leavesReaderTermBytes(pReaders); | |
| 1227 + int rc; | |
| 1228 | |
| 1229 assert( nReaders<=MERGE_COUNT ); | |
| 1230 | |
| 1231 for(i=0; i<nReaders; i++){ | |
| 1232 - dlrInit(&dlReaders[i], DL_DEFAULT, | |
| 1233 - leavesReaderData(pReaders+i), | |
| 1234 - leavesReaderDataBytes(pReaders+i)); | |
| 1235 + const char *pData = leavesReaderData(pReaders+i); | |
| 1236 + if( pData==NULL ){ | |
| 1237 + rc = SQLITE_CORRUPT_BKPT; | |
| 1238 + break; | |
| 1239 + } | |
| 1240 + rc = dlrInit(&dlReaders[i], DL_DEFAULT, | |
| 1241 + pData, | |
| 1242 + leavesReaderDataBytes(pReaders+i)); | |
| 1243 + if( rc!=SQLITE_OK ) break; | |
| 1244 + } | |
| 1245 + if( rc!=SQLITE_OK ){ | |
| 1246 + while( i-->0 ){ | |
| 1247 + dlrDestroy(&dlReaders[i]); | |
| 1248 + } | |
| 1249 + return rc; | |
| 1250 } | |
| 1251 | |
| 1252 return leafWriterStepMerge(v, pWriter, pTerm, nTerm, dlReaders, nReaders); | |
| 1253 @@ -5444,12 +5659,14 @@ static int segmentMerge(fulltext_vtab *v, int iLevel){ | |
| 1254 } | |
| 1255 | |
| 1256 /* Accumulate the union of *acc and *pData into *acc. */ | |
| 1257 -static void docListAccumulateUnion(DataBuffer *acc, | |
| 1258 - const char *pData, int nData) { | |
| 1259 +static int docListAccumulateUnion(DataBuffer *acc, | |
| 1260 + const char *pData, int nData) { | |
| 1261 DataBuffer tmp = *acc; | |
| 1262 + int rc; | |
| 1263 dataBufferInit(acc, tmp.nData+nData); | |
| 1264 - docListUnion(tmp.pData, tmp.nData, pData, nData, acc); | |
| 1265 + rc = docListUnion(tmp.pData, tmp.nData, pData, nData, acc); | |
| 1266 dataBufferDestroy(&tmp); | |
| 1267 + return rc; | |
| 1268 } | |
| 1269 | |
| 1270 /* TODO(shess) It might be interesting to explore different merge | |
| 1271 @@ -5491,8 +5708,13 @@ static int loadSegmentLeavesInt(fulltext_vtab *v, LeavesR
eader *pReader, | |
| 1272 int c = leafReaderTermCmp(&pReader->leafReader, pTerm, nTerm, isPrefix); | |
| 1273 if( c>0 ) break; /* Past any possible matches. */ | |
| 1274 if( c==0 ){ | |
| 1275 + int iBuffer, nData; | |
| 1276 const char *pData = leavesReaderData(pReader); | |
| 1277 - int iBuffer, nData = leavesReaderDataBytes(pReader); | |
| 1278 + if( pData==NULL ){ | |
| 1279 + rc = SQLITE_CORRUPT_BKPT; | |
| 1280 + break; | |
| 1281 + } | |
| 1282 + nData = leavesReaderDataBytes(pReader); | |
| 1283 | |
| 1284 /* Find the first empty buffer. */ | |
| 1285 for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){ | |
| 1286 @@ -5538,11 +5760,13 @@ static int loadSegmentLeavesInt(fulltext_vtab *v, Leaves
Reader *pReader, | |
| 1287 ** with pData/nData. | |
| 1288 */ | |
| 1289 dataBufferSwap(p, pAcc); | |
| 1290 - docListAccumulateUnion(pAcc, pData, nData); | |
| 1291 + rc = docListAccumulateUnion(pAcc, pData, nData); | |
| 1292 + if( rc!=SQLITE_OK ) goto err; | |
| 1293 | |
| 1294 /* Accumulate remaining doclists into pAcc. */ | |
| 1295 for(++p; p<pAcc; ++p){ | |
| 1296 - docListAccumulateUnion(pAcc, p->pData, p->nData); | |
| 1297 + rc = docListAccumulateUnion(pAcc, p->pData, p->nData); | |
| 1298 + if( rc!=SQLITE_OK ) goto err; | |
| 1299 | |
| 1300 /* dataBufferReset() could allow a large doclist to blow up | |
| 1301 ** our memory requirements. | |
| 1302 @@ -5567,13 +5791,15 @@ static int loadSegmentLeavesInt(fulltext_vtab *v, Leaves
Reader *pReader, | |
| 1303 if( out->nData==0 ){ | |
| 1304 dataBufferSwap(out, &(pBuffers[iBuffer])); | |
| 1305 }else{ | |
| 1306 - docListAccumulateUnion(out, pBuffers[iBuffer].pData, | |
| 1307 - pBuffers[iBuffer].nData); | |
| 1308 + rc = docListAccumulateUnion(out, pBuffers[iBuffer].pData, | |
| 1309 + pBuffers[iBuffer].nData); | |
| 1310 + if( rc!=SQLITE_OK ) break; | |
| 1311 } | |
| 1312 } | |
| 1313 } | |
| 1314 } | |
| 1315 | |
| 1316 +err: | |
| 1317 while( nBuffers-- ){ | |
| 1318 dataBufferDestroy(&(pBuffers[nBuffers])); | |
| 1319 } | |
| 1320 @@ -5632,20 +5858,26 @@ static int loadSegmentLeaves(fulltext_vtab *v, | |
| 1321 ** node. Consider whether breaking symmetry is worthwhile. I suspect | |
| 1322 ** it is not worthwhile. | |
| 1323 */ | |
| 1324 -static void getChildrenContaining(const char *pData, int nData, | |
| 1325 - const char *pTerm, int nTerm, int isPrefix, | |
| 1326 - sqlite_int64 *piStartChild, | |
| 1327 - sqlite_int64 *piEndChild){ | |
| 1328 +static int getChildrenContaining(const char *pData, int nData, | |
| 1329 + const char *pTerm, int nTerm, int isPrefix, | |
| 1330 + sqlite_int64 *piStartChild, | |
| 1331 + sqlite_int64 *piEndChild){ | |
| 1332 InteriorReader reader; | |
| 1333 + int rc; | |
| 1334 | |
| 1335 assert( nData>1 ); | |
| 1336 assert( *pData!='\0' ); | |
| 1337 - interiorReaderInit(pData, nData, &reader); | |
| 1338 + rc = interiorReaderInit(pData, nData, &reader); | |
| 1339 + if( rc!=SQLITE_OK ) return rc; | |
| 1340 | |
| 1341 /* Scan for the first child which could contain pTerm/nTerm. */ | |
| 1342 while( !interiorReaderAtEnd(&reader) ){ | |
| 1343 if( interiorReaderTermCmp(&reader, pTerm, nTerm, 0)>0 ) break; | |
| 1344 - interiorReaderStep(&reader); | |
| 1345 + rc = interiorReaderStep(&reader); | |
| 1346 + if( rc!=SQLITE_OK ){ | |
| 1347 + interiorReaderDestroy(&reader); | |
| 1348 + return rc; | |
| 1349 + } | |
| 1350 } | |
| 1351 *piStartChild = interiorReaderCurrentBlockid(&reader); | |
| 1352 | |
| 1353 @@ -5655,7 +5887,11 @@ static void getChildrenContaining(const char *pData, int
nData, | |
| 1354 */ | |
| 1355 while( !interiorReaderAtEnd(&reader) ){ | |
| 1356 if( interiorReaderTermCmp(&reader, pTerm, nTerm, isPrefix)>0 ) break; | |
| 1357 - interiorReaderStep(&reader); | |
| 1358 + rc = interiorReaderStep(&reader); | |
| 1359 + if( rc!=SQLITE_OK ){ | |
| 1360 + interiorReaderDestroy(&reader); | |
| 1361 + return rc; | |
| 1362 + } | |
| 1363 } | |
| 1364 *piEndChild = interiorReaderCurrentBlockid(&reader); | |
| 1365 | |
| 1366 @@ -5664,6 +5900,7 @@ static void getChildrenContaining(const char *pData, int n
Data, | |
| 1367 /* Children must ascend, and if !prefix, both must be the same. */ | |
| 1368 assert( *piEndChild>=*piStartChild ); | |
| 1369 assert( isPrefix || *piStartChild==*piEndChild ); | |
| 1370 + return rc; | |
| 1371 } | |
| 1372 | |
| 1373 /* Read block at iBlockid and pass it with other params to | |
| 1374 @@ -5709,8 +5946,12 @@ static int loadAndGetChildrenContaining( | |
| 1375 return SQLITE_CORRUPT_BKPT; | |
| 1376 } | |
| 1377 | |
| 1378 - getChildrenContaining(pData, nData, pTerm, nTerm, | |
| 1379 - isPrefix, piStartChild, piEndChild); | |
| 1380 + rc = getChildrenContaining(pData, nData, pTerm, nTerm, | |
| 1381 + isPrefix, piStartChild, piEndChild); | |
| 1382 + if( rc!=SQLITE_OK ){ | |
| 1383 + sqlite3_reset(s); | |
| 1384 + return rc; | |
| 1385 + } | |
| 1386 } | |
| 1387 | |
| 1388 /* We expect only one row. We must execute another sqlite3_step() | |
| 1389 @@ -5741,8 +5982,9 @@ static int loadSegmentInt(fulltext_vtab *v, const char *pD
ata, int nData, | |
| 1390 /* Process pData as an interior node, then loop down the tree | |
| 1391 ** until we find the set of leaf nodes to scan for the term. | |
| 1392 */ | |
| 1393 - getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, | |
| 1394 - &iStartChild, &iEndChild); | |
| 1395 + rc = getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, | |
| 1396 + &iStartChild, &iEndChild); | |
| 1397 + if( rc!=SQLITE_OK ) return rc; | |
| 1398 while( iStartChild>iLeavesEnd ){ | |
| 1399 sqlite_int64 iNextStart, iNextEnd; | |
| 1400 rc = loadAndGetChildrenContaining(v, iStartChild, pTerm, nTerm, isPrefix, | |
| 1401 @@ -5812,16 +6054,21 @@ static int loadSegment(fulltext_vtab *v, const char *pDa
ta, int nData, | |
| 1402 DataBuffer merged; | |
| 1403 DLReader readers[2]; | |
| 1404 | |
| 1405 - dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); | |
| 1406 - dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); | |
| 1407 - dataBufferInit(&merged, out->nData+result.nData); | |
| 1408 - docListMerge(&merged, readers, 2); | |
| 1409 - dataBufferDestroy(out); | |
| 1410 - *out = merged; | |
| 1411 - dlrDestroy(&readers[0]); | |
| 1412 - dlrDestroy(&readers[1]); | |
| 1413 + rc = dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); | |
| 1414 + if( rc==SQLITE_OK ){ | |
| 1415 + rc = dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); | |
| 1416 + if( rc==SQLITE_OK ){ | |
| 1417 + dataBufferInit(&merged, out->nData+result.nData); | |
| 1418 + rc = docListMerge(&merged, readers, 2); | |
| 1419 + dataBufferDestroy(out); | |
| 1420 + *out = merged; | |
| 1421 + dlrDestroy(&readers[1]); | |
| 1422 + } | |
| 1423 + dlrDestroy(&readers[0]); | |
| 1424 + } | |
| 1425 } | |
| 1426 } | |
| 1427 + | |
| 1428 dataBufferDestroy(&result); | |
| 1429 return rc; | |
| 1430 } | |
| 1431 @@ -5862,6 +6109,7 @@ static int termSelect(fulltext_vtab *v, int iColumn, | |
| 1432 if( rc!=SQLITE_OK ) goto err; | |
| 1433 } | |
| 1434 if( rc==SQLITE_DONE ){ | |
| 1435 + rc = SQLITE_OK; | |
| 1436 if( doclist.nData!=0 ){ | |
| 1437 /* TODO(shess) The old term_select_all() code applied the column | |
| 1438 ** restrict as we merged segments, leading to smaller buffers. | |
| 1439 @@ -5869,10 +6117,9 @@ static int termSelect(fulltext_vtab *v, int iColumn, | |
| 1440 ** system is checked in. | |
| 1441 */ | |
| 1442 if( iColumn==v->nColumn) iColumn = -1; | |
| 1443 - docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
| 1444 - iColumn, iType, out); | |
| 1445 + rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
| 1446 + iColumn, iType, out); | |
| 1447 } | |
| 1448 - rc = SQLITE_OK; | |
| 1449 } | |
| 1450 | |
| 1451 err: | |
| 1452 @@ -6218,6 +6465,7 @@ static int optimizeInternal(fulltext_vtab *v, | |
| 1453 LeafWriter *pWriter){ | |
| 1454 int i, rc = SQLITE_OK; | |
| 1455 DataBuffer doclist, merged, tmp; | |
| 1456 + const char *pData; | |
| 1457 | |
| 1458 /* Order the readers. */ | |
| 1459 i = nReaders; | |
| 1460 @@ -6238,14 +6486,21 @@ static int optimizeInternal(fulltext_vtab *v, | |
| 1461 if( 0!=optLeavesReaderTermCmp(&readers[0], &readers[i]) ) break; | |
| 1462 } | |
| 1463 | |
| 1464 + pData = optLeavesReaderData(&readers[0]); | |
| 1465 + if( pData==NULL ){ | |
| 1466 + rc = SQLITE_CORRUPT_BKPT; | |
| 1467 + break; | |
| 1468 + } | |
| 1469 + | |
| 1470 /* Special-case for no merge. */ | |
| 1471 if( i==1 ){ | |
| 1472 /* Trim deletions from the doclist. */ | |
| 1473 dataBufferReset(&merged); | |
| 1474 - docListTrim(DL_DEFAULT, | |
| 1475 - optLeavesReaderData(&readers[0]), | |
| 1476 - optLeavesReaderDataBytes(&readers[0]), | |
| 1477 - -1, DL_DEFAULT, &merged); | |
| 1478 + rc = docListTrim(DL_DEFAULT, | |
| 1479 + pData, | |
| 1480 + optLeavesReaderDataBytes(&readers[0]), | |
| 1481 + -1, DL_DEFAULT, &merged); | |
| 1482 + if( rc!= SQLITE_OK ) break; | |
| 1483 }else{ | |
| 1484 DLReader dlReaders[MERGE_COUNT]; | |
| 1485 int iReader, nReaders; | |
| 1486 @@ -6253,9 +6508,10 @@ static int optimizeInternal(fulltext_vtab *v, | |
| 1487 /* Prime the pipeline with the first reader's doclist. After | |
| 1488 ** one pass index 0 will reference the accumulated doclist. | |
| 1489 */ | |
| 1490 - dlrInit(&dlReaders[0], DL_DEFAULT, | |
| 1491 - optLeavesReaderData(&readers[0]), | |
| 1492 - optLeavesReaderDataBytes(&readers[0])); | |
| 1493 + rc = dlrInit(&dlReaders[0], DL_DEFAULT, | |
| 1494 + pData, | |
| 1495 + optLeavesReaderDataBytes(&readers[0])); | |
| 1496 + if( rc!=SQLITE_OK ) break; | |
| 1497 iReader = 1; | |
| 1498 | |
| 1499 assert( iReader<i ); /* Must execute the loop at least once. */ | |
| 1500 @@ -6263,24 +6519,35 @@ static int optimizeInternal(fulltext_vtab *v, | |
| 1501 /* Merge 16 inputs per pass. */ | |
| 1502 for( nReaders=1; iReader<i && nReaders<MERGE_COUNT; | |
| 1503 iReader++, nReaders++ ){ | |
| 1504 - dlrInit(&dlReaders[nReaders], DL_DEFAULT, | |
| 1505 - optLeavesReaderData(&readers[iReader]), | |
| 1506 - optLeavesReaderDataBytes(&readers[iReader])); | |
| 1507 + pData = optLeavesReaderData(&readers[iReader]); | |
| 1508 + if( pData == NULL ){ | |
| 1509 + rc = SQLITE_CORRUPT_BKPT; | |
| 1510 + break; | |
| 1511 + } | |
| 1512 + rc = dlrInit(&dlReaders[nReaders], DL_DEFAULT, | |
| 1513 + pData, | |
| 1514 + optLeavesReaderDataBytes(&readers[iReader])); | |
| 1515 + if( rc != SQLITE_OK ) break; | |
| 1516 } | |
| 1517 | |
| 1518 /* Merge doclists and swap result into accumulator. */ | |
| 1519 - dataBufferReset(&merged); | |
| 1520 - docListMerge(&merged, dlReaders, nReaders); | |
| 1521 - tmp = merged; | |
| 1522 - merged = doclist; | |
| 1523 - doclist = tmp; | |
| 1524 + if( rc==SQLITE_OK ){ | |
| 1525 + dataBufferReset(&merged); | |
| 1526 + rc = docListMerge(&merged, dlReaders, nReaders); | |
| 1527 + tmp = merged; | |
| 1528 + merged = doclist; | |
| 1529 + doclist = tmp; | |
| 1530 + } | |
| 1531 | |
| 1532 while( nReaders-- > 0 ){ | |
| 1533 dlrDestroy(&dlReaders[nReaders]); | |
| 1534 } | |
| 1535 | |
| 1536 + if( rc!=SQLITE_OK ) goto err; | |
| 1537 + | |
| 1538 /* Accumulated doclist to reader 0 for next pass. */ | |
| 1539 - dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); | |
| 1540 + rc = dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); | |
| 1541 + if( rc!=SQLITE_OK ) goto err; | |
| 1542 } | |
| 1543 | |
| 1544 /* Destroy reader that was left in the pipeline. */ | |
| 1545 @@ -6288,8 +6555,9 @@ static int optimizeInternal(fulltext_vtab *v, | |
| 1546 | |
| 1547 /* Trim deletions from the doclist. */ | |
| 1548 dataBufferReset(&merged); | |
| 1549 - docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
| 1550 - -1, DL_DEFAULT, &merged); | |
| 1551 + rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
| 1552 + -1, DL_DEFAULT, &merged); | |
| 1553 + if( rc!=SQLITE_OK ) goto err; | |
| 1554 } | |
| 1555 | |
| 1556 /* Only pass doclists with hits (skip if all hits deleted). */ | |
| 1557 @@ -6628,16 +6896,19 @@ static void createDoclistResult(sqlite3_context *pContex
t, | |
| 1558 const char *pData, int nData){ | |
| 1559 DataBuffer dump; | |
| 1560 DLReader dlReader; | |
| 1561 + int rc; | |
| 1562 | |
| 1563 assert( pData!=NULL && nData>0 ); | |
| 1564 | |
| 1565 + rc = dlrInit(&dlReader, DL_DEFAULT, pData, nData); | |
| 1566 + if( rc!=SQLITE_OK ) return; | |
| 1567 dataBufferInit(&dump, 0); | |
| 1568 - dlrInit(&dlReader, DL_DEFAULT, pData, nData); | |
| 1569 - for( ; !dlrAtEnd(&dlReader); dlrStep(&dlReader) ){ | |
| 1570 + for( ; rc==SQLITE_OK && !dlrAtEnd(&dlReader); rc = dlrStep(&dlReader) ){ | |
| 1571 char buf[256]; | |
| 1572 PLReader plReader; | |
| 1573 | |
| 1574 - plrInit(&plReader, &dlReader); | |
| 1575 + rc = plrInit(&plReader, &dlReader); | |
| 1576 + if( rc!=SQLITE_OK ) break; | |
| 1577 if( DL_DEFAULT==DL_DOCIDS || plrAtEnd(&plReader) ){ | |
| 1578 sqlite3_snprintf(sizeof(buf), buf, "[%lld] ", dlrDocid(&dlReader)); | |
| 1579 dataBufferAppend(&dump, buf, strlen(buf)); | |
| 1580 @@ -6648,7 +6919,8 @@ static void createDoclistResult(sqlite3_context *pContext, | |
| 1581 dlrDocid(&dlReader), iColumn); | |
| 1582 dataBufferAppend(&dump, buf, strlen(buf)); | |
| 1583 | |
| 1584 - for( ; !plrAtEnd(&plReader); plrStep(&plReader) ){ | |
| 1585 + for( ; !plrAtEnd(&plReader); rc = plrStep(&plReader) ){ | |
| 1586 + if( rc!=SQLITE_OK ) break; | |
| 1587 if( plrColumn(&plReader)!=iColumn ){ | |
| 1588 iColumn = plrColumn(&plReader); | |
| 1589 sqlite3_snprintf(sizeof(buf), buf, "] %d[", iColumn); | |
| 1590 @@ -6669,6 +6941,7 @@ static void createDoclistResult(sqlite3_context *pContext, | |
| 1591 dataBufferAppend(&dump, buf, strlen(buf)); | |
| 1592 } | |
| 1593 plrDestroy(&plReader); | |
| 1594 + if( rc!= SQLITE_OK ) break; | |
| 1595 | |
| 1596 assert( dump.nData>0 ); | |
| 1597 dump.nData--; /* Overwrite trailing space. */ | |
| 1598 @@ -6677,6 +6950,10 @@ static void createDoclistResult(sqlite3_context *pContext
, | |
| 1599 } | |
| 1600 } | |
| 1601 dlrDestroy(&dlReader); | |
| 1602 + if( rc!=SQLITE_OK ){ | |
| 1603 + dataBufferDestroy(&dump); | |
| 1604 + return; | |
| 1605 + } | |
| 1606 | |
| 1607 assert( dump.nData>0 ); | |
| 1608 dump.nData--; /* Overwrite trailing space. */ | |
| 1609 -- | |
| 1610 2.2.1 | |
| 1611 | |
| OLD | NEW |