OLD | NEW |
1 Index: Makefile.linux-gcc | 1 Index: Makefile.linux-gcc |
2 =================================================================== | 2 =================================================================== |
3 --- Makefile.linux-gcc 2009-09-03 13:32:06.000000000 -0700 | 3 --- Makefile.linux-gcc 2009-09-03 13:32:06.000000000 -0700 |
4 +++ Makefile.linux-gcc 2009-07-01 12:08:39.000000000 -0700 | 4 +++ Makefile.linux-gcc 2009-07-01 12:08:39.000000000 -0700 |
5 @@ -14,7 +14,7 @@ | 5 @@ -14,7 +14,7 @@ |
6 #### The toplevel directory of the source tree. This is the directory | 6 #### The toplevel directory of the source tree. This is the directory |
7 # that contains this "Makefile.in" and the "configure.in" script. | 7 # that contains this "Makefile.in" and the "configure.in" script. |
8 # | 8 # |
9 -TOP = ../sqlite | 9 -TOP = ../sqlite |
10 +TOP = .. | 10 +TOP = .. |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 break; | 88 break; |
89 } | 89 } |
90 return rc; | 90 return rc; |
91 - | 91 - |
92 - err: | 92 - err: |
93 - sqlite3_finalize(s); | 93 - sqlite3_finalize(s); |
94 - return rc; | 94 - return rc; |
95 } | 95 } |
96 | 96 |
97 /* Like sql_step_statement(), but convert SQLITE_DONE to SQLITE_OK. | 97 /* Like sql_step_statement(), but convert SQLITE_DONE to SQLITE_OK. |
98 Index: ext/fts2/fts2.c | |
99 =================================================================== | |
100 --- ext/fts2/fts2.c 2009-09-04 13:37:41.000000000 -0700 | |
101 +++ ext/fts2/fts2.c 2009-09-14 18:17:02.000000000 -0700 | |
102 @@ -37,6 +37,20 @@ | |
103 ** This is an SQLite module implementing full-text search. | |
104 */ | |
105 | |
106 +/* TODO(shess): To make it easier to spot changes without groveling | |
107 +** through changelogs, I've defined GEARS_FTS2_CHANGES to call them | |
108 +** out, and I will document them here. On imports, these changes | |
109 +** should be reviewed to make sure they are still present, or are | |
110 +** dropped as appropriate. | |
111 +** | |
112 +** SQLite core adds the custom function fts2_tokenizer() to be used | |
113 +** for defining new tokenizers. The second parameter is a vtable | |
114 +** pointer encoded as a blob. Obviously this cannot be exposed to | |
115 +** Gears callers for security reasons. It could be suppressed in the | |
116 +** authorizer, but for now I have simply commented the definition out. | |
117 +*/ | |
118 +#define GEARS_FTS2_CHANGES 1 | |
119 + | |
120 /* | |
121 ** The code in this file is only compiled if: | |
122 ** | |
123 @@ -335,6 +349,16 @@ | |
124 # define TRACE(A) | |
125 #endif | |
126 | |
127 +#if 0 | |
128 +/* Useful to set breakpoints. See main.c sqlite3Corrupt(). */ | |
129 +static int fts2Corrupt(void){ | |
130 + return SQLITE_CORRUPT; | |
131 +} | |
132 +# define SQLITE_CORRUPT_BKPT fts2Corrupt() | |
133 +#else | |
134 +# define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT | |
135 +#endif | |
136 + | |
137 /* It is not safe to call isspace(), tolower(), or isalnum() on | |
138 ** hi-bit-set characters. This is the same solution used in the | |
139 ** tokenizer. | |
140 @@ -1814,7 +1838,7 @@ | |
141 /* SEGDIR_MAX_INDEX */ "select max(idx) from %_segdir where level = ?", | |
142 /* SEGDIR_SET */ "insert into %_segdir values (?, ?, ?, ?, ?, ?)", | |
143 /* SEGDIR_SELECT_LEVEL */ | |
144 - "select start_block, leaves_end_block, root from %_segdir " | |
145 + "select start_block, leaves_end_block, root, idx from %_segdir " | |
146 " where level = ? order by idx", | |
147 /* SEGDIR_SPAN */ | |
148 "select min(start_block), max(end_block) from %_segdir " | |
149 @@ -3421,8 +3445,11 @@ | |
150 c->eof = 0; | |
151 return SQLITE_OK; | |
152 } | |
153 - /* an error occurred; abort */ | |
154 - return rc==SQLITE_DONE ? SQLITE_ERROR : rc; | |
155 + | |
156 + /* Corrupt if the index refers to missing document. */ | |
157 + if( rc==SQLITE_DONE ) return SQLITE_CORRUPT_BKPT; | |
158 + | |
159 + return rc; | |
160 } | |
161 } | |
162 | |
163 @@ -3544,6 +3571,7 @@ | |
164 int firstIndex = pQuery->nTerms; | |
165 int iCol; | |
166 int nTerm = 1; | |
167 + int iEndLast = -1; | |
168 | |
169 int rc = pModule->xOpen(pTokenizer, pSegment, nSegment, &pCursor); | |
170 if( rc!=SQLITE_OK ) return rc; | |
171 @@ -3568,6 +3596,20 @@ | |
172 pQuery->nextIsOr = 1; | |
173 continue; | |
174 } | |
175 + | |
176 + /* | |
177 + * The ICU tokenizer considers '*' a break character, so the code below | |
178 + * sets isPrefix correctly, but since that code doesn't eat the '*', the | |
179 + * ICU tokenizer returns it as the next token. So eat it here until a | |
180 + * better solution presents itself. | |
181 + */ | |
182 + if( pQuery->nTerms>0 && nToken==1 && pSegment[iBegin]=='*' && | |
183 + iEndLast==iBegin){ | |
184 + pQuery->pTerms[pQuery->nTerms-1].isPrefix = 1; | |
185 + continue; | |
186 + } | |
187 + iEndLast = iEnd; | |
188 + | |
189 queryAdd(pQuery, pToken, nToken); | |
190 if( !inPhrase && iBegin>0 && pSegment[iBegin-1]=='-' ){ | |
191 pQuery->pTerms[pQuery->nTerms-1].isNot = 1; | |
192 @@ -5077,6 +5119,9 @@ | |
193 ** the leaf data was entirely contained in the root), or from the | |
194 ** stream of blocks between iStartBlockid and iEndBlockid, inclusive. | |
195 */ | |
196 +/* TODO(shess): Figure out a means of indicating how many leaves are | |
197 +** expected, for purposes of detecting corruption. | |
198 +*/ | |
199 static int leavesReaderInit(fulltext_vtab *v, | |
200 int idx, | |
201 sqlite_int64 iStartBlockid, | |
202 @@ -5088,6 +5133,10 @@ | |
203 | |
204 dataBufferInit(&pReader->rootData, 0); | |
205 if( iStartBlockid==0 ){ | |
206 + /* Corrupt if this can't be a leaf node. */ | |
207 + if( pRootData==NULL || nRootData<1 || pRootData[0]!='\0' ){ | |
208 + return SQLITE_CORRUPT_BKPT; | |
209 + } | |
210 /* Entire leaf level fit in root data. */ | |
211 dataBufferReplace(&pReader->rootData, pRootData, nRootData); | |
212 leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, | |
213 @@ -5098,22 +5147,48 @@ | |
214 if( rc!=SQLITE_OK ) return rc; | |
215 | |
216 rc = sqlite3_bind_int64(s, 1, iStartBlockid); | |
217 - if( rc!=SQLITE_OK ) return rc; | |
218 + if( rc!=SQLITE_OK ) goto err; | |
219 | |
220 rc = sqlite3_bind_int64(s, 2, iEndBlockid); | |
221 - if( rc!=SQLITE_OK ) return rc; | |
222 + if( rc!=SQLITE_OK ) goto err; | |
223 | |
224 rc = sqlite3_step(s); | |
225 + | |
226 + /* Corrupt if interior node referenced missing leaf node. */ | |
227 if( rc==SQLITE_DONE ){ | |
228 - pReader->eof = 1; | |
229 - return SQLITE_OK; | |
230 + rc = SQLITE_CORRUPT_BKPT; | |
231 + goto err; | |
232 + } | |
233 + | |
234 + if( rc!=SQLITE_ROW ) goto err; | |
235 + rc = SQLITE_OK; | |
236 + | |
237 + /* Corrupt if leaf data isn't a blob. */ | |
238 + if( sqlite3_column_type(s, 0)!=SQLITE_BLOB ){ | |
239 + rc = SQLITE_CORRUPT_BKPT; | |
240 + }else{ | |
241 + const char *pLeafData = sqlite3_column_blob(s, 0); | |
242 + int nLeafData = sqlite3_column_bytes(s, 0); | |
243 + | |
244 + /* Corrupt if this can't be a leaf node. */ | |
245 + if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ | |
246 + rc = SQLITE_CORRUPT_BKPT; | |
247 + }else{ | |
248 + leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); | |
249 + } | |
250 + } | |
251 + | |
252 + err: | |
253 + if( rc!=SQLITE_OK ){ | |
254 + if( idx==-1 ){ | |
255 + sqlite3_finalize(s); | |
256 + }else{ | |
257 + sqlite3_reset(s); | |
258 + } | |
259 + return rc; | |
260 } | |
261 - if( rc!=SQLITE_ROW ) return rc; | |
262 | |
263 pReader->pStmt = s; | |
264 - leafReaderInit(sqlite3_column_blob(pReader->pStmt, 0), | |
265 - sqlite3_column_bytes(pReader->pStmt, 0), | |
266 - &pReader->leafReader); | |
267 } | |
268 return SQLITE_OK; | |
269 } | |
270 @@ -5136,10 +5211,22 @@ | |
271 pReader->eof = 1; | |
272 return rc==SQLITE_DONE ? SQLITE_OK : rc; | |
273 } | |
274 - leafReaderDestroy(&pReader->leafReader); | |
275 - leafReaderInit(sqlite3_column_blob(pReader->pStmt, 0), | |
276 - sqlite3_column_bytes(pReader->pStmt, 0), | |
277 - &pReader->leafReader); | |
278 + | |
279 + /* Corrupt if leaf data isn't a blob. */ | |
280 + if( sqlite3_column_type(pReader->pStmt, 0)!=SQLITE_BLOB ){ | |
281 + return SQLITE_CORRUPT_BKPT; | |
282 + }else{ | |
283 + const char *pLeafData = sqlite3_column_blob(pReader->pStmt, 0); | |
284 + int nLeafData = sqlite3_column_bytes(pReader->pStmt, 0); | |
285 + | |
286 + /* Corrupt if this can't be a leaf node. */ | |
287 + if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ | |
288 + return SQLITE_CORRUPT_BKPT; | |
289 + } | |
290 + | |
291 + leafReaderDestroy(&pReader->leafReader); | |
292 + leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); | |
293 + } | |
294 } | |
295 return SQLITE_OK; | |
296 } | |
297 @@ -5200,8 +5287,19 @@ | |
298 sqlite_int64 iEnd = sqlite3_column_int64(s, 1); | |
299 const char *pRootData = sqlite3_column_blob(s, 2); | |
300 int nRootData = sqlite3_column_bytes(s, 2); | |
301 + sqlite_int64 iIndex = sqlite3_column_int64(s, 3); | |
302 + | |
303 + /* Corrupt if we get back different types than we stored. */ | |
304 + /* Also corrupt if the index is not sequential starting at 0. */ | |
305 + if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER || | |
306 + sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
307 + sqlite3_column_type(s, 2)!=SQLITE_BLOB || | |
308 + i!=iIndex || | |
309 + i>=MERGE_COUNT ){ | |
310 + rc = SQLITE_CORRUPT_BKPT; | |
311 + break; | |
312 + } | |
313 | |
314 - assert( i<MERGE_COUNT ); | |
315 rc = leavesReaderInit(v, i, iStart, iEnd, pRootData, nRootData, | |
316 &pReaders[i]); | |
317 if( rc!=SQLITE_OK ) break; | |
318 @@ -5212,6 +5310,7 @@ | |
319 while( i-->0 ){ | |
320 leavesReaderDestroy(&pReaders[i]); | |
321 } | |
322 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
323 return rc; | |
324 } | |
325 | |
326 @@ -5295,10 +5394,14 @@ | |
327 memset(&lrs, '\0', sizeof(lrs)); | |
328 rc = leavesReadersInit(v, iLevel, lrs, &i); | |
329 if( rc!=SQLITE_OK ) return rc; | |
330 - assert( i==MERGE_COUNT ); | |
331 | |
332 leafWriterInit(iLevel+1, idx, &writer); | |
333 | |
334 + if( i!=MERGE_COUNT ){ | |
335 + rc = SQLITE_CORRUPT_BKPT; | |
336 + goto err; | |
337 + } | |
338 + | |
339 /* Since leavesReaderReorder() pushes readers at eof to the end, | |
340 ** when the first reader is empty, all will be empty. | |
341 */ | |
342 @@ -5588,11 +5691,27 @@ | |
343 if( rc!=SQLITE_OK ) return rc; | |
344 | |
345 rc = sqlite3_step(s); | |
346 - if( rc==SQLITE_DONE ) return SQLITE_ERROR; | |
347 + /* Corrupt if interior node references missing child node. */ | |
348 + if( rc==SQLITE_DONE ) return SQLITE_CORRUPT_BKPT; | |
349 if( rc!=SQLITE_ROW ) return rc; | |
350 | |
351 - getChildrenContaining(sqlite3_column_blob(s, 0), sqlite3_column_bytes(s, 0), | |
352 - pTerm, nTerm, isPrefix, piStartChild, piEndChild); | |
353 + /* Corrupt if child node isn't a blob. */ | |
354 + if( sqlite3_column_type(s, 0)!=SQLITE_BLOB ){ | |
355 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
356 + return SQLITE_CORRUPT_BKPT; | |
357 + }else{ | |
358 + const char *pData = sqlite3_column_blob(s, 0); | |
359 + int nData = sqlite3_column_bytes(s, 0); | |
360 + | |
361 + /* Corrupt if child is not a valid interior node. */ | |
362 + if( pData==NULL || nData<1 || pData[0]=='\0' ){ | |
363 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
364 + return SQLITE_CORRUPT_BKPT; | |
365 + } | |
366 + | |
367 + getChildrenContaining(pData, nData, pTerm, nTerm, | |
368 + isPrefix, piStartChild, piEndChild); | |
369 + } | |
370 | |
371 /* We expect only one row. We must execute another sqlite3_step() | |
372 * to complete the iteration; otherwise the table will remain | |
373 @@ -5675,7 +5794,8 @@ | |
374 DataBuffer result; | |
375 int rc; | |
376 | |
377 - assert( nData>1 ); | |
378 + /* Corrupt if segment root can't be valid. */ | |
379 + if( pData==NULL || nData<1 ) return SQLITE_CORRUPT_BKPT; | |
380 | |
381 /* This code should never be called with buffered updates. */ | |
382 assert( v->nPendingData<0 ); | |
383 @@ -5729,6 +5849,14 @@ | |
384 const char *pData = sqlite3_column_blob(s, 2); | |
385 const int nData = sqlite3_column_bytes(s, 2); | |
386 const sqlite_int64 iLeavesEnd = sqlite3_column_int64(s, 1); | |
387 + | |
388 + /* Corrupt if we get back different types than we stored. */ | |
389 + if( sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
390 + sqlite3_column_type(s, 2)!=SQLITE_BLOB ){ | |
391 + rc = SQLITE_CORRUPT_BKPT; | |
392 + goto err; | |
393 + } | |
394 + | |
395 rc = loadSegment(v, pData, nData, iLeavesEnd, pTerm, nTerm, isPrefix, | |
396 &doclist); | |
397 if( rc!=SQLITE_OK ) goto err; | |
398 @@ -5748,6 +5876,7 @@ | |
399 } | |
400 | |
401 err: | |
402 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
403 dataBufferDestroy(&doclist); | |
404 return rc; | |
405 } | |
406 @@ -6240,6 +6369,14 @@ | |
407 const char *pRootData = sqlite3_column_blob(s, 2); | |
408 int nRootData = sqlite3_column_bytes(s, 2); | |
409 | |
410 + /* Corrupt if we get back different types than we stored. */ | |
411 + if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER || | |
412 + sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
413 + sqlite3_column_type(s, 2)!=SQLITE_BLOB ){ | |
414 + rc = SQLITE_CORRUPT_BKPT; | |
415 + break; | |
416 + } | |
417 + | |
418 assert( i<nReaders ); | |
419 rc = leavesReaderInit(v, -1, iStart, iEnd, pRootData, nRootData, | |
420 &readers[i].reader); | |
421 @@ -6253,6 +6390,8 @@ | |
422 if( rc==SQLITE_DONE ){ | |
423 assert( i==nReaders ); | |
424 rc = optimizeInternal(v, readers, nReaders, &writer); | |
425 + }else{ | |
426 + sqlite3_reset(s); /* So we don't leave a lock. */ | |
427 } | |
428 | |
429 while( i-- > 0 ){ | |
430 @@ -6316,9 +6455,18 @@ | |
431 const sqlite_int64 iEndBlockid = sqlite3_column_int64(s, 1); | |
432 const char *pRootData = sqlite3_column_blob(s, 2); | |
433 const int nRootData = sqlite3_column_bytes(s, 2); | |
434 + int rc; | |
435 LeavesReader reader; | |
436 - int rc = leavesReaderInit(v, 0, iStartBlockid, iEndBlockid, | |
437 - pRootData, nRootData, &reader); | |
438 + | |
439 + /* Corrupt if we get back different types than we stored. */ | |
440 + if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER || | |
441 + sqlite3_column_type(s, 1)!=SQLITE_INTEGER || | |
442 + sqlite3_column_type(s, 2)!=SQLITE_BLOB ){ | |
443 + return SQLITE_CORRUPT_BKPT; | |
444 + } | |
445 + | |
446 + rc = leavesReaderInit(v, 0, iStartBlockid, iEndBlockid, | |
447 + pRootData, nRootData, &reader); | |
448 if( rc!=SQLITE_OK ) return rc; | |
449 | |
450 while( rc==SQLITE_OK && !leavesReaderAtEnd(&reader) ){ | |
451 @@ -6822,7 +6970,11 @@ | |
452 ** module with sqlite. | |
453 */ | |
454 if( SQLITE_OK==rc | |
455 +#if GEARS_FTS2_CHANGES && !SQLITE_TEST | |
456 + /* fts2_tokenizer() disabled for security reasons. */ | |
457 +#else | |
458 && SQLITE_OK==(rc = sqlite3Fts2InitHashTable(db, pHash, "fts2_tokenizer")) | |
459 +#endif | |
460 && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1)) | |
461 && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", -1)) | |
462 && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", -1)) | |
463 Index: ext/fts2/fts2_icu.c | |
464 =================================================================== | |
465 --- ext/fts2/fts2_icu.c 2009-09-03 13:32:06.000000000 -0700 | |
466 +++ ext/fts2/fts2_icu.c 2009-09-14 18:17:16.000000000 -0700 | |
467 @@ -198,7 +198,7 @@ | |
468 | |
469 while( iStart<iEnd ){ | |
470 int iWhite = iStart; | |
471 - U8_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c); | |
472 + U16_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c); | |
473 if( u_isspace(c) ){ | |
474 iStart = iWhite; | |
475 }else{ | |
476 Index: ext/fts2/fts2_tokenizer.c | |
477 =================================================================== | |
478 --- ext/fts2/fts2_tokenizer.c 2009-09-03 13:32:06.000000000 -0700 | |
479 +++ ext/fts2/fts2_tokenizer.c 2009-09-14 18:17:24.000000000 -0700 | |
480 @@ -33,6 +33,7 @@ | |
481 #include "fts2_hash.h" | |
482 #include "fts2_tokenizer.h" | |
483 #include <assert.h> | |
484 +#include <stddef.h> | |
485 | |
486 /* | |
487 ** Implementation of the SQL scalar function for accessing the underlying | |
488 Index: ext/icu/icu.c | 98 Index: ext/icu/icu.c |
489 =================================================================== | 99 =================================================================== |
490 --- ext/icu/icu.c 2009-09-03 13:32:06.000000000 -0700 | 100 --- ext/icu/icu.c 2009-09-03 13:32:06.000000000 -0700 |
491 +++ ext/icu/icu.c 2009-07-01 12:08:37.000000000 -0700 | 101 +++ ext/icu/icu.c 2009-07-01 12:08:37.000000000 -0700 |
492 @@ -38,6 +38,11 @@ | 102 @@ -38,6 +38,11 @@ |
493 | 103 |
494 #include <assert.h> | 104 #include <assert.h> |
495 | 105 |
496 +// TODO(evanm): this is cut'n'pasted from fts2.c. Why is it necessary? | 106 +// TODO(evanm): this is cut'n'pasted from fts2.c. Why is it necessary? |
497 +#if !defined(SQLITE_CORE) | 107 +#if !defined(SQLITE_CORE) |
(...skipping 1088 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1586 + if {$sqlite_open_file_count>0} { | 1196 + if {$sqlite_open_file_count>0} { |
1587 + puts "$tail did not close all files: $sqlite_open_file_count" | 1197 + puts "$tail did not close all files: $sqlite_open_file_count" |
1588 + incr nErr | 1198 + incr nErr |
1589 + lappend ::failList $tail | 1199 + lappend ::failList $tail |
1590 + } | 1200 + } |
1591 +} | 1201 +} |
1592 +source $testdir/misuse.test | 1202 +source $testdir/misuse.test |
1593 + | 1203 + |
1594 +set sqlite_open_file_count 0 | 1204 +set sqlite_open_file_count 0 |
1595 +really_finish_test | 1205 +really_finish_test |
OLD | NEW |