| 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 |