| OLD | NEW |
| 1 Index: ext/fts3/fts3.c | 1 diff --git ext/fts3/fts3.c ext/fts3/fts3.c |
| 2 =================================================================== | 2 index 20da051..71e22ae 100644 |
| 3 --- ext/fts3/fts3.c» (revision 48811) | 3 --- ext/fts3/fts3.c |
| 4 +++ ext/fts3/fts3.c» (working copy) | 4 +++ ext/fts3/fts3.c |
| 5 @@ -271,6 +271,7 @@ | 5 @@ -291,6 +291,7 @@ |
| 6 ** deletions and duplications. This would basically be a forced merge | 6 ** deletions and duplications. This would basically be a forced merge |
| 7 ** into a single segment. | 7 ** into a single segment. |
| 8 */ | 8 */ |
| 9 +#define CHROMIUM_FTS3_CHANGES 1 | 9 +#define CHROMIUM_FTS3_CHANGES 1 |
| 10 | 10 |
| 11 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) | 11 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) |
| 12 | 12 |
| 13 @@ -313,6 +314,16 @@ | 13 @@ -1226,7 +1227,13 @@ static int fts3ScanInteriorNode( |
| 14 # define FTSTRACE(A) | 14 isFirstTerm = 0; |
| 15 #endif | 15 zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix); |
| 16 | 16 |
| 17 +#if 0 | 17 - if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){ |
| 18 +/* Useful to set breakpoints. See main.c sqlite3Corrupt(). */ | 18 + /* NOTE(shess): Previous code checked for negative nPrefix and |
| 19 +static int fts3Corrupt(void){ | 19 + ** nSuffix and suffix overrunning zEnd. Additionally corrupt if |
| 20 + return SQLITE_CORRUPT; | 20 + ** the prefix is longer than the previous term, or if the suffix |
| 21 +} | 21 + ** causes overflow. |
| 22 +# define SQLITE_CORRUPT_BKPT fts3Corrupt() | 22 + */ |
| 23 +#else | 23 + if( nPrefix<0 || nSuffix<0 || nPrefix>nBuffer |
| 24 +# define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT | 24 + || &zCsr[nSuffix]<zCsr || &zCsr[nSuffix]>zEnd ){ |
| 25 +#endif | 25 rc = SQLITE_CORRUPT; |
| 26 + | 26 goto finish_scan; |
| 27 /* It is not safe to call isspace(), tolower(), or isalnum() on | |
| 28 ** hi-bit-set characters. This is the same solution used in the | |
| 29 ** tokenizer. | |
| 30 @@ -401,30 +412,41 @@ | |
| 31 /* Read a 64-bit variable-length integer from memory starting at p[0]. | |
| 32 * Return the number of bytes read, or 0 on error. | |
| 33 * The value is stored in *v. */ | |
| 34 -static int fts3GetVarint(const char *p, sqlite_int64 *v){ | |
| 35 +static int fts3GetVarintSafe(const char *p, sqlite_int64 *v, int max){ | |
| 36 const unsigned char *q = (const unsigned char *) p; | |
| 37 sqlite_uint64 x = 0, y = 1; | |
| 38 - while( (*q & 0x80) == 0x80 ){ | |
| 39 + if( max>VARINT_MAX ) max = VARINT_MAX; | |
| 40 + while( max && (*q & 0x80) == 0x80 ){ | |
| 41 + max--; | |
| 42 x += y * (*q++ & 0x7f); | |
| 43 y <<= 7; | |
| 44 - if( q - (unsigned char *)p >= VARINT_MAX ){ /* bad data */ | |
| 45 - assert( 0 ); | |
| 46 - return 0; | |
| 47 - } | |
| 48 } | |
| 49 + if( !max ){ | |
| 50 + assert( 0 ); | |
| 51 + return 0; /* tried to read too much; bad data */ | |
| 52 + } | |
| 53 x += y * (*q++); | |
| 54 *v = (sqlite_int64) x; | |
| 55 return (int) (q - (unsigned char *)p); | |
| 56 } | |
| 57 | |
| 58 -static int fts3GetVarint32(const char *p, int *pi){ | |
| 59 +static int fts3GetVarint(const char *p, sqlite_int64 *v){ | |
| 60 + return fts3GetVarintSafe(p, v, VARINT_MAX); | |
| 61 +} | |
| 62 + | |
| 63 +static int fts3GetVarint32Safe(const char *p, int *pi, int max){ | |
| 64 sqlite_int64 i; | |
| 65 - int ret = fts3GetVarint(p, &i); | |
| 66 + int ret = fts3GetVarintSafe(p, &i, max); | |
| 67 + if( !ret ) return ret; | |
| 68 *pi = (int) i; | |
| 69 assert( *pi==i ); | |
| 70 return ret; | |
| 71 } | |
| 72 | |
| 73 +static int fts3GetVarint32(const char* p, int *pi){ | |
| 74 + return fts3GetVarint32Safe(p, pi, VARINT_MAX); | |
| 75 +} | |
| 76 + | |
| 77 /*******************************************************************/ | |
| 78 /* DataBuffer is used to collect data into a buffer in piecemeal | |
| 79 ** fashion. It implements the usual distinction between amount of | |
| 80 @@ -593,7 +615,7 @@ | |
| 81 | |
| 82 static int dlrAtEnd(DLReader *pReader){ | |
| 83 assert( pReader->nData>=0 ); | |
| 84 - return pReader->nData==0; | |
| 85 + return pReader->nData<=0; | |
| 86 } | |
| 87 static sqlite_int64 dlrDocid(DLReader *pReader){ | |
| 88 assert( !dlrAtEnd(pReader) ); | |
| 89 @@ -617,7 +639,8 @@ | |
| 90 */ | |
| 91 static const char *dlrPosData(DLReader *pReader){ | |
| 92 sqlite_int64 iDummy; | |
| 93 - int n = fts3GetVarint(pReader->pData, &iDummy); | |
| 94 + int n = fts3GetVarintSafe(pReader->pData, &iDummy, pReader->nElement); | |
| 95 + if( !n ) return NULL; | |
| 96 assert( !dlrAtEnd(pReader) ); | |
| 97 return pReader->pData+n; | |
| 98 } | |
| 99 @@ -627,7 +650,7 @@ | |
| 100 assert( !dlrAtEnd(pReader) ); | |
| 101 return pReader->nElement-n; | |
| 102 } | |
| 103 -static void dlrStep(DLReader *pReader){ | |
| 104 +static int dlrStep(DLReader *pReader){ | |
| 105 assert( !dlrAtEnd(pReader) ); | |
| 106 | |
| 107 /* Skip past current doclist element. */ | |
| 108 @@ -636,32 +659,44 @@ | |
| 109 pReader->nData -= pReader->nElement; | |
| 110 | |
| 111 /* If there is more data, read the next doclist element. */ | |
| 112 - if( pReader->nData!=0 ){ | |
| 113 + if( pReader->nData>0 ){ | |
| 114 sqlite_int64 iDocidDelta; | |
| 115 - int iDummy, n = fts3GetVarint(pReader->pData, &iDocidDelta); | |
| 116 + int nTotal = 0; | |
| 117 + int iDummy, n = fts3GetVarintSafe(pReader->pData, &iDocidDelta, pReader->nD
ata); | |
| 118 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 119 + nTotal += n; | |
| 120 pReader->iDocid += iDocidDelta; | |
| 121 if( pReader->iType>=DL_POSITIONS ){ | |
| 122 - assert( n<pReader->nData ); | |
| 123 while( 1 ){ | |
| 124 - n += fts3GetVarint32(pReader->pData+n, &iDummy); | |
| 125 - assert( n<=pReader->nData ); | |
| 126 + n = fts3GetVarint32Safe(pReader->pData+nTotal, &iDummy, pReader->nData-
nTotal); | |
| 127 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 128 + nTotal += n; | |
| 129 if( iDummy==POS_END ) break; | |
| 130 if( iDummy==POS_COLUMN ){ | |
| 131 - n += fts3GetVarint32(pReader->pData+n, &iDummy); | |
| 132 - assert( n<pReader->nData ); | |
| 133 + n = fts3GetVarint32Safe(pReader->pData+nTotal, &iDummy, pReader->nDat
a-nTotal); | |
| 134 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 135 + nTotal += n; | |
| 136 }else if( pReader->iType==DL_POSITIONS_OFFSETS ){ | |
| 137 - n += fts3GetVarint32(pReader->pData+n, &iDummy); | |
| 138 - n += fts3GetVarint32(pReader->pData+n, &iDummy); | |
| 139 - assert( n<pReader->nData ); | |
| 140 + n = fts3GetVarint32Safe(pReader->pData+nTotal, &iDummy, pReader->nDat
a-nTotal); | |
| 141 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 142 + nTotal += n; | |
| 143 + n = fts3GetVarint32Safe(pReader->pData+nTotal, &iDummy, pReader->nDat
a-nTotal); | |
| 144 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 145 + nTotal += n; | |
| 146 } | |
| 147 } | |
| 148 } | 27 } |
| 149 - pReader->nElement = n; | 28 @@ -3646,7 +3660,11 @@ int sqlite3Fts3Init(sqlite3 *db){ |
| 150 + pReader->nElement = nTotal; | |
| 151 assert( pReader->nElement<=pReader->nData ); | |
| 152 } | |
| 153 + return SQLITE_OK; | |
| 154 } | |
| 155 -static void dlrInit(DLReader *pReader, DocListType iType, | |
| 156 - const char *pData, int nData){ | |
| 157 +static void dlrDestroy(DLReader *pReader){ | |
| 158 + SCRAMBLE(pReader); | |
| 159 +} | |
| 160 +static int dlrInit(DLReader *pReader, DocListType iType, | |
| 161 + const char *pData, int nData){ | |
| 162 + int rc; | |
| 163 assert( pData!=NULL && nData!=0 ); | |
| 164 pReader->iType = iType; | |
| 165 pReader->pData = pData; | |
| 166 @@ -670,11 +705,10 @@ | |
| 167 pReader->iDocid = 0; | |
| 168 | |
| 169 /* Load the first element's data. There must be a first element. */ | |
| 170 - dlrStep(pReader); | |
| 171 + rc = dlrStep(pReader); | |
| 172 + if( rc!=SQLITE_OK ) dlrDestroy(pReader); | |
| 173 + return rc; | |
| 174 } | |
| 175 -static void dlrDestroy(DLReader *pReader){ | |
| 176 - SCRAMBLE(pReader); | |
| 177 -} | |
| 178 | |
| 179 #ifndef NDEBUG | |
| 180 /* Verify that the doclist can be validly decoded. Also returns the | |
| 181 @@ -760,9 +794,9 @@ | |
| 182 /* TODO(shess) This has become just a helper for docListMerge. | |
| 183 ** Consider a refactor to make this cleaner. | |
| 184 */ | |
| 185 -static void dlwAppend(DLWriter *pWriter, | |
| 186 - const char *pData, int nData, | |
| 187 - sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ | |
| 188 +static int dlwAppend(DLWriter *pWriter, | |
| 189 + const char *pData, int nData, | |
| 190 + sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ | |
| 191 sqlite_int64 iDocid = 0; | |
| 192 char c[VARINT_MAX]; | |
| 193 int nFirstOld, nFirstNew; /* Old and new varint len of first docid. */ | |
| 194 @@ -771,7 +805,8 @@ | |
| 195 #endif | |
| 196 | |
| 197 /* Recode the initial docid as delta from iPrevDocid. */ | |
| 198 - nFirstOld = fts3GetVarint(pData, &iDocid); | |
| 199 + nFirstOld = fts3GetVarintSafe(pData, &iDocid, nData); | |
| 200 + if( !nFirstOld ) return SQLITE_CORRUPT_BKPT; | |
| 201 assert( nFirstOld<nData || (nFirstOld==nData && pWriter->iType==DL_DOCIDS) ); | |
| 202 nFirstNew = fts3PutVarint(c, iFirstDocid-pWriter->iPrevDocid); | |
| 203 | |
| 204 @@ -792,10 +827,11 @@ | |
| 205 dataBufferAppend(pWriter->b, c, nFirstNew); | |
| 206 } | |
| 207 pWriter->iPrevDocid = iLastDocid; | |
| 208 + return SQLITE_OK; | |
| 209 } | |
| 210 -static void dlwCopy(DLWriter *pWriter, DLReader *pReader){ | |
| 211 - dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), | |
| 212 - dlrDocid(pReader), dlrDocid(pReader)); | |
| 213 +static int dlwCopy(DLWriter *pWriter, DLReader *pReader){ | |
| 214 + return dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), | |
| 215 + dlrDocid(pReader), dlrDocid(pReader)); | |
| 216 } | |
| 217 static void dlwAdd(DLWriter *pWriter, sqlite_int64 iDocid){ | |
| 218 char c[VARINT_MAX]; | |
| 219 @@ -856,45 +892,61 @@ | |
| 220 assert( !plrAtEnd(pReader) ); | |
| 221 return pReader->iEndOffset; | |
| 222 } | |
| 223 -static void plrStep(PLReader *pReader){ | |
| 224 - int i, n; | |
| 225 +static int plrStep(PLReader *pReader){ | |
| 226 + int i, n, nTotal = 0; | |
| 227 | |
| 228 assert( !plrAtEnd(pReader) ); | |
| 229 | |
| 230 - if( pReader->nData==0 ){ | |
| 231 + if( pReader->nData<=0 ){ | |
| 232 pReader->pData = NULL; | |
| 233 - return; | |
| 234 + return SQLITE_OK; | |
| 235 } | |
| 236 | |
| 237 - n = fts3GetVarint32(pReader->pData, &i); | |
| 238 + n = fts3GetVarint32Safe(pReader->pData, &i, pReader->nData); | |
| 239 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 240 + nTotal += n; | |
| 241 if( i==POS_COLUMN ){ | |
| 242 - n += fts3GetVarint32(pReader->pData+n, &pReader->iColumn); | |
| 243 + n = fts3GetVarint32Safe(pReader->pData+nTotal, &pReader->iColumn, pReader->
nData-nTotal); | |
| 244 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 245 + nTotal += n; | |
| 246 pReader->iPosition = 0; | |
| 247 pReader->iStartOffset = 0; | |
| 248 - n += fts3GetVarint32(pReader->pData+n, &i); | |
| 249 + n = fts3GetVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); | |
| 250 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 251 + nTotal += n; | |
| 252 } | |
| 253 /* Should never see adjacent column changes. */ | |
| 254 assert( i!=POS_COLUMN ); | |
| 255 | |
| 256 if( i==POS_END ){ | |
| 257 + assert( nTotal<=pReader->nData ); | |
| 258 pReader->nData = 0; | |
| 259 pReader->pData = NULL; | |
| 260 - return; | |
| 261 + return SQLITE_OK; | |
| 262 } | |
| 263 | |
| 264 pReader->iPosition += i-POS_BASE; | |
| 265 if( pReader->iType==DL_POSITIONS_OFFSETS ){ | |
| 266 - n += fts3GetVarint32(pReader->pData+n, &i); | |
| 267 + n = fts3GetVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); | |
| 268 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 269 + nTotal += n; | |
| 270 pReader->iStartOffset += i; | |
| 271 - n += fts3GetVarint32(pReader->pData+n, &i); | |
| 272 + n = fts3GetVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); | |
| 273 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 274 + nTotal += n; | |
| 275 pReader->iEndOffset = pReader->iStartOffset+i; | |
| 276 } | |
| 277 - assert( n<=pReader->nData ); | |
| 278 - pReader->pData += n; | |
| 279 - pReader->nData -= n; | |
| 280 + assert( nTotal<=pReader->nData ); | |
| 281 + pReader->pData += nTotal; | |
| 282 + pReader->nData -= nTotal; | |
| 283 + return SQLITE_OK; | |
| 284 } | |
| 285 | |
| 286 -static void plrInit(PLReader *pReader, DLReader *pDLReader){ | |
| 287 +static void plrDestroy(PLReader *pReader){ | |
| 288 + SCRAMBLE(pReader); | |
| 289 +} | |
| 290 +static int plrInit(PLReader *pReader, DLReader *pDLReader){ | |
| 291 + int rc; | |
| 292 pReader->pData = dlrPosData(pDLReader); | |
| 293 pReader->nData = dlrPosDataLen(pDLReader); | |
| 294 pReader->iType = pDLReader->iType; | |
| 295 @@ -902,11 +954,10 @@ | |
| 296 pReader->iPosition = 0; | |
| 297 pReader->iStartOffset = 0; | |
| 298 pReader->iEndOffset = 0; | |
| 299 - plrStep(pReader); | |
| 300 + rc = plrStep(pReader); | |
| 301 + if( rc!=SQLITE_OK ) plrDestroy(pReader); | |
| 302 + return rc; | |
| 303 } | |
| 304 -static void plrDestroy(PLReader *pReader){ | |
| 305 - SCRAMBLE(pReader); | |
| 306 -} | |
| 307 | |
| 308 /*******************************************************************/ | |
| 309 /* PLWriter is used in constructing a document's position list. As a | |
| 310 @@ -1091,14 +1142,16 @@ | |
| 311 ** deletion will be trimmed, and will thus not effect a deletion | |
| 312 ** during the merge. | |
| 313 */ | |
| 314 -static void docListTrim(DocListType iType, const char *pData, int nData, | |
| 315 - int iColumn, DocListType iOutType, DataBuffer *out){ | |
| 316 +static int docListTrim(DocListType iType, const char *pData, int nData, | |
| 317 + int iColumn, DocListType iOutType, DataBuffer *out){ | |
| 318 DLReader dlReader; | |
| 319 DLWriter dlWriter; | |
| 320 + int rc; | |
| 321 | |
| 322 assert( iOutType<=iType ); | |
| 323 | |
| 324 - dlrInit(&dlReader, iType, pData, nData); | |
| 325 + rc = dlrInit(&dlReader, iType, pData, nData); | |
| 326 + if( rc!=SQLITE_OK ) return rc; | |
| 327 dlwInit(&dlWriter, iOutType, out); | |
| 328 | |
| 329 while( !dlrAtEnd(&dlReader) ){ | |
| 330 @@ -1106,7 +1159,8 @@ | |
| 331 PLWriter plWriter; | |
| 332 int match = 0; | |
| 333 | |
| 334 - plrInit(&plReader, &dlReader); | |
| 335 + rc = plrInit(&plReader, &dlReader); | |
| 336 + if( rc!=SQLITE_OK ) break; | |
| 337 | |
| 338 while( !plrAtEnd(&plReader) ){ | |
| 339 if( iColumn==-1 || plrColumn(&plReader)==iColumn ){ | |
| 340 @@ -1117,7 +1171,11 @@ | |
| 341 plwAdd(&plWriter, plrColumn(&plReader), plrPosition(&plReader), | |
| 342 plrStartOffset(&plReader), plrEndOffset(&plReader)); | |
| 343 } | |
| 344 - plrStep(&plReader); | |
| 345 + rc = plrStep(&plReader); | |
| 346 + if( rc!=SQLITE_OK ){ | |
| 347 + plrDestroy(&plReader); | |
| 348 + goto err; | |
| 349 + } | |
| 350 } | |
| 351 if( match ){ | |
| 352 plwTerminate(&plWriter); | |
| 353 @@ -1125,10 +1183,13 @@ | |
| 354 } | |
| 355 | |
| 356 plrDestroy(&plReader); | |
| 357 - dlrStep(&dlReader); | |
| 358 + rc = dlrStep(&dlReader); | |
| 359 + if( rc!=SQLITE_OK ) break; | |
| 360 } | |
| 361 +err: | |
| 362 dlwDestroy(&dlWriter); | |
| 363 dlrDestroy(&dlReader); | |
| 364 + return rc; | |
| 365 } | |
| 366 | |
| 367 /* Used by docListMerge() to keep doclists in the ascending order by | |
| 368 @@ -1185,19 +1246,20 @@ | |
| 369 /* TODO(shess) nReaders must be <= MERGE_COUNT. This should probably | |
| 370 ** be fixed. | |
| 371 */ | |
| 372 -static void docListMerge(DataBuffer *out, | |
| 373 - DLReader *pReaders, int nReaders){ | |
| 374 +static int docListMerge(DataBuffer *out, | |
| 375 + DLReader *pReaders, int nReaders){ | |
| 376 OrderedDLReader readers[MERGE_COUNT]; | |
| 377 DLWriter writer; | |
| 378 int i, n; | |
| 379 const char *pStart = 0; | |
| 380 int nStart = 0; | |
| 381 sqlite_int64 iFirstDocid = 0, iLastDocid = 0; | |
| 382 + int rc = SQLITE_OK; | |
| 383 | |
| 384 assert( nReaders>0 ); | |
| 385 if( nReaders==1 ){ | |
| 386 dataBufferAppend(out, dlrDocData(pReaders), dlrAllDataBytes(pReaders)); | |
| 387 - return; | |
| 388 + return SQLITE_OK; | |
| 389 } | |
| 390 | |
| 391 assert( nReaders<=MERGE_COUNT ); | |
| 392 @@ -1230,20 +1292,23 @@ | |
| 393 nStart += dlrDocDataBytes(readers[0].pReader); | |
| 394 }else{ | |
| 395 if( pStart!=0 ){ | |
| 396 - dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | |
| 397 + rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | |
| 398 + if( rc!=SQLITE_OK ) goto err; | |
| 399 } | |
| 400 pStart = dlrDocData(readers[0].pReader); | |
| 401 nStart = dlrDocDataBytes(readers[0].pReader); | |
| 402 iFirstDocid = iDocid; | |
| 403 } | |
| 404 iLastDocid = iDocid; | |
| 405 - dlrStep(readers[0].pReader); | |
| 406 + rc = dlrStep(readers[0].pReader); | |
| 407 + if( rc!= SQLITE_OK ) goto err; | |
| 408 | |
| 409 /* Drop all of the older elements with the same docid. */ | |
| 410 for(i=1; i<nReaders && | |
| 411 !dlrAtEnd(readers[i].pReader) && | |
| 412 dlrDocid(readers[i].pReader)==iDocid; i++){ | |
| 413 - dlrStep(readers[i].pReader); | |
| 414 + rc = dlrStep(readers[i].pReader); | |
| 415 + if( rc!=SQLITE_OK ) goto err; | |
| 416 } | |
| 417 | |
| 418 /* Get the readers back into order. */ | |
| 419 @@ -1253,8 +1318,10 @@ | |
| 420 } | |
| 421 | |
| 422 /* Copy over any remaining elements. */ | |
| 423 - if( nStart>0 ) dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | |
| 424 + if( nStart>0 ) rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDoci
d); | |
| 425 +err: | |
| 426 dlwDestroy(&writer); | |
| 427 + return rc; | |
| 428 } | |
| 429 | |
| 430 /* Helper function for posListUnion(). Compares the current position | |
| 431 @@ -1290,30 +1357,40 @@ | |
| 432 ** work with any doclist type, though both inputs and the output | |
| 433 ** should be the same type. | |
| 434 */ | |
| 435 -static void posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ | |
| 436 +static int posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ | |
| 437 PLReader left, right; | |
| 438 PLWriter writer; | |
| 439 + int rc; | |
| 440 | |
| 441 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); | |
| 442 assert( pLeft->iType==pRight->iType ); | |
| 443 assert( pLeft->iType==pOut->iType ); | |
| 444 | |
| 445 - plrInit(&left, pLeft); | |
| 446 - plrInit(&right, pRight); | |
| 447 + rc = plrInit(&left, pLeft); | |
| 448 + if( rc!=SQLITE_OK ) return rc; | |
| 449 + rc = plrInit(&right, pRight); | |
| 450 + if( rc!=SQLITE_OK ){ | |
| 451 + plrDestroy(&left); | |
| 452 + return rc; | |
| 453 + } | |
| 454 plwInit(&writer, pOut, dlrDocid(pLeft)); | |
| 455 | |
| 456 while( !plrAtEnd(&left) || !plrAtEnd(&right) ){ | |
| 457 int c = posListCmp(&left, &right); | |
| 458 if( c<0 ){ | |
| 459 plwCopy(&writer, &left); | |
| 460 - plrStep(&left); | |
| 461 + rc = plrStep(&left); | |
| 462 + if( rc!=SQLITE_OK ) break; | |
| 463 }else if( c>0 ){ | |
| 464 plwCopy(&writer, &right); | |
| 465 - plrStep(&right); | |
| 466 + rc = plrStep(&right); | |
| 467 + if( rc!=SQLITE_OK ) break; | |
| 468 }else{ | |
| 469 plwCopy(&writer, &left); | |
| 470 - plrStep(&left); | |
| 471 - plrStep(&right); | |
| 472 + rc = plrStep(&left); | |
| 473 + if( rc!=SQLITE_OK ) break; | |
| 474 + rc = plrStep(&right); | |
| 475 + if( rc!=SQLITE_OK ) break; | |
| 476 } | |
| 477 } | |
| 478 | |
| 479 @@ -1321,56 +1398,75 @@ | |
| 480 plwDestroy(&writer); | |
| 481 plrDestroy(&left); | |
| 482 plrDestroy(&right); | |
| 483 + return rc; | |
| 484 } | |
| 485 | |
| 486 /* Write the union of doclists in pLeft and pRight to pOut. For | |
| 487 ** docids in common between the inputs, the union of the position | |
| 488 ** lists is written. Inputs and outputs are always type DL_DEFAULT. | |
| 489 */ | |
| 490 -static void docListUnion( | |
| 491 +static int docListUnion( | |
| 492 const char *pLeft, int nLeft, | |
| 493 const char *pRight, int nRight, | |
| 494 DataBuffer *pOut /* Write the combined doclist here */ | |
| 495 ){ | |
| 496 DLReader left, right; | |
| 497 DLWriter writer; | |
| 498 + int rc; | |
| 499 | |
| 500 if( nLeft==0 ){ | |
| 501 if( nRight!=0) dataBufferAppend(pOut, pRight, nRight); | |
| 502 - return; | |
| 503 + return SQLITE_OK; | |
| 504 } | |
| 505 if( nRight==0 ){ | |
| 506 dataBufferAppend(pOut, pLeft, nLeft); | |
| 507 - return; | |
| 508 + return SQLITE_OK; | |
| 509 } | |
| 510 | |
| 511 - dlrInit(&left, DL_DEFAULT, pLeft, nLeft); | |
| 512 - dlrInit(&right, DL_DEFAULT, pRight, nRight); | |
| 513 + rc = dlrInit(&left, DL_DEFAULT, pLeft, nLeft); | |
| 514 + if( rc!=SQLITE_OK ) return rc; | |
| 515 + rc = dlrInit(&right, DL_DEFAULT, pRight, nRight); | |
| 516 + if( rc!=SQLITE_OK){ | |
| 517 + dlrDestroy(&left); | |
| 518 + return rc; | |
| 519 + } | |
| 520 dlwInit(&writer, DL_DEFAULT, pOut); | |
| 521 | |
| 522 while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ | |
| 523 if( dlrAtEnd(&right) ){ | |
| 524 - dlwCopy(&writer, &left); | |
| 525 - dlrStep(&left); | |
| 526 + rc = dlwCopy(&writer, &left); | |
| 527 + if( rc!=SQLITE_OK) break; | |
| 528 + rc = dlrStep(&left); | |
| 529 + if( rc!=SQLITE_OK) break; | |
| 530 }else if( dlrAtEnd(&left) ){ | |
| 531 - dlwCopy(&writer, &right); | |
| 532 - dlrStep(&right); | |
| 533 + rc = dlwCopy(&writer, &right); | |
| 534 + if( rc!=SQLITE_OK ) break; | |
| 535 + rc = dlrStep(&right); | |
| 536 + if( rc!=SQLITE_OK ) break; | |
| 537 }else if( dlrDocid(&left)<dlrDocid(&right) ){ | |
| 538 - dlwCopy(&writer, &left); | |
| 539 - dlrStep(&left); | |
| 540 + rc = dlwCopy(&writer, &left); | |
| 541 + if( rc!=SQLITE_OK ) break; | |
| 542 + rc = dlrStep(&left); | |
| 543 + if( rc!=SQLITE_OK ) break; | |
| 544 }else if( dlrDocid(&left)>dlrDocid(&right) ){ | |
| 545 - dlwCopy(&writer, &right); | |
| 546 - dlrStep(&right); | |
| 547 + rc = dlwCopy(&writer, &right); | |
| 548 + if( rc!=SQLITE_OK ) break; | |
| 549 + rc = dlrStep(&right); | |
| 550 + if( rc!=SQLITE_OK ) break; | |
| 551 }else{ | |
| 552 - posListUnion(&left, &right, &writer); | |
| 553 - dlrStep(&left); | |
| 554 - dlrStep(&right); | |
| 555 + rc = posListUnion(&left, &right, &writer); | |
| 556 + if( rc!=SQLITE_OK ) break; | |
| 557 + rc = dlrStep(&left); | |
| 558 + if( rc!=SQLITE_OK ) break; | |
| 559 + rc = dlrStep(&right); | |
| 560 + if( rc!=SQLITE_OK ) break; | |
| 561 } | |
| 562 } | |
| 563 | |
| 564 dlrDestroy(&left); | |
| 565 dlrDestroy(&right); | |
| 566 dlwDestroy(&writer); | |
| 567 + return rc; | |
| 568 } | |
| 569 | |
| 570 /* | |
| 571 @@ -1394,7 +1490,7 @@ | |
| 572 ** from pLeft instead of pRight. In the example above, the positions "5" | |
| 573 ** and "20" would be added instead of "6" and "21". | |
| 574 */ | |
| 575 -static void posListPhraseMerge( | |
| 576 +static int posListPhraseMerge( | |
| 577 DLReader *pLeft, | |
| 578 DLReader *pRight, | |
| 579 int nNear, | |
| 580 @@ -1404,20 +1500,29 @@ | |
| 581 PLReader left, right; | |
| 582 PLWriter writer; | |
| 583 int match = 0; | |
| 584 + int rc; | |
| 585 | |
| 586 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); | |
| 587 assert( pOut->iType!=DL_POSITIONS_OFFSETS ); | |
| 588 | |
| 589 - plrInit(&left, pLeft); | |
| 590 - plrInit(&right, pRight); | |
| 591 + rc = plrInit(&left, pLeft); | |
| 592 + if( rc!=SQLITE_OK ) return rc; | |
| 593 + rc = plrInit(&right, pRight); | |
| 594 + if( rc!=SQLITE_OK ){ | |
| 595 + plrDestroy(&left); | |
| 596 + return rc; | |
| 597 + } | |
| 598 | |
| 599 while( !plrAtEnd(&left) && !plrAtEnd(&right) ){ | |
| 600 if( plrColumn(&left)<plrColumn(&right) ){ | |
| 601 - plrStep(&left); | |
| 602 + rc = plrStep(&left); | |
| 603 + if( rc!=SQLITE_OK ) break; | |
| 604 }else if( plrColumn(&left)>plrColumn(&right) ){ | |
| 605 - plrStep(&right); | |
| 606 + rc = plrStep(&right); | |
| 607 + if( rc!=SQLITE_OK ) break; | |
| 608 }else if( plrPosition(&left)>=plrPosition(&right) ){ | |
| 609 - plrStep(&right); | |
| 610 + rc = plrStep(&right); | |
| 611 + if( rc!=SQLITE_OK ) break; | |
| 612 }else{ | |
| 613 if( (plrPosition(&right)-plrPosition(&left))<=(nNear+1) ){ | |
| 614 if( !match ){ | |
| 615 @@ -1429,9 +1534,11 @@ | |
| 616 }else{ | |
| 617 plwAdd(&writer, plrColumn(&left), plrPosition(&left), 0, 0); | |
| 618 } | |
| 619 - plrStep(&right); | |
| 620 + rc = plrStep(&right); | |
| 621 + if( rc!=SQLITE_OK ) break; | |
| 622 }else{ | |
| 623 - plrStep(&left); | |
| 624 + rc = plrStep(&left); | |
| 625 + if( rc!=SQLITE_OK ) break; | |
| 626 } | |
| 627 } | |
| 628 } | |
| 629 @@ -1443,6 +1550,7 @@ | |
| 630 | |
| 631 plrDestroy(&left); | |
| 632 plrDestroy(&right); | |
| 633 + return rc; | |
| 634 } | |
| 635 | |
| 636 /* | |
| 637 @@ -1496,7 +1604,7 @@ | |
| 638 ** iType controls the type of data written to pOut. If iType is | |
| 639 ** DL_POSITIONS, the positions are those from pRight. | |
| 640 */ | |
| 641 -static void docListPhraseMerge( | |
| 642 +static int docListPhraseMerge( | |
| 643 const char *pLeft, int nLeft, | |
| 644 const char *pRight, int nRight, | |
| 645 int nNear, /* 0 for a phrase merge, non-zero for a NEAR merge */ | |
| 646 @@ -1506,43 +1614,63 @@ | |
| 647 ){ | |
| 648 DLReader left, right; | |
| 649 DLWriter writer; | |
| 650 + int rc; | |
| 651 | |
| 652 - if( nLeft==0 || nRight==0 ) return; | |
| 653 + /* These two buffers are used in the 'while', but are declared here | |
| 654 + ** to simplify error-handling. | |
| 655 + */ | |
| 656 + DataBuffer one = {0, 0, 0}; | |
| 657 + DataBuffer two = {0, 0, 0}; | |
| 658 | |
| 659 + if( nLeft==0 || nRight==0 ) return SQLITE_OK; | |
| 660 + | |
| 661 assert( iType!=DL_POSITIONS_OFFSETS ); | |
| 662 | |
| 663 - dlrInit(&left, DL_POSITIONS, pLeft, nLeft); | |
| 664 - dlrInit(&right, DL_POSITIONS, pRight, nRight); | |
| 665 + rc = dlrInit(&left, DL_POSITIONS, pLeft, nLeft); | |
| 666 + if( rc!=SQLITE_OK ) return rc; | |
| 667 + rc = dlrInit(&right, DL_POSITIONS, pRight, nRight); | |
| 668 + if( rc!=SQLITE_OK ){ | |
| 669 + dlrDestroy(&left); | |
| 670 + return rc; | |
| 671 + } | |
| 672 dlwInit(&writer, iType, pOut); | |
| 673 | |
| 674 while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ | |
| 675 if( dlrDocid(&left)<dlrDocid(&right) ){ | |
| 676 - dlrStep(&left); | |
| 677 + rc = dlrStep(&left); | |
| 678 + if( rc!=SQLITE_OK ) goto err; | |
| 679 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | |
| 680 - dlrStep(&right); | |
| 681 + rc = dlrStep(&right); | |
| 682 + if( rc!=SQLITE_OK ) goto err; | |
| 683 }else{ | |
| 684 if( nNear==0 ){ | |
| 685 - posListPhraseMerge(&left, &right, 0, 0, &writer); | |
| 686 + rc = posListPhraseMerge(&left, &right, 0, 0, &writer); | |
| 687 + if( rc!=SQLITE_OK ) goto err; | |
| 688 }else{ | |
| 689 /* This case occurs when two terms (simple terms or phrases) are | |
| 690 * connected by a NEAR operator, span (nNear+1). i.e. | |
| 691 * | |
| 692 * '"terrible company" NEAR widget' | |
| 693 */ | |
| 694 - DataBuffer one = {0, 0, 0}; | |
| 695 - DataBuffer two = {0, 0, 0}; | |
| 696 - | |
| 697 DLWriter dlwriter2; | |
| 698 - DLReader dr1 = {0, 0, 0, 0, 0}; | |
| 699 + DLReader dr1 = {0, 0, 0, 0, 0}; | |
| 700 DLReader dr2 = {0, 0, 0, 0, 0}; | |
| 701 | |
| 702 dlwInit(&dlwriter2, iType, &one); | |
| 703 - posListPhraseMerge(&right, &left, nNear-3+nPhrase, 1, &dlwriter2); | |
| 704 + rc = posListPhraseMerge(&right, &left, nNear-3+nPhrase, 1, &dlwriter2); | |
| 705 + if( rc!=SQLITE_OK ) goto err; | |
| 706 dlwInit(&dlwriter2, iType, &two); | |
| 707 - posListPhraseMerge(&left, &right, nNear-1, 0, &dlwriter2); | |
| 708 + rc = posListPhraseMerge(&left, &right, nNear-1, 0, &dlwriter2); | |
| 709 + if( rc!=SQLITE_OK ) goto err; | |
| 710 | |
| 711 - if( one.nData) dlrInit(&dr1, iType, one.pData, one.nData); | |
| 712 - if( two.nData) dlrInit(&dr2, iType, two.pData, two.nData); | |
| 713 + if( one.nData){ | |
| 714 + rc = dlrInit(&dr1, iType, one.pData, one.nData); | |
| 715 + if( rc!=SQLITE_OK ) goto err; | |
| 716 + } | |
| 717 + if( two.nData){ | |
| 718 + rc = dlrInit(&dr2, iType, two.pData, two.nData); | |
| 719 + if( rc!=SQLITE_OK ) goto err; | |
| 720 + } | |
| 721 | |
| 722 if( !dlrAtEnd(&dr1) || !dlrAtEnd(&dr2) ){ | |
| 723 PLReader pr1 = {0}; | |
| 724 @@ -1551,161 +1679,211 @@ | |
| 725 PLWriter plwriter; | |
| 726 plwInit(&plwriter, &writer, dlrDocid(dlrAtEnd(&dr1)?&dr2:&dr1)); | |
| 727 | |
| 728 - if( one.nData ) plrInit(&pr1, &dr1); | |
| 729 - if( two.nData ) plrInit(&pr2, &dr2); | |
| 730 + if( one.nData ){ | |
| 731 + rc = plrInit(&pr1, &dr1); | |
| 732 + if( rc!=SQLITE_OK ) goto err; | |
| 733 + } | |
| 734 + if( two.nData ){ | |
| 735 + rc = plrInit(&pr2, &dr2); | |
| 736 + if( rc!=SQLITE_OK ) goto err; | |
| 737 + } | |
| 738 while( !plrAtEnd(&pr1) || !plrAtEnd(&pr2) ){ | |
| 739 int iCompare = plrCompare(&pr1, &pr2); | |
| 740 switch( iCompare ){ | |
| 741 case -1: | |
| 742 plwCopy(&plwriter, &pr1); | |
| 743 - plrStep(&pr1); | |
| 744 + rc = plrStep(&pr1); | |
| 745 + if( rc!=SQLITE_OK ) goto err; | |
| 746 break; | |
| 747 case 1: | |
| 748 plwCopy(&plwriter, &pr2); | |
| 749 - plrStep(&pr2); | |
| 750 + rc = plrStep(&pr2); | |
| 751 + if( rc!=SQLITE_OK ) goto err; | |
| 752 break; | |
| 753 case 0: | |
| 754 plwCopy(&plwriter, &pr1); | |
| 755 - plrStep(&pr1); | |
| 756 - plrStep(&pr2); | |
| 757 + rc = plrStep(&pr1); | |
| 758 + if( rc!=SQLITE_OK ) goto err; | |
| 759 + rc = plrStep(&pr2); | |
| 760 + if( rc!=SQLITE_OK ) goto err; | |
| 761 break; | |
| 762 } | |
| 763 } | |
| 764 plwTerminate(&plwriter); | |
| 765 } | |
| 766 - dataBufferDestroy(&one); | |
| 767 - dataBufferDestroy(&two); | |
| 768 + dataBufferReset(&one); | |
| 769 + dataBufferReset(&two); | |
| 770 } | |
| 771 - dlrStep(&left); | |
| 772 - dlrStep(&right); | |
| 773 + rc = dlrStep(&left); | |
| 774 + if( rc!=SQLITE_OK ) goto err; | |
| 775 + rc = dlrStep(&right); | |
| 776 + if( rc!=SQLITE_OK ) goto err; | |
| 777 } | |
| 778 } | |
| 779 | |
| 780 +err: | |
| 781 + dataBufferDestroy(&one); | |
| 782 + dataBufferDestroy(&two); | |
| 783 dlrDestroy(&left); | |
| 784 dlrDestroy(&right); | |
| 785 dlwDestroy(&writer); | |
| 786 + return rc; | |
| 787 } | |
| 788 | |
| 789 /* We have two DL_DOCIDS doclists: pLeft and pRight. | |
| 790 ** Write the intersection of these two doclists into pOut as a | |
| 791 ** DL_DOCIDS doclist. | |
| 792 */ | |
| 793 -static void docListAndMerge( | |
| 794 +static int docListAndMerge( | |
| 795 const char *pLeft, int nLeft, | |
| 796 const char *pRight, int nRight, | |
| 797 DataBuffer *pOut /* Write the combined doclist here */ | |
| 798 ){ | |
| 799 DLReader left, right; | |
| 800 DLWriter writer; | |
| 801 + int rc; | |
| 802 | |
| 803 - if( nLeft==0 || nRight==0 ) return; | |
| 804 + if( nLeft==0 || nRight==0 ) return SQLITE_OK; | |
| 805 | |
| 806 - dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 807 - dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 808 + rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 809 + if( rc!=SQLITE_OK ) return rc; | |
| 810 + rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 811 + if( rc!=SQLITE_OK ){ | |
| 812 + dlrDestroy(&left); | |
| 813 + return rc; | |
| 814 + } | |
| 815 dlwInit(&writer, DL_DOCIDS, pOut); | |
| 816 | |
| 817 while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ | |
| 818 if( dlrDocid(&left)<dlrDocid(&right) ){ | |
| 819 - dlrStep(&left); | |
| 820 + rc = dlrStep(&left); | |
| 821 + if( rc!=SQLITE_OK ) break; | |
| 822 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | |
| 823 - dlrStep(&right); | |
| 824 + rc = dlrStep(&right); | |
| 825 + if( rc!=SQLITE_OK ) break; | |
| 826 }else{ | |
| 827 dlwAdd(&writer, dlrDocid(&left)); | |
| 828 - dlrStep(&left); | |
| 829 - dlrStep(&right); | |
| 830 + rc = dlrStep(&left); | |
| 831 + if( rc!=SQLITE_OK ) break; | |
| 832 + rc = dlrStep(&right); | |
| 833 + if( rc!=SQLITE_OK ) break; | |
| 834 } | |
| 835 } | |
| 836 | |
| 837 dlrDestroy(&left); | |
| 838 dlrDestroy(&right); | |
| 839 dlwDestroy(&writer); | |
| 840 + return rc; | |
| 841 } | |
| 842 | |
| 843 /* We have two DL_DOCIDS doclists: pLeft and pRight. | |
| 844 ** Write the union of these two doclists into pOut as a | |
| 845 ** DL_DOCIDS doclist. | |
| 846 */ | |
| 847 -static void docListOrMerge( | |
| 848 +static int docListOrMerge( | |
| 849 const char *pLeft, int nLeft, | |
| 850 const char *pRight, int nRight, | |
| 851 DataBuffer *pOut /* Write the combined doclist here */ | |
| 852 ){ | |
| 853 DLReader left, right; | |
| 854 DLWriter writer; | |
| 855 + int rc; | |
| 856 | |
| 857 if( nLeft==0 ){ | |
| 858 if( nRight!=0 ) dataBufferAppend(pOut, pRight, nRight); | |
| 859 - return; | |
| 860 + return SQLITE_OK; | |
| 861 } | |
| 862 if( nRight==0 ){ | |
| 863 dataBufferAppend(pOut, pLeft, nLeft); | |
| 864 - return; | |
| 865 + return SQLITE_OK; | |
| 866 } | |
| 867 | |
| 868 - dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 869 - dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 870 + rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 871 + if( rc!=SQLITE_OK ) return rc; | |
| 872 + rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 873 + if( rc!=SQLITE_OK ){ | |
| 874 + dlrDestroy(&left); | |
| 875 + return rc; | |
| 876 + } | |
| 877 dlwInit(&writer, DL_DOCIDS, pOut); | |
| 878 | |
| 879 while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ | |
| 880 if( dlrAtEnd(&right) ){ | |
| 881 dlwAdd(&writer, dlrDocid(&left)); | |
| 882 - dlrStep(&left); | |
| 883 + rc = dlrStep(&left); | |
| 884 + if( rc!=SQLITE_OK ) break; | |
| 885 }else if( dlrAtEnd(&left) ){ | |
| 886 dlwAdd(&writer, dlrDocid(&right)); | |
| 887 - dlrStep(&right); | |
| 888 + rc = dlrStep(&right); | |
| 889 + if( rc!=SQLITE_OK ) break; | |
| 890 }else if( dlrDocid(&left)<dlrDocid(&right) ){ | |
| 891 dlwAdd(&writer, dlrDocid(&left)); | |
| 892 - dlrStep(&left); | |
| 893 + rc = dlrStep(&left); | |
| 894 + if( rc!=SQLITE_OK ) break; | |
| 895 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | |
| 896 dlwAdd(&writer, dlrDocid(&right)); | |
| 897 - dlrStep(&right); | |
| 898 + rc = dlrStep(&right); | |
| 899 + if( rc!=SQLITE_OK ) break; | |
| 900 }else{ | |
| 901 dlwAdd(&writer, dlrDocid(&left)); | |
| 902 - dlrStep(&left); | |
| 903 - dlrStep(&right); | |
| 904 + rc = dlrStep(&left); | |
| 905 + if( rc!=SQLITE_OK ) break; | |
| 906 + rc = dlrStep(&right); | |
| 907 + if( rc!=SQLITE_OK ) break; | |
| 908 } | |
| 909 } | |
| 910 | |
| 911 dlrDestroy(&left); | |
| 912 dlrDestroy(&right); | |
| 913 dlwDestroy(&writer); | |
| 914 + return rc; | |
| 915 } | |
| 916 | |
| 917 /* We have two DL_DOCIDS doclists: pLeft and pRight. | |
| 918 ** Write into pOut as DL_DOCIDS doclist containing all documents that | |
| 919 ** occur in pLeft but not in pRight. | |
| 920 */ | |
| 921 -static void docListExceptMerge( | |
| 922 +static int docListExceptMerge( | |
| 923 const char *pLeft, int nLeft, | |
| 924 const char *pRight, int nRight, | |
| 925 DataBuffer *pOut /* Write the combined doclist here */ | |
| 926 ){ | |
| 927 DLReader left, right; | |
| 928 DLWriter writer; | |
| 929 + int rc; | |
| 930 | |
| 931 - if( nLeft==0 ) return; | |
| 932 + if( nLeft==0 ) return SQLITE_OK; | |
| 933 if( nRight==0 ){ | |
| 934 dataBufferAppend(pOut, pLeft, nLeft); | |
| 935 - return; | |
| 936 + return SQLITE_OK; | |
| 937 } | |
| 938 | |
| 939 - dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 940 - dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 941 + rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
| 942 + if( rc!=SQLITE_OK ) return rc; | |
| 943 + rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
| 944 + if( rc!=SQLITE_OK ){ | |
| 945 + dlrDestroy(&left); | |
| 946 + return rc; | |
| 947 + } | |
| 948 dlwInit(&writer, DL_DOCIDS, pOut); | |
| 949 | |
| 950 while( !dlrAtEnd(&left) ){ | |
| 951 while( !dlrAtEnd(&right) && dlrDocid(&right)<dlrDocid(&left) ){ | |
| 952 - dlrStep(&right); | |
| 953 + rc = dlrStep(&right); | |
| 954 + if( rc!=SQLITE_OK ) goto err; | |
| 955 } | |
| 956 if( dlrAtEnd(&right) || dlrDocid(&left)<dlrDocid(&right) ){ | |
| 957 dlwAdd(&writer, dlrDocid(&left)); | |
| 958 } | |
| 959 - dlrStep(&left); | |
| 960 + rc = dlrStep(&left); | |
| 961 + if( rc!=SQLITE_OK ) break; | |
| 962 } | |
| 963 | |
| 964 +err: | |
| 965 dlrDestroy(&left); | |
| 966 dlrDestroy(&right); | |
| 967 dlwDestroy(&writer); | |
| 968 + return rc; | |
| 969 } | |
| 970 | |
| 971 static char *string_dup_n(const char *s, int n){ | |
| 972 @@ -1858,7 +2036,7 @@ | |
| 973 /* SEGDIR_MAX_INDEX */ "select max(idx) from %_segdir where level = ?", | |
| 974 /* SEGDIR_SET */ "insert into %_segdir values (?, ?, ?, ?, ?, ?)", | |
| 975 /* SEGDIR_SELECT_LEVEL */ | |
| 976 - "select start_block, leaves_end_block, root from %_segdir " | |
| 977 + "select start_block, leaves_end_block, root, idx from %_segdir " | |
| 978 " where level = ? order by idx", | |
| 979 /* SEGDIR_SPAN */ | |
| 980 "select min(start_block), max(end_block) from %_segdir " | |
| 981 @@ -3680,16 +3858,19 @@ | |
| 982 return SQLITE_OK; | |
| 983 } | |
| 984 rc = sqlite3_bind_int64(c->pStmt, 1, dlrDocid(&c->reader)); | |
| 985 - dlrStep(&c->reader); | |
| 986 if( rc!=SQLITE_OK ) return rc; | |
| 987 + rc = dlrStep(&c->reader); | |
| 988 + if( rc!=SQLITE_OK ) return rc; | |
| 989 /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ | |
| 990 rc = sqlite3_step(c->pStmt); | |
| 991 if( rc==SQLITE_ROW ){ /* the case we expect */ | |
| 992 c->eof = 0; | |
| 993 return SQLITE_OK; | |
| 994 } | |
| 995 - /* an error occurred; abort */ | |
| 996 - return rc==SQLITE_DONE ? SQLITE_ERROR : rc; | |
| 997 + /* Corrupt if the index refers to missing document. */ | |
| 998 + if( rc==SQLITE_DONE ) return SQLITE_CORRUPT_BKPT; | |
| 999 + | |
| 1000 + return rc; | |
| 1001 } | |
| 1002 } | |
| 1003 | |
| 1004 @@ -3739,11 +3920,12 @@ | |
| 1005 if( ii==(pPhrase->nToken-1) ){ | |
| 1006 eType = eListType; | |
| 1007 } | |
| 1008 - docListPhraseMerge( | |
| 1009 + rc = docListPhraseMerge( | |
| 1010 res.pData, res.nData, tmp.pData, tmp.nData, 0, 0, eType, pResult | |
| 1011 ); | |
| 1012 dataBufferDestroy(&res); | |
| 1013 dataBufferDestroy(&tmp); | |
| 1014 + if( rc!= SQLITE_OK ) return rc; | |
| 1015 } | |
| 1016 } | |
| 1017 } | |
| 1018 @@ -3798,21 +3980,21 @@ | |
| 1019 assert( pExpr->pRight->eType==FTSQUERY_PHRASE ); | |
| 1020 assert( pLeft->eType==FTSQUERY_PHRASE ); | |
| 1021 nToken = pLeft->pPhrase->nToken + pExpr->pRight->pPhrase->nToken; | |
| 1022 - docListPhraseMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData, | |
| 1023 + rc = docListPhraseMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData,
| |
| 1024 pExpr->nNear+1, nToken, eType, pRes | |
| 1025 ); | |
| 1026 break; | |
| 1027 } | |
| 1028 case FTSQUERY_NOT: { | |
| 1029 - docListExceptMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData,pRes)
; | |
| 1030 + rc = docListExceptMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData,
pRes); | |
| 1031 break; | |
| 1032 } | |
| 1033 case FTSQUERY_AND: { | |
| 1034 - docListAndMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData, pRes); | |
| 1035 + rc = docListAndMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData, pR
es); | |
| 1036 break; | |
| 1037 } | |
| 1038 case FTSQUERY_OR: { | |
| 1039 - docListOrMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData, pRes); | |
| 1040 + rc = docListOrMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData, pRe
s); | |
| 1041 break; | |
| 1042 } | |
| 1043 } | |
| 1044 @@ -4469,22 +4651,19 @@ | |
| 1045 SCRAMBLE(pReader); | |
| 1046 } | |
| 1047 | |
| 1048 -/* TODO(shess) The assertions are great, but what if we're in NDEBUG | |
| 1049 -** and the blob is empty or otherwise contains suspect data? | |
| 1050 -*/ | |
| 1051 -static void interiorReaderInit(const char *pData, int nData, | |
| 1052 - InteriorReader *pReader){ | |
| 1053 +static int interiorReaderInit(const char *pData, int nData, | |
| 1054 + InteriorReader *pReader){ | |
| 1055 int n, nTerm; | |
| 1056 | |
| 1057 - /* Require at least the leading flag byte */ | |
| 1058 + /* These conditions are checked and met by the callers. */ | |
| 1059 assert( nData>0 ); | |
| 1060 assert( pData[0]!='\0' ); | |
| 1061 | |
| 1062 CLEAR(pReader); | |
| 1063 | |
| 1064 /* Decode the base blockid, and set the cursor to the first term. */ | |
| 1065 - n = fts3GetVarint(pData+1, &pReader->iBlockid); | |
| 1066 - assert( 1+n<=nData ); | |
| 1067 + n = fts3GetVarintSafe(pData+1, &pReader->iBlockid, nData-1); | |
| 1068 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 1069 pReader->pData = pData+1+n; | |
| 1070 pReader->nData = nData-(1+n); | |
| 1071 | |
| 1072 @@ -4495,17 +4674,18 @@ | |
| 1073 if( pReader->nData==0 ){ | |
| 1074 dataBufferInit(&pReader->term, 0); | |
| 1075 }else{ | |
| 1076 - n = fts3GetVarint32(pReader->pData, &nTerm); | |
| 1077 + n = fts3GetVarint32Safe(pReader->pData, &nTerm, pReader->nData); | |
| 1078 + if( !n || nTerm<0 || nTerm>pReader->nData-n) return SQLITE_CORRUPT_BKPT; | |
| 1079 dataBufferInit(&pReader->term, nTerm); | |
| 1080 dataBufferReplace(&pReader->term, pReader->pData+n, nTerm); | |
| 1081 - assert( n+nTerm<=pReader->nData ); | |
| 1082 pReader->pData += n+nTerm; | |
| 1083 pReader->nData -= n+nTerm; | |
| 1084 } | |
| 1085 + return SQLITE_OK; | |
| 1086 } | |
| 1087 | |
| 1088 static int interiorReaderAtEnd(InteriorReader *pReader){ | |
| 1089 - return pReader->term.nData==0; | |
| 1090 + return pReader->term.nData<=0; | |
| 1091 } | |
| 1092 | |
| 1093 static sqlite_int64 interiorReaderCurrentBlockid(InteriorReader *pReader){ | |
| 1094 @@ -4522,7 +4702,7 @@ | |
| 1095 } | |
| 1096 | |
| 1097 /* Step forward to the next term in the node. */ | |
| 1098 -static void interiorReaderStep(InteriorReader *pReader){ | |
| 1099 +static int interiorReaderStep(InteriorReader *pReader){ | |
| 1100 assert( !interiorReaderAtEnd(pReader) ); | |
| 1101 | |
| 1102 /* If the last term has been read, signal eof, else construct the | |
| 1103 @@ -4533,18 +4713,26 @@ | |
| 1104 }else{ | |
| 1105 int n, nPrefix, nSuffix; | |
| 1106 | |
| 1107 - n = fts3GetVarint32(pReader->pData, &nPrefix); | |
| 1108 - n += fts3GetVarint32(pReader->pData+n, &nSuffix); | |
| 1109 + n = fts3GetVarint32Safe(pReader->pData, &nPrefix, pReader->nData); | |
| 1110 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 1111 + pReader->nData -= n; | |
| 1112 + pReader->pData += n; | |
| 1113 + n = fts3GetVarint32Safe(pReader->pData, &nSuffix, pReader->nData); | |
| 1114 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 1115 + pReader->nData -= n; | |
| 1116 + pReader->pData += n; | |
| 1117 + if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT; | |
| 1118 + if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT; | |
| 1119 | |
| 1120 /* Truncate the current term and append suffix data. */ | |
| 1121 pReader->term.nData = nPrefix; | |
| 1122 - dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); | |
| 1123 + dataBufferAppend(&pReader->term, pReader->pData, nSuffix); | |
| 1124 | |
| 1125 - assert( n+nSuffix<=pReader->nData ); | |
| 1126 - pReader->pData += n+nSuffix; | |
| 1127 - pReader->nData -= n+nSuffix; | |
| 1128 + pReader->pData += nSuffix; | |
| 1129 + pReader->nData -= nSuffix; | |
| 1130 } | |
| 1131 pReader->iBlockid++; | |
| 1132 + return SQLITE_OK; | |
| 1133 } | |
| 1134 | |
| 1135 /* Compare the current term to pTerm[nTerm], returning strcmp-style | |
| 1136 @@ -4916,7 +5104,8 @@ | |
| 1137 n = fts3PutVarint(c, nData); | |
| 1138 dataBufferAppend(&pWriter->data, c, n); | |
| 1139 | |
| 1140 - docListMerge(&pWriter->data, pReaders, nReaders); | |
| 1141 + rc = docListMerge(&pWriter->data, pReaders, nReaders); | |
| 1142 + if( rc!=SQLITE_OK ) return rc; | |
| 1143 ASSERT_VALID_DOCLIST(DL_DEFAULT, | |
| 1144 pWriter->data.pData+iDoclistData+n, | |
| 1145 pWriter->data.nData-iDoclistData-n, NULL); | |
| 1146 @@ -5026,7 +5215,8 @@ | |
| 1147 int rc; | |
| 1148 DLReader reader; | |
| 1149 | |
| 1150 - dlrInit(&reader, DL_DEFAULT, pData, nData); | |
| 1151 + rc = dlrInit(&reader, DL_DEFAULT, pData, nData); | |
| 1152 + if( rc!=SQLITE_OK ) return rc; | |
| 1153 rc = leafWriterStepMerge(v, pWriter, pTerm, nTerm, &reader, 1); | |
| 1154 dlrDestroy(&reader); | |
| 1155 | |
| 1156 @@ -5071,38 +5261,41 @@ | |
| 1157 static const char *leafReaderData(LeafReader *pReader){ | |
| 1158 int n, nData; | |
| 1159 assert( pReader->term.nData>0 ); | |
| 1160 - n = fts3GetVarint32(pReader->pData, &nData); | |
| 1161 + n = fts3GetVarint32Safe(pReader->pData, &nData, pReader->nData); | |
| 1162 + if( !n || nData>pReader->nData-n ) return NULL; | |
| 1163 return pReader->pData+n; | |
| 1164 } | |
| 1165 | |
| 1166 -static void leafReaderInit(const char *pData, int nData, | |
| 1167 - LeafReader *pReader){ | |
| 1168 +static int leafReaderInit(const char *pData, int nData, | |
| 1169 + LeafReader *pReader){ | |
| 1170 int nTerm, n; | |
| 1171 | |
| 1172 + /* All callers check this precondition. */ | |
| 1173 assert( nData>0 ); | |
| 1174 assert( pData[0]=='\0' ); | |
| 1175 | |
| 1176 CLEAR(pReader); | |
| 1177 | |
| 1178 /* Read the first term, skipping the header byte. */ | |
| 1179 - n = fts3GetVarint32(pData+1, &nTerm); | |
| 1180 + n = fts3GetVarint32Safe(pData+1, &nTerm, nData-1); | |
| 1181 + if( !n || nTerm<0 || nTerm>nData-1-n ) return SQLITE_CORRUPT_BKPT; | |
| 1182 dataBufferInit(&pReader->term, nTerm); | |
| 1183 dataBufferReplace(&pReader->term, pData+1+n, nTerm); | |
| 1184 | |
| 1185 /* Position after the first term. */ | |
| 1186 - assert( 1+n+nTerm<nData ); | |
| 1187 pReader->pData = pData+1+n+nTerm; | |
| 1188 pReader->nData = nData-1-n-nTerm; | |
| 1189 + return SQLITE_OK; | |
| 1190 } | |
| 1191 | |
| 1192 /* Step the reader forward to the next term. */ | |
| 1193 -static void leafReaderStep(LeafReader *pReader){ | |
| 1194 +static int leafReaderStep(LeafReader *pReader){ | |
| 1195 int n, nData, nPrefix, nSuffix; | |
| 1196 assert( !leafReaderAtEnd(pReader) ); | |
| 1197 | |
| 1198 /* Skip previous entry's data block. */ | |
| 1199 - n = fts3GetVarint32(pReader->pData, &nData); | |
| 1200 - assert( n+nData<=pReader->nData ); | |
| 1201 + n = fts3GetVarint32Safe(pReader->pData, &nData, pReader->nData); | |
| 1202 + if( !n || nData<0 || nData>pReader->nData-n ) return SQLITE_CORRUPT_BKPT; | |
| 1203 pReader->pData += n+nData; | |
| 1204 pReader->nData -= n+nData; | |
| 1205 | |
| 1206 @@ -5110,15 +5303,23 @@ | |
| 1207 /* Construct the new term using a prefix from the old term plus a | |
| 1208 ** suffix from the leaf data. | |
| 1209 */ | |
| 1210 - n = fts3GetVarint32(pReader->pData, &nPrefix); | |
| 1211 - n += fts3GetVarint32(pReader->pData+n, &nSuffix); | |
| 1212 - assert( n+nSuffix<pReader->nData ); | |
| 1213 + n = fts3GetVarint32Safe(pReader->pData, &nPrefix, pReader->nData); | |
| 1214 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 1215 + pReader->nData -= n; | |
| 1216 + pReader->pData += n; | |
| 1217 + n = fts3GetVarint32Safe(pReader->pData, &nSuffix, pReader->nData); | |
| 1218 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
| 1219 + pReader->nData -= n; | |
| 1220 + pReader->pData += n; | |
| 1221 + if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT; | |
| 1222 + if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT; | |
| 1223 pReader->term.nData = nPrefix; | |
| 1224 - dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); | |
| 1225 + dataBufferAppend(&pReader->term, pReader->pData, nSuffix); | |
| 1226 | |
| 1227 - pReader->pData += n+nSuffix; | |
| 1228 - pReader->nData -= n+nSuffix; | |
| 1229 + pReader->pData += nSuffix; | |
| 1230 + pReader->nData -= nSuffix; | |
| 1231 } | |
| 1232 + return SQLITE_OK; | |
| 1233 } | |
| 1234 | |
| 1235 /* strcmp-style comparison of pReader's current term against pTerm. | |
| 1236 @@ -5222,32 +5423,67 @@ | |
| 1237 | |
| 1238 dataBufferInit(&pReader->rootData, 0); | |
| 1239 if( iStartBlockid==0 ){ | |
| 1240 + int rc; | |
| 1241 + /* Corrupt if this can't be a leaf node. */ | |
| 1242 + if( pRootData==NULL || nRootData<1 || pRootData[0]!='\0' ){ | |
| 1243 + return SQLITE_CORRUPT_BKPT; | |
| 1244 + } | |
| 1245 /* Entire leaf level fit in root data. */ | |
| 1246 dataBufferReplace(&pReader->rootData, pRootData, nRootData); | |
| 1247 - leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, | |
| 1248 - &pReader->leafReader); | |
| 1249 + rc = leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, | |
| 1250 + &pReader->leafReader); | |
| 1251 + if( rc!=SQLITE_OK ){ | |
| 1252 + dataBufferDestroy(&pReader->rootData); | |
| 1253 + return rc; | |
| 1254 + } | |
| 1255 }else{ | |
| 1256 sqlite3_stmt *s; | |
| 1257 int rc = sql_get_leaf_statement(v, idx, &s); | |
| 1258 if( rc!=SQLITE_OK ) return rc; | |
| 1259 | |
| 1260 rc = sqlite3_bind_int64(s, 1, iStartBlockid); | |
| 1261 - if( rc!=SQLITE_OK ) return rc; | |
| 1262 + if( rc!=SQLITE_OK ) goto err; | |
| 1263 | |
| 1264 rc = sqlite3_bind_int64(s, 2, iEndBlockid); | |
| 1265 - if( rc!=SQLITE_OK ) return rc; | |
| 1266 + if( rc!=SQLITE_OK ) goto err; | |
| 1267 | |
| 1268 rc = sqlite3_step(s); | |
| 1269 + | |
| 1270 + /* Corrupt if interior node referenced missing leaf node. */ | |
| 1271 if( rc==SQLITE_DONE ){ | |
| 1272 - pReader->eof = 1; | |
| 1273 - return SQLITE_OK; | |
| 1274 + rc = SQLITE_CORRUPT_BKPT; | |
| 1275 + goto err; | |
| 1276 } | |
| 1277 - if( rc!=SQLITE_ROW ) return rc; | |
| 1278 | |
| 1279 + if( rc!=SQLITE_ROW ) goto err; | |
| 1280 + rc = SQLITE_OK; | |
| 1281 + | |
| 1282 + /* Corrupt if leaf data isn't a blob. */ | |
| 1283 + if( sqlite3_column_type(s, 0)!=SQLITE_BLOB ){ | |
| 1284 + rc = SQLITE_CORRUPT_BKPT; | |
| 1285 + }else{ | |
| 1286 + const char *pLeafData = sqlite3_column_blob(s, 0); | |
| 1287 + int nLeafData = sqlite3_column_bytes(s, 0); | |
| 1288 + | |
| 1289 + /* Corrupt if this can't be a leaf node. */ | |
| 1290 + if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ | |
| 1291 + rc = SQLITE_CORRUPT_BKPT; | |
| 1292 + }else{ | |
| 1293 + rc = leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); | |
| 1294 + } | |
| 1295 + } | |
| 1296 + | |
| 1297 + err: | |
| 1298 + if( rc!=SQLITE_OK ){ | |
| 1299 + if( idx==-1 ){ | |
| 1300 + sqlite3_finalize(s); | |
| 1301 + }else{ | |
| 1302 + sqlite3_reset(s); | |
| 1303 + } | |
| 1304 + return rc; | |
| 1305 + } | |
| 1306 + | |
| 1307 pReader->pStmt = s; | |
| 1308 - leafReaderInit(sqlite3_column_blob(pReader->pStmt, 0), | |
| 1309 - sqlite3_column_bytes(pReader->pStmt, 0), | |
| 1310 - &pReader->leafReader); | |
| 1311 } | |
| 1312 return SQLITE_OK; | |
| 1313 } | |
| 1314 @@ -5256,11 +5492,12 @@ | |
| 1315 ** end of the current leaf, step forward to the next leaf block. | |
| 1316 */ | |
| 1317 static int leavesReaderStep(fulltext_vtab *v, LeavesReader *pReader){ | |
| 1318 + int rc; | |
| 1319 assert( !leavesReaderAtEnd(pReader) ); | |
| 1320 - leafReaderStep(&pReader->leafReader); | |
| 1321 + rc = leafReaderStep(&pReader->leafReader); | |
| 1322 + if( rc!=SQLITE_OK ) return rc; | |
| 1323 | |
| 1324 if( leafReaderAtEnd(&pReader->leafReader) ){ | |
| 1325 - int rc; | |
| 1326 if( pReader->rootData.pData ){ | |
| 1327 pReader->eof = 1; | |
| 1328 return SQLITE_OK; | |
| 1329 @@ -5270,10 +5507,25 @@ | |
| 1330 pReader->eof = 1; | |
| 1331 return rc==SQLITE_DONE ? SQLITE_OK : rc; | |
| 1332 } | |
| 1333 - leafReaderDestroy(&pReader->leafReader); | |
| 1334 - leafReaderInit(sqlite3_column_blob(pReader->pStmt, 0), | |
| 1335 - sqlite3_column_bytes(pReader->pStmt, 0), | |
| 1336 - &pReader->leafReader); | |
| 1337 + | |
| 1338 + /* Corrupt if leaf data isn't a blob. */ | |
| 1339 + if( sqlite3_column_type(pReader->pStmt, 0)!=SQLITE_BLOB ){ | |
| 1340 + return SQLITE_CORRUPT_BKPT; | |
| 1341 + }else{ | |
| 1342 + LeafReader tmp; | |
| 1343 + const char *pLeafData = sqlite3_column_blob(pReader->pStmt, 0); | |
| 1344 + int nLeafData = sqlite3_column_bytes(pReader->pStmt, 0); | |
| 1345 + | |
| 1346 + /* Corrupt if this can't be a leaf node. */ | |
| 1347 + if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ | |
| 1348 + return SQLITE_CORRUPT_BKPT; | |
| 1349 + } | |
| 1350 + | |
| 1351 + rc = leafReaderInit(pLeafData, nLeafData, &tmp); | |
| 1352 + if( rc!=SQLITE_OK ) return rc; | |
| 1353 + leafReaderDestroy(&pReader->leafReader); | |
| 1354 + pReader->leafReader = tmp; | |
| 1355 + } | |
| 1356 } | |
| 1357 return SQLITE_OK; | |
| 1358 } | |
| 1359 @@ -5334,8 +5586,19 @@ | |
| 1360 sqlite_int64 iEnd = sqlite3_column_int64(s, 1); | |
| 1361 const char *pRootData = sqlite3_column_blob(s, 2); | |
| 1362 int nRootData = sqlite3_column_bytes(s, 2); | |
| 1363 + sqlite_int64 iIndex = sqlite3_column_int64(s, 3); | |
| 1364 | |
| 1365 - assert( i<MERGE_COUNT ); | |
| 1366 + /* Corrupt if we get back different types than we stored. */ | |
| 1367 + /* Also corrupt if the index is not sequential starting at 0. */ | |
| 1368 + if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER || | |
| 1369 + sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
| 1370 + sqlite3_column_type(s, 2)!=SQLITE_BLOB || | |
| 1371 + i!=iIndex || | |
| 1372 + i>=MERGE_COUNT ){ | |
| 1373 + rc = SQLITE_CORRUPT_BKPT; | |
| 1374 + break; | |
| 1375 + } | |
| 1376 + | |
| 1377 rc = leavesReaderInit(v, i, iStart, iEnd, pRootData, nRootData, | |
| 1378 &pReaders[i]); | |
| 1379 if( rc!=SQLITE_OK ) break; | |
| 1380 @@ -5346,6 +5609,7 @@ | |
| 1381 while( i-->0 ){ | |
| 1382 leavesReaderDestroy(&pReaders[i]); | |
| 1383 } | |
| 1384 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
| 1385 return rc; | |
| 1386 } | |
| 1387 | |
| 1388 @@ -5369,14 +5633,27 @@ | |
| 1389 DLReader dlReaders[MERGE_COUNT]; | |
| 1390 const char *pTerm = leavesReaderTerm(pReaders); | |
| 1391 int i, nTerm = leavesReaderTermBytes(pReaders); | |
| 1392 + int rc; | |
| 1393 | |
| 1394 assert( nReaders<=MERGE_COUNT ); | |
| 1395 | |
| 1396 for(i=0; i<nReaders; i++){ | |
| 1397 - dlrInit(&dlReaders[i], DL_DEFAULT, | |
| 1398 - leavesReaderData(pReaders+i), | |
| 1399 - leavesReaderDataBytes(pReaders+i)); | |
| 1400 + const char *pData = leavesReaderData(pReaders+i); | |
| 1401 + if( pData==NULL ){ | |
| 1402 + rc = SQLITE_CORRUPT_BKPT; | |
| 1403 + break; | |
| 1404 + } | |
| 1405 + rc = dlrInit(&dlReaders[i], DL_DEFAULT, | |
| 1406 + pData, | |
| 1407 + leavesReaderDataBytes(pReaders+i)); | |
| 1408 + if( rc!=SQLITE_OK ) break; | |
| 1409 } | |
| 1410 + if( rc!=SQLITE_OK ){ | |
| 1411 + while( i-->0 ){ | |
| 1412 + dlrDestroy(&dlReaders[i]); | |
| 1413 + } | |
| 1414 + return rc; | |
| 1415 + } | |
| 1416 | |
| 1417 return leafWriterStepMerge(v, pWriter, pTerm, nTerm, dlReaders, nReaders); | |
| 1418 } | |
| 1419 @@ -5429,10 +5706,14 @@ | |
| 1420 memset(&lrs, '\0', sizeof(lrs)); | |
| 1421 rc = leavesReadersInit(v, iLevel, lrs, &i); | |
| 1422 if( rc!=SQLITE_OK ) return rc; | |
| 1423 - assert( i==MERGE_COUNT ); | |
| 1424 | |
| 1425 leafWriterInit(iLevel+1, idx, &writer); | |
| 1426 | |
| 1427 + if( i!=MERGE_COUNT ){ | |
| 1428 + rc = SQLITE_CORRUPT_BKPT; | |
| 1429 + goto err; | |
| 1430 + } | |
| 1431 + | |
| 1432 /* Since leavesReaderReorder() pushes readers at eof to the end, | |
| 1433 ** when the first reader is empty, all will be empty. | |
| 1434 */ | |
| 1435 @@ -5475,12 +5756,14 @@ | |
| 1436 } | |
| 1437 | |
| 1438 /* Accumulate the union of *acc and *pData into *acc. */ | |
| 1439 -static void docListAccumulateUnion(DataBuffer *acc, | |
| 1440 - const char *pData, int nData) { | |
| 1441 +static int docListAccumulateUnion(DataBuffer *acc, | |
| 1442 + const char *pData, int nData) { | |
| 1443 DataBuffer tmp = *acc; | |
| 1444 + int rc; | |
| 1445 dataBufferInit(acc, tmp.nData+nData); | |
| 1446 - docListUnion(tmp.pData, tmp.nData, pData, nData, acc); | |
| 1447 + rc = docListUnion(tmp.pData, tmp.nData, pData, nData, acc); | |
| 1448 dataBufferDestroy(&tmp); | |
| 1449 + return rc; | |
| 1450 } | |
| 1451 | |
| 1452 /* TODO(shess) It might be interesting to explore different merge | |
| 1453 @@ -5522,8 +5805,13 @@ | |
| 1454 int c = leafReaderTermCmp(&pReader->leafReader, pTerm, nTerm, isPrefix); | |
| 1455 if( c>0 ) break; /* Past any possible matches. */ | |
| 1456 if( c==0 ){ | |
| 1457 + int iBuffer, nData; | |
| 1458 const char *pData = leavesReaderData(pReader); | |
| 1459 - int iBuffer, nData = leavesReaderDataBytes(pReader); | |
| 1460 + if( pData==NULL ){ | |
| 1461 + rc = SQLITE_CORRUPT_BKPT; | |
| 1462 + break; | |
| 1463 + } | |
| 1464 + nData = leavesReaderDataBytes(pReader); | |
| 1465 | |
| 1466 /* Find the first empty buffer. */ | |
| 1467 for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){ | |
| 1468 @@ -5569,11 +5857,13 @@ | |
| 1469 ** with pData/nData. | |
| 1470 */ | |
| 1471 dataBufferSwap(p, pAcc); | |
| 1472 - docListAccumulateUnion(pAcc, pData, nData); | |
| 1473 + rc = docListAccumulateUnion(pAcc, pData, nData); | |
| 1474 + if( rc!=SQLITE_OK ) goto err; | |
| 1475 | |
| 1476 /* Accumulate remaining doclists into pAcc. */ | |
| 1477 for(++p; p<pAcc; ++p){ | |
| 1478 - docListAccumulateUnion(pAcc, p->pData, p->nData); | |
| 1479 + rc = docListAccumulateUnion(pAcc, p->pData, p->nData); | |
| 1480 + if( rc!=SQLITE_OK ) goto err; | |
| 1481 | |
| 1482 /* dataBufferReset() could allow a large doclist to blow up | |
| 1483 ** our memory requirements. | |
| 1484 @@ -5598,13 +5888,15 @@ | |
| 1485 if( out->nData==0 ){ | |
| 1486 dataBufferSwap(out, &(pBuffers[iBuffer])); | |
| 1487 }else{ | |
| 1488 - docListAccumulateUnion(out, pBuffers[iBuffer].pData, | |
| 1489 - pBuffers[iBuffer].nData); | |
| 1490 + rc = docListAccumulateUnion(out, pBuffers[iBuffer].pData, | |
| 1491 + pBuffers[iBuffer].nData); | |
| 1492 + if( rc!=SQLITE_OK ) break; | |
| 1493 } | |
| 1494 } | |
| 1495 } | |
| 1496 } | |
| 1497 | |
| 1498 +err: | |
| 1499 while( nBuffers-- ){ | |
| 1500 dataBufferDestroy(&(pBuffers[nBuffers])); | |
| 1501 } | |
| 1502 @@ -5663,20 +5955,26 @@ | |
| 1503 ** node. Consider whether breaking symmetry is worthwhile. I suspect | |
| 1504 ** it is not worthwhile. | |
| 1505 */ | |
| 1506 -static void getChildrenContaining(const char *pData, int nData, | |
| 1507 - const char *pTerm, int nTerm, int isPrefix, | |
| 1508 - sqlite_int64 *piStartChild, | |
| 1509 - sqlite_int64 *piEndChild){ | |
| 1510 +static int getChildrenContaining(const char *pData, int nData, | |
| 1511 + const char *pTerm, int nTerm, int isPrefix, | |
| 1512 + sqlite_int64 *piStartChild, | |
| 1513 + sqlite_int64 *piEndChild){ | |
| 1514 InteriorReader reader; | |
| 1515 + int rc; | |
| 1516 | |
| 1517 assert( nData>1 ); | |
| 1518 assert( *pData!='\0' ); | |
| 1519 - interiorReaderInit(pData, nData, &reader); | |
| 1520 + rc = interiorReaderInit(pData, nData, &reader); | |
| 1521 + if( rc!=SQLITE_OK ) return rc; | |
| 1522 | |
| 1523 /* Scan for the first child which could contain pTerm/nTerm. */ | |
| 1524 while( !interiorReaderAtEnd(&reader) ){ | |
| 1525 if( interiorReaderTermCmp(&reader, pTerm, nTerm, 0)>0 ) break; | |
| 1526 - interiorReaderStep(&reader); | |
| 1527 + rc = interiorReaderStep(&reader); | |
| 1528 + if( rc!=SQLITE_OK ){ | |
| 1529 + interiorReaderDestroy(&reader); | |
| 1530 + return rc; | |
| 1531 + } | |
| 1532 } | |
| 1533 *piStartChild = interiorReaderCurrentBlockid(&reader); | |
| 1534 | |
| 1535 @@ -5686,7 +5984,11 @@ | |
| 1536 */ | |
| 1537 while( !interiorReaderAtEnd(&reader) ){ | |
| 1538 if( interiorReaderTermCmp(&reader, pTerm, nTerm, isPrefix)>0 ) break; | |
| 1539 - interiorReaderStep(&reader); | |
| 1540 + rc = interiorReaderStep(&reader); | |
| 1541 + if( rc!=SQLITE_OK ){ | |
| 1542 + interiorReaderDestroy(&reader); | |
| 1543 + return rc; | |
| 1544 + } | |
| 1545 } | |
| 1546 *piEndChild = interiorReaderCurrentBlockid(&reader); | |
| 1547 | |
| 1548 @@ -5695,6 +5997,7 @@ | |
| 1549 /* Children must ascend, and if !prefix, both must be the same. */ | |
| 1550 assert( *piEndChild>=*piStartChild ); | |
| 1551 assert( isPrefix || *piStartChild==*piEndChild ); | |
| 1552 + return rc; | |
| 1553 } | |
| 1554 | |
| 1555 /* Read block at iBlockid and pass it with other params to | |
| 1556 @@ -5722,12 +6025,32 @@ | |
| 1557 if( rc!=SQLITE_OK ) return rc; | |
| 1558 | |
| 1559 rc = sqlite3_step(s); | |
| 1560 - if( rc==SQLITE_DONE ) return SQLITE_ERROR; | |
| 1561 + /* Corrupt if interior node references missing child node. */ | |
| 1562 + if( rc==SQLITE_DONE ) return SQLITE_CORRUPT_BKPT; | |
| 1563 if( rc!=SQLITE_ROW ) return rc; | |
| 1564 | |
| 1565 - getChildrenContaining(sqlite3_column_blob(s, 0), sqlite3_column_bytes(s, 0), | |
| 1566 - pTerm, nTerm, isPrefix, piStartChild, piEndChild); | |
| 1567 + /* Corrupt if child node isn't a blob. */ | |
| 1568 + if( sqlite3_column_type(s, 0)!=SQLITE_BLOB ){ | |
| 1569 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
| 1570 + return SQLITE_CORRUPT_BKPT; | |
| 1571 + }else{ | |
| 1572 + const char *pData = sqlite3_column_blob(s, 0); | |
| 1573 + int nData = sqlite3_column_bytes(s, 0); | |
| 1574 | |
| 1575 + /* Corrupt if child is not a valid interior node. */ | |
| 1576 + if( pData==NULL || nData<1 || pData[0]=='\0' ){ | |
| 1577 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
| 1578 + return SQLITE_CORRUPT_BKPT; | |
| 1579 + } | |
| 1580 + | |
| 1581 + rc = getChildrenContaining(pData, nData, pTerm, nTerm, | |
| 1582 + isPrefix, piStartChild, piEndChild); | |
| 1583 + if( rc!=SQLITE_OK ){ | |
| 1584 + sqlite3_reset(s); | |
| 1585 + return rc; | |
| 1586 + } | |
| 1587 + } | |
| 1588 + | |
| 1589 /* We expect only one row. We must execute another sqlite3_step() | |
| 1590 * to complete the iteration; otherwise the table will remain | |
| 1591 * locked. */ | |
| 1592 @@ -5756,8 +6079,9 @@ | |
| 1593 /* Process pData as an interior node, then loop down the tree | |
| 1594 ** until we find the set of leaf nodes to scan for the term. | |
| 1595 */ | |
| 1596 - getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, | |
| 1597 - &iStartChild, &iEndChild); | |
| 1598 + rc = getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, | |
| 1599 + &iStartChild, &iEndChild); | |
| 1600 + if( rc!=SQLITE_OK ) return rc; | |
| 1601 while( iStartChild>iLeavesEnd ){ | |
| 1602 sqlite_int64 iNextStart, iNextEnd; | |
| 1603 rc = loadAndGetChildrenContaining(v, iStartChild, pTerm, nTerm, isPrefix, | |
| 1604 @@ -5809,7 +6133,8 @@ | |
| 1605 DataBuffer result; | |
| 1606 int rc; | |
| 1607 | |
| 1608 - assert( nData>1 ); | |
| 1609 + /* Corrupt if segment root can't be valid. */ | |
| 1610 + if( pData==NULL || nData<1 ) return SQLITE_CORRUPT_BKPT; | |
| 1611 | |
| 1612 /* This code should never be called with buffered updates. */ | |
| 1613 assert( v->nPendingData<0 ); | |
| 1614 @@ -5826,16 +6151,21 @@ | |
| 1615 DataBuffer merged; | |
| 1616 DLReader readers[2]; | |
| 1617 | |
| 1618 - dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); | |
| 1619 - dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); | |
| 1620 - dataBufferInit(&merged, out->nData+result.nData); | |
| 1621 - docListMerge(&merged, readers, 2); | |
| 1622 - dataBufferDestroy(out); | |
| 1623 - *out = merged; | |
| 1624 - dlrDestroy(&readers[0]); | |
| 1625 - dlrDestroy(&readers[1]); | |
| 1626 + rc = dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); | |
| 1627 + if( rc==SQLITE_OK ){ | |
| 1628 + rc = dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); | |
| 1629 + if( rc==SQLITE_OK ){ | |
| 1630 + dataBufferInit(&merged, out->nData+result.nData); | |
| 1631 + rc = docListMerge(&merged, readers, 2); | |
| 1632 + dataBufferDestroy(out); | |
| 1633 + *out = merged; | |
| 1634 + dlrDestroy(&readers[1]); | |
| 1635 + } | |
| 1636 + dlrDestroy(&readers[0]); | |
| 1637 + } | |
| 1638 } | |
| 1639 } | |
| 1640 + | |
| 1641 dataBufferDestroy(&result); | |
| 1642 return rc; | |
| 1643 } | |
| 1644 @@ -5869,11 +6199,20 @@ | |
| 1645 const char *pData = sqlite3_column_blob(s, 2); | |
| 1646 const int nData = sqlite3_column_bytes(s, 2); | |
| 1647 const sqlite_int64 iLeavesEnd = sqlite3_column_int64(s, 1); | |
| 1648 + | |
| 1649 + /* Corrupt if we get back different types than we stored. */ | |
| 1650 + if( sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
| 1651 + sqlite3_column_type(s, 2)!=SQLITE_BLOB ){ | |
| 1652 + rc = SQLITE_CORRUPT_BKPT; | |
| 1653 + goto err; | |
| 1654 + } | |
| 1655 + | |
| 1656 rc = loadSegment(v, pData, nData, iLeavesEnd, pTerm, nTerm, isPrefix, | |
| 1657 &doclist); | |
| 1658 if( rc!=SQLITE_OK ) goto err; | |
| 1659 } | |
| 1660 if( rc==SQLITE_DONE ){ | |
| 1661 + rc = SQLITE_OK; | |
| 1662 if( doclist.nData!=0 ){ | |
| 1663 /* TODO(shess) The old term_select_all() code applied the column | |
| 1664 ** restrict as we merged segments, leading to smaller buffers. | |
| 1665 @@ -5881,13 +6220,13 @@ | |
| 1666 ** system is checked in. | |
| 1667 */ | |
| 1668 if( iColumn==v->nColumn) iColumn = -1; | |
| 1669 - docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
| 1670 - iColumn, iType, out); | |
| 1671 + rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
| 1672 + iColumn, iType, out); | |
| 1673 } | |
| 1674 - rc = SQLITE_OK; | |
| 1675 } | |
| 1676 | |
| 1677 err: | |
| 1678 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
| 1679 dataBufferDestroy(&doclist); | |
| 1680 return rc; | |
| 1681 } | |
| 1682 @@ -6250,6 +6589,7 @@ | |
| 1683 LeafWriter *pWriter){ | |
| 1684 int i, rc = SQLITE_OK; | |
| 1685 DataBuffer doclist, merged, tmp; | |
| 1686 + const char *pData; | |
| 1687 | |
| 1688 /* Order the readers. */ | |
| 1689 i = nReaders; | |
| 1690 @@ -6270,14 +6610,20 @@ | |
| 1691 if( 0!=optLeavesReaderTermCmp(&readers[0], &readers[i]) ) break; | |
| 1692 } | |
| 1693 | |
| 1694 + pData = optLeavesReaderData(&readers[0]); | |
| 1695 + if( pData==NULL ){ | |
| 1696 + rc = SQLITE_CORRUPT_BKPT; | |
| 1697 + break; | |
| 1698 + } | |
| 1699 + | |
| 1700 /* Special-case for no merge. */ | |
| 1701 if( i==1 ){ | |
| 1702 /* Trim deletions from the doclist. */ | |
| 1703 dataBufferReset(&merged); | |
| 1704 - docListTrim(DL_DEFAULT, | |
| 1705 - optLeavesReaderData(&readers[0]), | |
| 1706 - optLeavesReaderDataBytes(&readers[0]), | |
| 1707 - -1, DL_DEFAULT, &merged); | |
| 1708 + rc = docListTrim(DL_DEFAULT, pData, | |
| 1709 + optLeavesReaderDataBytes(&readers[0]), | |
| 1710 + -1, DL_DEFAULT, &merged); | |
| 1711 + if( rc!=SQLITE_OK ) break; | |
| 1712 }else{ | |
| 1713 DLReader dlReaders[MERGE_COUNT]; | |
| 1714 int iReader, nReaders; | |
| 1715 @@ -6285,9 +6631,10 @@ | |
| 1716 /* Prime the pipeline with the first reader's doclist. After | |
| 1717 ** one pass index 0 will reference the accumulated doclist. | |
| 1718 */ | |
| 1719 - dlrInit(&dlReaders[0], DL_DEFAULT, | |
| 1720 - optLeavesReaderData(&readers[0]), | |
| 1721 - optLeavesReaderDataBytes(&readers[0])); | |
| 1722 + rc = dlrInit(&dlReaders[0], DL_DEFAULT, | |
| 1723 + pData, | |
| 1724 + optLeavesReaderDataBytes(&readers[0])); | |
| 1725 + if( rc!=SQLITE_OK ) break; | |
| 1726 iReader = 1; | |
| 1727 | |
| 1728 assert( iReader<i ); /* Must execute the loop at least once. */ | |
| 1729 @@ -6295,24 +6642,34 @@ | |
| 1730 /* Merge 16 inputs per pass. */ | |
| 1731 for( nReaders=1; iReader<i && nReaders<MERGE_COUNT; | |
| 1732 iReader++, nReaders++ ){ | |
| 1733 - dlrInit(&dlReaders[nReaders], DL_DEFAULT, | |
| 1734 - optLeavesReaderData(&readers[iReader]), | |
| 1735 - optLeavesReaderDataBytes(&readers[iReader])); | |
| 1736 + pData = optLeavesReaderData(&readers[iReader]); | |
| 1737 + if( pData==NULL ){ | |
| 1738 + rc = SQLITE_CORRUPT_BKPT; | |
| 1739 + break; | |
| 1740 + } | |
| 1741 + rc = dlrInit(&dlReaders[nReaders], DL_DEFAULT, pData, | |
| 1742 + optLeavesReaderDataBytes(&readers[iReader])); | |
| 1743 + if( rc!=SQLITE_OK ) break; | |
| 1744 } | |
| 1745 | |
| 1746 /* Merge doclists and swap result into accumulator. */ | |
| 1747 - dataBufferReset(&merged); | |
| 1748 - docListMerge(&merged, dlReaders, nReaders); | |
| 1749 - tmp = merged; | |
| 1750 - merged = doclist; | |
| 1751 - doclist = tmp; | |
| 1752 + if( rc==SQLITE_OK ){ | |
| 1753 + dataBufferReset(&merged); | |
| 1754 + rc = docListMerge(&merged, dlReaders, nReaders); | |
| 1755 + tmp = merged; | |
| 1756 + merged = doclist; | |
| 1757 + doclist = tmp; | |
| 1758 + } | |
| 1759 | |
| 1760 while( nReaders-- > 0 ){ | |
| 1761 dlrDestroy(&dlReaders[nReaders]); | |
| 1762 } | |
| 1763 | |
| 1764 + if( rc!=SQLITE_OK ) goto err; | |
| 1765 + | |
| 1766 /* Accumulated doclist to reader 0 for next pass. */ | |
| 1767 - dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); | |
| 1768 + rc = dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); | |
| 1769 + if( rc!=SQLITE_OK ) goto err; | |
| 1770 } | |
| 1771 | |
| 1772 /* Destroy reader that was left in the pipeline. */ | |
| 1773 @@ -6320,8 +6677,9 @@ | |
| 1774 | |
| 1775 /* Trim deletions from the doclist. */ | |
| 1776 dataBufferReset(&merged); | |
| 1777 - docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
| 1778 - -1, DL_DEFAULT, &merged); | |
| 1779 + rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
| 1780 + -1, DL_DEFAULT, &merged); | |
| 1781 + if( rc!=SQLITE_OK ) goto err; | |
| 1782 } | |
| 1783 | |
| 1784 /* Only pass doclists with hits (skip if all hits deleted). */ | |
| 1785 @@ -6401,6 +6759,14 @@ | |
| 1786 const char *pRootData = sqlite3_column_blob(s, 2); | |
| 1787 int nRootData = sqlite3_column_bytes(s, 2); | |
| 1788 | |
| 1789 + /* Corrupt if we get back different types than we stored. */ | |
| 1790 + if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER || | |
| 1791 + sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
| 1792 + sqlite3_column_type(s, 2)!=SQLITE_BLOB ){ | |
| 1793 + rc = SQLITE_CORRUPT_BKPT; | |
| 1794 + break; | |
| 1795 + } | |
| 1796 + | |
| 1797 assert( i<nReaders ); | |
| 1798 rc = leavesReaderInit(v, -1, iStart, iEnd, pRootData, nRootData, | |
| 1799 &readers[i].reader); | |
| 1800 @@ -6414,6 +6780,8 @@ | |
| 1801 if( rc==SQLITE_DONE ){ | |
| 1802 assert( i==nReaders ); | |
| 1803 rc = optimizeInternal(v, readers, nReaders, &writer); | |
| 1804 + }else{ | |
| 1805 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
| 1806 } | |
| 1807 | |
| 1808 while( i-- > 0 ){ | |
| 1809 @@ -6477,9 +6845,18 @@ | |
| 1810 const sqlite_int64 iEndBlockid = sqlite3_column_int64(s, 1); | |
| 1811 const char *pRootData = sqlite3_column_blob(s, 2); | |
| 1812 const int nRootData = sqlite3_column_bytes(s, 2); | |
| 1813 + int rc; | |
| 1814 LeavesReader reader; | |
| 1815 - int rc = leavesReaderInit(v, 0, iStartBlockid, iEndBlockid, | |
| 1816 - pRootData, nRootData, &reader); | |
| 1817 + | |
| 1818 + /* Corrupt if we get back different types than we stored. */ | |
| 1819 + if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER || | |
| 1820 + sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
| 1821 + sqlite3_column_type(s, 2)!=SQLITE_BLOB ){ | |
| 1822 + return SQLITE_CORRUPT_BKPT; | |
| 1823 + } | |
| 1824 + | |
| 1825 + rc = leavesReaderInit(v, 0, iStartBlockid, iEndBlockid, | |
| 1826 + pRootData, nRootData, &reader); | |
| 1827 if( rc!=SQLITE_OK ) return rc; | |
| 1828 | |
| 1829 while( rc==SQLITE_OK && !leavesReaderAtEnd(&reader) ){ | |
| 1830 @@ -6641,16 +7018,19 @@ | |
| 1831 const char *pData, int nData){ | |
| 1832 DataBuffer dump; | |
| 1833 DLReader dlReader; | |
| 1834 + int rc; | |
| 1835 | |
| 1836 assert( pData!=NULL && nData>0 ); | |
| 1837 | |
| 1838 + rc = dlrInit(&dlReader, DL_DEFAULT, pData, nData); | |
| 1839 + if( rc!=SQLITE_OK ) return rc; | |
| 1840 dataBufferInit(&dump, 0); | |
| 1841 - dlrInit(&dlReader, DL_DEFAULT, pData, nData); | |
| 1842 - for( ; !dlrAtEnd(&dlReader); dlrStep(&dlReader) ){ | |
| 1843 + for( ; rc==SQLITE_OK && !dlrAtEnd(&dlReader); rc = dlrStep(&dlReader) ){ | |
| 1844 char buf[256]; | |
| 1845 PLReader plReader; | |
| 1846 | |
| 1847 - plrInit(&plReader, &dlReader); | |
| 1848 + rc = plrInit(&plReader, &dlReader); | |
| 1849 + if( rc!=SQLITE_OK ) break; | |
| 1850 if( DL_DEFAULT==DL_DOCIDS || plrAtEnd(&plReader) ){ | |
| 1851 sqlite3_snprintf(sizeof(buf), buf, "[%lld] ", dlrDocid(&dlReader)); | |
| 1852 dataBufferAppend(&dump, buf, strlen(buf)); | |
| 1853 @@ -6661,7 +7041,8 @@ | |
| 1854 dlrDocid(&dlReader), iColumn); | |
| 1855 dataBufferAppend(&dump, buf, strlen(buf)); | |
| 1856 | |
| 1857 - for( ; !plrAtEnd(&plReader); plrStep(&plReader) ){ | |
| 1858 + for( ; !plrAtEnd(&plReader); rc = plrStep(&plReader) ){ | |
| 1859 + if( rc!=SQLITE_OK ) break; | |
| 1860 if( plrColumn(&plReader)!=iColumn ){ | |
| 1861 iColumn = plrColumn(&plReader); | |
| 1862 sqlite3_snprintf(sizeof(buf), buf, "] %d[", iColumn); | |
| 1863 @@ -6682,6 +7063,7 @@ | |
| 1864 dataBufferAppend(&dump, buf, strlen(buf)); | |
| 1865 } | |
| 1866 plrDestroy(&plReader); | |
| 1867 + if( rc!= SQLITE_OK ) break; | |
| 1868 | |
| 1869 assert( dump.nData>0 ); | |
| 1870 dump.nData--; /* Overwrite trailing space. */ | |
| 1871 @@ -6690,6 +7072,10 @@ | |
| 1872 } | |
| 1873 } | |
| 1874 dlrDestroy(&dlReader); | |
| 1875 + if( rc!=SQLITE_OK ){ | |
| 1876 + dataBufferDestroy(&dump); | |
| 1877 + return rc; | |
| 1878 + } | |
| 1879 | |
| 1880 assert( dump.nData>0 ); | |
| 1881 dump.nData--; /* Overwrite trailing space. */ | |
| 1882 @@ -6701,6 +7087,7 @@ | |
| 1883 sqlite3_result_text(pContext, dump.pData, dump.nData, sqlite3_free); | |
| 1884 dump.pData = NULL; | |
| 1885 dump.nData = dump.nCapacity = 0; | |
| 1886 + return SQLITE_OK; | |
| 1887 } | |
| 1888 | |
| 1889 /* Implements dump_doclist() for use in inspecting the fts3 index from | |
| 1890 @@ -6987,7 +7374,11 @@ | |
| 1891 ** module with sqlite. | 29 ** module with sqlite. |
| 1892 */ | 30 */ |
| 1893 if( SQLITE_OK==rc | 31 if( SQLITE_OK==rc |
| 1894 +#if CHROMIUM_FTS3_CHANGES && !SQLITE_TEST | 32 +#if CHROMIUM_FTS3_CHANGES && !SQLITE_TEST |
| 1895 + /* fts3_tokenizer() disabled for security reasons. */ | 33 + /* fts3_tokenizer() disabled for security reasons. */ |
| 1896 +#else | 34 +#else |
| 1897 && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer")) | 35 && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer")) |
| 1898 +#endif | 36 +#endif |
| 1899 && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1)) | 37 && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1)) |
| 1900 && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", -1)) | 38 && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1)) |
| 1901 && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", -1)) | 39 && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1)) |
| 1902 Index: ext/fts3/fts3_icu.c | 40 @@ -3656,11 +3674,15 @@ int sqlite3Fts3Init(sqlite3 *db){ |
| 1903 =================================================================== | 41 rc = sqlite3_create_module_v2( |
| 1904 --- ext/fts3/fts3_icu.c»(revision 48811) | 42 db, "fts3", &fts3Module, (void *)pHash, hashDestroy |
| 1905 +++ ext/fts3/fts3_icu.c»(working copy) | 43 ); |
| 1906 @@ -198,7 +198,7 @@ | 44 +#if CHROMIUM_FTS3_CHANGES && !SQLITE_TEST |
| 45 + /* Disable fts4 pending review. */ |
| 46 +#else |
| 47 if( rc==SQLITE_OK ){ |
| 48 rc = sqlite3_create_module_v2( |
| 49 db, "fts4", &fts3Module, (void *)pHash, 0 |
| 50 ); |
| 51 } |
| 52 +#endif |
| 53 return rc; |
| 54 } |
| 55 |
| 56 diff --git ext/fts3/fts3_icu.c ext/fts3/fts3_icu.c |
| 57 index 85390d3..a75b14a 100644 |
| 58 --- ext/fts3/fts3_icu.c |
| 59 +++ ext/fts3/fts3_icu.c |
| 60 @@ -198,7 +198,7 @@ static int icuNext( |
| 1907 | 61 |
| 1908 while( iStart<iEnd ){ | 62 while( iStart<iEnd ){ |
| 1909 int iWhite = iStart; | 63 int iWhite = iStart; |
| 1910 - U8_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c); | 64 - U8_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c); |
| 1911 + U16_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c); | 65 + U16_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c); |
| 1912 if( u_isspace(c) ){ | 66 if( u_isspace(c) ){ |
| 1913 iStart = iWhite; | 67 iStart = iWhite; |
| 1914 }else{ | 68 }else{ |
| 1915 Index: ext/fts3/fts3_tokenizer.c | |
| 1916 =================================================================== | |
| 1917 --- ext/fts3/fts3_tokenizer.c (revision 48811) | |
| 1918 +++ ext/fts3/fts3_tokenizer.c (working copy) | |
| 1919 @@ -33,6 +33,7 @@ | |
| 1920 #include "fts3_hash.h" | |
| 1921 #include "fts3_tokenizer.h" | |
| 1922 #include <assert.h> | |
| 1923 +#include <stddef.h> | |
| 1924 | |
| 1925 /* | |
| 1926 ** Implementation of the SQL scalar function for accessing the underlying | |
| OLD | NEW |