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 |