Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Test cases to improve coverage of btree.c (and minor bugfixes). (CVS 2190) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
8ced491588764b1e1066787d0abf3cde |
User & Date: | danielk1977 2005-01-11 10:25:06.975 |
Original User & Date: | danielk1977 2005-01-11 10:25:07.000 |
Context
2005-01-11
| ||
10:25 | Test cases to improve coverage of btree.c (and minor bugfixes). (CVS 2191) (check-in: a37e0108de user: danielk1977 tags: trunk) | |
10:25 | Test cases to improve coverage of btree.c (and minor bugfixes). (CVS 2190) (check-in: 8ced491588 user: danielk1977 tags: trunk) | |
2005-01-10
| ||
12:59 | Extra test cases to improve coverage of btree.c (CVS 2189) (check-in: a461988661 user: danielk1977 tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: btree.c,v 1.230 2005/01/11 10:25:07 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. |
︙ | ︙ | |||
352 353 354 355 356 357 358 | void *pArg; /* First arg to xCompare() */ Pgno pgnoRoot; /* The root page of this tree */ MemPage *pPage; /* Page that contains the entry */ int idx; /* Index of the entry in pPage->aCell[] */ CellInfo info; /* A parse of the cell we are pointing at */ u8 wrFlag; /* True if writable */ u8 isValid; /* TRUE if points to a valid entry */ | < | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 | void *pArg; /* First arg to xCompare() */ Pgno pgnoRoot; /* The root page of this tree */ MemPage *pPage; /* Page that contains the entry */ int idx; /* Index of the entry in pPage->aCell[] */ CellInfo info; /* A parse of the cell we are pointing at */ u8 wrFlag; /* True if writable */ u8 isValid; /* TRUE if points to a valid entry */ }; /* ** Forward declaration */ static int checkReadLocks(Btree*,Pgno,BtCursor*); |
︙ | ︙ | |||
949 950 951 952 953 954 955 | ** we failed to detect any corruption. */ static int initPage( MemPage *pPage, /* The page to be initialized */ MemPage *pParent /* The parent. Might be NULL */ ){ int pc; /* Address of a freeblock within pPage->aData[] */ | < | 948 949 950 951 952 953 954 955 956 957 958 959 960 961 | ** we failed to detect any corruption. */ static int initPage( MemPage *pPage, /* The page to be initialized */ MemPage *pParent /* The parent. Might be NULL */ ){ int pc; /* Address of a freeblock within pPage->aData[] */ int hdr; /* Offset to beginning of page header */ u8 *data; /* Equal to pPage->aData */ Btree *pBt; /* The main btree structure */ int usableSize; /* Amount of usable space on each page */ int cellOffset; /* Offset from start of page to first cell pointer */ int nFree; /* Number of unused bytes on the page */ int top; /* First byte of the cell content area */ |
︙ | ︙ | |||
993 994 995 996 997 998 999 | /* All pages must have at least one cell, except for root pages */ return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } /* Compute the total free space on the page */ pc = get2byte(&data[hdr+1]); nFree = data[hdr+7] + top - (cellOffset + 2*pPage->nCell); | < < < < < | 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 | /* All pages must have at least one cell, except for root pages */ return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } /* Compute the total free space on the page */ pc = get2byte(&data[hdr+1]); nFree = data[hdr+7] + top - (cellOffset + 2*pPage->nCell); while( pc>0 ){ int next, size; if( pc>usableSize-4 ){ /* Free block is off the page */ return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); if( next>0 && next<=pc+size+3 ){ /* Free blocks must be in accending order */ return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } nFree += size; |
︙ | ︙ | |||
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 | ** size supplied does not meet this constraint then the page size is not ** changed. ** ** Page sizes are constrained to be a power of two so that the region ** of the database file used for locking (beginning at PENDING_BYTE, ** the first byte past the 1GB boundary, 0x40000000) needs to occur ** at the beginning of a page. */ int sqlite3BtreeSetPageSize(Btree *pBt, int pageSize, int nReserve){ if( pBt->pageSizeFixed ){ return SQLITE_READONLY; } if( nReserve<0 ){ nReserve = pBt->pageSize - pBt->usableSize; | > > > | 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 | ** size supplied does not meet this constraint then the page size is not ** changed. ** ** Page sizes are constrained to be a power of two so that the region ** of the database file used for locking (beginning at PENDING_BYTE, ** the first byte past the 1GB boundary, 0x40000000) needs to occur ** at the beginning of a page. ** ** If parameter nReserve is less than zero, then the number of reserved ** bytes per page is left unchanged. */ int sqlite3BtreeSetPageSize(Btree *pBt, int pageSize, int nReserve){ if( pBt->pageSizeFixed ){ return SQLITE_READONLY; } if( nReserve<0 ){ nReserve = pBt->pageSize - pBt->usableSize; |
︙ | ︙ | |||
1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 | #endif #ifdef SQLITE_TEST /* ** Print debugging information about all cursors to standard output. */ void sqlite3BtreeCursorList(Btree *pBt){ BtCursor *pCur; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ MemPage *pPage = pCur->pPage; char *zMode = pCur->wrFlag ? "rw" : "ro"; sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n", pCur, pCur->pgnoRoot, zMode, pPage ? pPage->pgno : 0, pCur->idx, pCur->isValid ? "" : " eof" ); } } #endif /* ** Rollback the transaction in progress. All cursors will be ** invalided by this operation. Any attempt to use a cursor ** that was open at the beginning of this operation will result | > > | 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 | #endif #ifdef SQLITE_TEST /* ** Print debugging information about all cursors to standard output. */ void sqlite3BtreeCursorList(Btree *pBt){ #ifndef SQLITE_OMIT_CURSOR BtCursor *pCur; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ MemPage *pPage = pCur->pPage; char *zMode = pCur->wrFlag ? "rw" : "ro"; sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n", pCur, pCur->pgnoRoot, zMode, pPage ? pPage->pgno : 0, pCur->idx, pCur->isValid ? "" : " eof" ); } #endif } #endif /* ** Rollback the transaction in progress. All cursors will be ** invalided by this operation. Any attempt to use a cursor ** that was open at the beginning of this operation will result |
︙ | ︙ | |||
2113 2114 2115 2116 2117 2118 2119 | pCur->pNext = pBt->pCursor; if( pCur->pNext ){ pCur->pNext->pPrev = pCur; } pCur->pPrev = 0; pBt->pCursor = pCur; pCur->isValid = 0; | < | 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 | pCur->pNext = pBt->pCursor; if( pCur->pNext ){ pCur->pNext->pPrev = pCur; } pCur->pPrev = 0; pBt->pCursor = pCur; pCur->isValid = 0; *ppCur = pCur; return SQLITE_OK; create_cursor_exception: if( pCur ){ releasePage(pCur->pPage); sqliteFree(pCur); |
︙ | ︙ | |||
2340 2341 2342 2343 2344 2345 2346 | ** begins at "offset". ** ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ | | < < | < < | 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 | ** begins at "offset". ** ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( pCur->isValid ); assert( pCur->pPage!=0 ); assert( pCur->pPage->intKey==0 ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); return getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } /* ** Read part of the data associated with cursor pCur. Exactly ** "amt" bytes will be transfered into pBuf[]. The transfer ** begins at "offset". ** ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( pCur->isValid ); assert( pCur->pPage!=0 ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); return getPayload(pCur, offset, amt, pBuf, 1); } /* ** Return a pointer to payload information from the entry that the |
︙ | ︙ | |||
2599 2600 2601 2602 2603 2604 2605 | /* Move the cursor to the first entry in the table. Return SQLITE_OK ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. */ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int rc; | < < < < < < | 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 | /* Move the cursor to the first entry in the table. Return SQLITE_OK ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. */ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int rc; rc = moveToRoot(pCur); if( rc ) return rc; if( pCur->isValid==0 ){ assert( pCur->pPage->nCell==0 ); *pRes = 1; return SQLITE_OK; } assert( pCur->pPage->nCell>0 ); *pRes = 0; rc = moveToLeftmost(pCur); return rc; } /* Move the cursor to the last entry in the table. Return SQLITE_OK ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. */ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ int rc; rc = moveToRoot(pCur); if( rc ) return rc; if( pCur->isValid==0 ){ assert( pCur->pPage->nCell==0 ); *pRes = 1; return SQLITE_OK; } |
︙ | ︙ | |||
2666 2667 2668 2669 2670 2671 2672 | ** exactly matches pKey. ** ** *pRes>0 The cursor is left pointing at an entry that ** is larger than pKey. */ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){ int rc; | < < < < | 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 | ** exactly matches pKey. ** ** *pRes>0 The cursor is left pointing at an entry that ** is larger than pKey. */ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){ int rc; rc = moveToRoot(pCur); if( rc ) return rc; assert( pCur->pPage ); assert( pCur->pPage->isInit ); if( pCur->isValid==0 ){ *pRes = -1; assert( pCur->pPage->nCell==0 ); |
︙ | ︙ | |||
3270 3271 3272 3273 3274 3275 3276 | */ if( pBt->autoVacuum && pgnoPtrmap!=0 && rc==SQLITE_OK ){ rc = ptrmapPut(pBt, pgnoOvfl, PTRMAP_OVERFLOW2, pgnoPtrmap); } #endif if( rc ){ releasePage(pToRelease); | | | 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 | */ if( pBt->autoVacuum && pgnoPtrmap!=0 && rc==SQLITE_OK ){ rc = ptrmapPut(pBt, pgnoOvfl, PTRMAP_OVERFLOW2, pgnoPtrmap); } #endif if( rc ){ releasePage(pToRelease); /* clearCell(pPage, pCell); */ return rc; } put4byte(pPrior, pgnoOvfl); releasePage(pToRelease); pToRelease = pOvfl; pPrior = pOvfl->aData; put4byte(pPrior, 0); |
︙ | ︙ | |||
3869 3870 3871 3872 3873 3874 3875 | pageFlags = pPage->aData[0]; for(i=0; i<k; i++){ MemPage *pNew; if( i<nOld ){ pNew = apNew[i] = apOld[i]; pgnoNew[i] = pgnoOld[i]; apOld[i] = 0; | | > | 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 | pageFlags = pPage->aData[0]; for(i=0; i<k; i++){ MemPage *pNew; if( i<nOld ){ pNew = apNew[i] = apOld[i]; pgnoNew[i] = pgnoOld[i]; apOld[i] = 0; rc = sqlite3pager_write(pNew->aData); if( rc ) goto balance_cleanup; }else{ rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1], 0); if( rc ) goto balance_cleanup; apNew[i] = pNew; } nNew++; zeroPage(pNew, pageFlags); |
︙ | ︙ | |||
4232 4233 4234 4235 4236 4237 4238 | int loc; int szNew; MemPage *pPage; Btree *pBt = pCur->pBt; unsigned char *oldCell; unsigned char *newCell = 0; | < < < | 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 | int loc; int szNew; MemPage *pPage; Btree *pBt = pCur->pBt; unsigned char *oldCell; unsigned char *newCell = 0; if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction before doing an insert */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( !pBt->readOnly ); if( !pCur->wrFlag ){ return SQLITE_PERM; /* Cursor not open for writing */ |
︙ | ︙ | |||
4306 4307 4308 4309 4310 4311 4312 | MemPage *pPage = pCur->pPage; unsigned char *pCell; int rc; Pgno pgnoChild = 0; Btree *pBt = pCur->pBt; assert( pPage->isInit ); | < < < | 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 | MemPage *pPage = pCur->pPage; unsigned char *pCell; int rc; Pgno pgnoChild = 0; Btree *pBt = pCur->pBt; assert( pPage->isInit ); if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction before doing a delete */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( !pBt->readOnly ); if( pCur->idx >= pPage->nCell ){ return SQLITE_ERROR; /* The cursor is not pointing to anything */ |
︙ | ︙ | |||
4334 4335 4336 4337 4338 4339 4340 | ** data. The clearCell() call frees any overflow pages associated with the ** cell. The cell itself is still intact. */ pCell = findCell(pPage, pCur->idx); if( !pPage->leaf ){ pgnoChild = get4byte(pCell); } | | > | 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 | ** data. The clearCell() call frees any overflow pages associated with the ** cell. The cell itself is still intact. */ pCell = findCell(pPage, pCur->idx); if( !pPage->leaf ){ pgnoChild = get4byte(pCell); } rc = clearCell(pPage, pCell); if( rc ) return rc; if( !pPage->leaf ){ /* ** The entry we are about to delete is not a leaf so if we do not ** do something we will leave a hole on an internal page. ** We have to fill the hole by moving in a cell from a leaf. The ** next Cell after the one to be deleted is guaranteed to exist and |
︙ | ︙ | |||
4406 4407 4408 4409 4410 4411 4412 | MemPage *pRoot; Pgno pgnoRoot; int rc; if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction first */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } | | < < | 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 | MemPage *pRoot; Pgno pgnoRoot; int rc; if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction first */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( !pBt->readOnly ); /* It is illegal to create a table if any cursors are open on the ** database. This is because in auto-vacuum mode the backend may ** need to move a database page to make room for the new root-page. ** If an open cursor was using the page a problem would occur. */ if( pBt->pCursor ){ |
︙ | ︙ | |||
4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 | } /* ** Print a disassembly of the given page on standard output. This routine ** is used for debugging and testing only. */ #ifdef SQLITE_TEST static int btreePageDump(Btree *pBt, int pgno, int recursive, MemPage *pParent){ int rc; MemPage *pPage; int i, j, c; int nFree; u16 idx; int hdr; | > | 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 | } /* ** Print a disassembly of the given page on standard output. This routine ** is used for debugging and testing only. */ #ifdef SQLITE_TEST #ifndef SQLITE_OMIT_BTREEPAGEDUMP static int btreePageDump(Btree *pBt, int pgno, int recursive, MemPage *pParent){ int rc; MemPage *pPage; int i, j, c; int nFree; u16 idx; int hdr; |
︙ | ︙ | |||
4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 | btreePageDump(pBt, get4byte(&data[hdr+8]), 1, pPage); } pPage->isInit = isInit; sqlite3pager_unref(data); fflush(stdout); return SQLITE_OK; } int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){ return btreePageDump(pBt, pgno, recursive, 0); } #endif #ifdef SQLITE_TEST /* ** Fill aResult[] with information about the entry and page that the ** cursor is pointing to. | > > > | 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 | btreePageDump(pBt, get4byte(&data[hdr+8]), 1, pPage); } pPage->isInit = isInit; sqlite3pager_unref(data); fflush(stdout); return SQLITE_OK; } #endif int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){ #ifndef SQLITE_OMIT_BTREEPAGEDUMP return btreePageDump(pBt, pgno, recursive, 0); #endif } #endif #ifdef SQLITE_TEST /* ** Fill aResult[] with information about the entry and page that the ** cursor is pointing to. |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** ** @(#) $Id: pager.c,v 1.181 2005/01/11 10:25:08 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
931 932 933 934 935 936 937 | assert( pPager->state>=PAGER_EXCLUSIVE || pPg ); TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno); if( pPager->state>=PAGER_EXCLUSIVE ){ sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize); rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize); } if( pPg ){ | | | > > | | | 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 | assert( pPager->state>=PAGER_EXCLUSIVE || pPg ); TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno); if( pPager->state>=PAGER_EXCLUSIVE ){ sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize); rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize); } if( pPg ){ /* No page should ever be explicitly rolled back that is in use, except ** for page 1 which is held in use in order to keep the lock on the ** database active. However such a page may be rolled back as a result ** of an internal error resulting in an automatic call to ** sqlite3pager_rollback(). */ void *pData; /* assert( pPg->nRef==0 || pPg->pgno==1 ); */ pData = PGHDR_TO_DATA(pPg); memcpy(pData, aData, pPager->pageSize); if( pPager->xDestructor ){ /*** FIX ME: Should this be xReinit? ***/ pPager->xDestructor(pData, pPager->pageSize); } if( pPager->state>=PAGER_EXCLUSIVE ){ pPg->dirty = 0; |
︙ | ︙ |
Changes to src/pragma.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2003 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2003 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** ** $Id: pragma.c,v 1.83 2005/01/11 10:25:08 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> /* Ignore this whole file if pragmas are disabled */ |
︙ | ︙ | |||
281 282 283 284 285 286 287 | */ if( sqlite3StrICmp(zLeft,"page_size")==0 ){ Btree *pBt = pDb->pBt; if( !zRight ){ int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0; returnSingleInt(pParse, "page_size", size); }else{ | | | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | */ if( sqlite3StrICmp(zLeft,"page_size")==0 ){ Btree *pBt = pDb->pBt; if( !zRight ){ int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0; returnSingleInt(pParse, "page_size", size); }else{ sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1); } }else #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ /* ** PRAGMA [database.]auto_vacuum ** PRAGMA [database.]auto_vacuum=N |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** ** $Id: vdbe.c,v 1.438 2005/01/11 10:25:08 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include "vdbeInt.h" /* |
︙ | ︙ | |||
2561 2562 2563 2564 2565 2566 2567 | if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){ pC->movetoTarget = iKey; pC->deferredMoveto = 1; assert( (pTos->flags & MEM_Dyn)==0 ); pTos--; break; } | | > > > | > > > | > > > | 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 | if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){ pC->movetoTarget = iKey; pC->deferredMoveto = 1; assert( (pTos->flags & MEM_Dyn)==0 ); pTos--; break; } rc = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } pC->lastRecno = pTos->i; pC->recnoIsValid = res==0; }else{ Stringify(pTos, db->enc); rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } pC->recnoIsValid = 0; } pC->deferredMoveto = 0; pC->cacheValid = 0; *pC->pIncrKey = 0; sqlite3_search_count++; if( oc==OP_MoveGe || oc==OP_MoveGt ){ if( res<0 ){ rc = sqlite3BtreeNext(pC->pCursor, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } pC->recnoIsValid = 0; }else{ res = 0; } }else{ assert( oc==OP_MoveLt || oc==OP_MoveLe ); if( res>=0 ){ |
︙ | ︙ | |||
2796 2797 2798 2799 2800 2801 2802 | assert( p->apCsr[i]!=0 ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int res, rx; u64 iKey; assert( pTos->flags & MEM_Int ); assert( p->apCsr[i]->intKey ); iKey = intToKey(pTos->i); | | > | > | 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 | assert( p->apCsr[i]!=0 ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int res, rx; u64 iKey; assert( pTos->flags & MEM_Int ); assert( p->apCsr[i]->intKey ); iKey = intToKey(pTos->i); // rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res); rc = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res); pC->lastRecno = pTos->i; pC->recnoIsValid = res==0; pC->nullRow = 0; pC->cacheValid = 0; // if( rx!=SQLITE_OK || res!=0 ){ if( res!=0 ){ pc = pOp->p2 - 1; pC->recnoIsValid = 0; } } Release(pTos); pTos--; break; |
︙ | ︙ |
Added test/autovacuum_ioerr.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file runs the tests in the file crash.test with auto-vacuum enabled # databases. # # $Id: autovacuum_ioerr.test,v 1.1 2005/01/11 10:25:07 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl rename finish_test really_finish_test2 proc finish_test {} {} set ISQUICK 1 rename sqlite3 real_sqlite3 proc sqlite3 {args} { set r [eval "real_sqlite3 $args"] if { [llength $args] == 2 } { [lindex $args 0] eval {pragma auto_vacuum = 1} } set r } rename do_test really_do_test proc do_test {args} { set sc [concat really_do_test "autovacuum-[lindex $args 0]" \ [lrange $args 1 end]] eval $sc } source $testdir/ioerr.test rename sqlite3 "" rename real_sqlite3 sqlite3 rename finish_test "" rename really_finish_test2 finish_test rename do_test "" rename really_do_test do_test finish_test |
Added test/autovacuum_ioerr2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | # 2001 October 12 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing for correct handling of I/O errors # such as writes failing because the disk is full. # # The tests in this file use special facilities that are only # available in the SQLite test fixture. # # $Id: autovacuum_ioerr2.test,v 1.1 2005/01/11 10:25:07 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl proc opendb {} { catch {file delete -force test.db} catch {file delete -force test.db-journal} sqlite3 db test.db execsql {pragma auto_vacuum = 1} execsql {SELECT * FROM sqlite_master} } set ::go 1 for {set n 1} {$go} {incr n} { do_test autovacuum-ioerr2-1.$n.1 { set ::sqlite_io_error_pending 0 db close opendb execsql { CREATE TABLE abc(a); INSERT INTO abc VALUES(randstr(1500,1500)); } expr [file size test.db]/1024 } {4} do_test autovacuum-ioerr2-1.$n.2 [subst { set ::sqlite_io_error_pending $n }] $n do_test autovacuum-ioerr2-1.$n.3 { set r [catch {db eval { CREATE TABLE abc2(a); BEGIN; DELETE FROM abc; INSERT INTO abc VALUES(randstr(1500,1500)); CREATE TABLE abc3(a); COMMIT; }} msg] set ::go [expr {$::sqlite_io_error_pending<=0}] expr {$::sqlite_io_error_pending>0 || $r!=0} } {1} } set ::sqlite_io_error_pending 0 set ::go 1 for {set n 1} {$go} {incr n} { do_test autovacuum-ioerr2-2.$n.1 { set ::sqlite_io_error_pending 0 db close opendb execsql { PRAGMA cache_size = 10; BEGIN; CREATE TABLE abc(a); INSERT INTO abc VALUES(randstr(1100,1100)); -- Page 4 is overflow INSERT INTO abc VALUES(randstr(1100,1100)); -- Page 5 is overflow } for {set i 0} {$i<150} {incr i} { execsql { INSERT INTO abc VALUES(randstr(100,100)); } } execsql COMMIT expr [file size test.db]/1024 } {24} do_test autovacuum-ioerr2-2.$n.2 [subst { set ::sqlite_io_error_pending $n }] $n do_test autovacuum-ioerr2-2.$n.3 { set r [catch {db eval { BEGIN; DELETE FROM abc WHERE length(a)>100; UPDATE abc SET a = randstr(90,90); CREATE TABLE abc3(a); COMMIT; }} msg] set ::go [expr {$::sqlite_io_error_pending<=0}] expr {$::sqlite_io_error_pending>0 || $r!=0} } {1} } set ::sqlite_io_error_pending 0 set ::go 1 for {set n 1} {$go} {incr n} { do_test autovacuum-ioerr2-3.$n.1 { set ::sqlite_io_error_pending 0 db close opendb execsql { CREATE TABLE abc(a); CREATE TABLE abc2(b); } } {} do_test autovacuum-ioerr2-3.$n.2 [subst { set ::sqlite_io_error_pending $n }] $n do_test autovacuum-ioerr2-3.$n.3 { set r [catch {db eval { BEGIN; INSERT INTO abc2 VALUES(10); DROP TABLE abc; COMMIT; DROP TABLE abc2; }} msg] set ::go [expr {$::sqlite_io_error_pending<=0}] expr {$::sqlite_io_error_pending>0 || $r!=0} } {1} } set ::sqlite_io_error_pending 0 do_test autovacuum-ioerr2.4.0 { db close opendb execsql { PRAGMA cache_size = 10; BEGIN; CREATE TABLE abc(a); INSERT INTO abc VALUES(randstr(1100,1100)); -- Page 4 is overflow INSERT INTO abc VALUES(randstr(1100,1100)); -- Page 5 is overflow } for {set i 0} {$i<2500} {incr i} { execsql { INSERT INTO abc VALUES(randstr(100,100)); } } execsql COMMIT file copy -force test.db backup.db } {} proc opendb2 {} { catch {file delete -force test.db} catch {file delete -force test.db-journal} file copy backup.db test.db sqlite3 db test.db execsql {select * from sqlite_master} execsql {PRAGMA cache_size = 10} return "" } set ::go 1 for {set n 1} {$go} {incr n} { do_test autovacuum-ioerr2-4.$n.1 { set ::sqlite_io_error_pending 0 db close opendb2 } {} do_test autovacuum-ioerr2-4.$n.2 [subst { set ::sqlite_io_error_pending $n }] $n do_test autovacuum-ioerr2-4.$n.3 { set r [catch {db eval { BEGIN; DELETE FROM abc WHERE oid < 3; UPDATE abc SET a = randstr(100,100) WHERE oid > 2300; UPDATE abc SET a = randstr(1100,1100) WHERE oid = (select max(oid) from abc); COMMIT; }} msg] set ::go [expr {$::sqlite_io_error_pending<=0}] expr {$::sqlite_io_error_pending>0 || $r!=0} } {1} } set ::sqlite_io_error_pending 0 rename opendb "" db close catch {file delete -force test.db} catch {file delete -force test.db-journal} finish_test |
Changes to test/btree.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # # $Id: btree.test,v 1.35 2005/01/11 10:25:07 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable default_autovacuum { finish_test |
︙ | ︙ | |||
193 194 195 196 197 198 199 | do_test btree-3.20.1 { btree_next $::c1 btree_key $::c1 } {0} do_test btree-3.20.2 { btree_eof $::c1 } {1} | > > > | | | | | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | do_test btree-3.20.1 { btree_next $::c1 btree_key $::c1 } {0} do_test btree-3.20.2 { btree_eof $::c1 } {1} # This test case used to test that one couldn't request data from an # invalid cursor. That is now an assert()ed condition. # # do_test btree-3.21 { # set rc [catch {btree_data $::c1} res] # lappend rc $res # } {1 SQLITE_INTERNAL} # Commit the changes, reopen and reread the data # do_test btree-3.22 { set rc [catch {btree_close_cursor $::c1} msg] lappend rc $msg } {0 {}} |
︙ | ︙ | |||
274 275 276 277 278 279 280 | do_test btree-3.38 { btree_data $::c1 } {6.00} do_test btree-3.39 { btree_next $::c1 btree_key $::c1 } {0} | > > > | | | | | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | do_test btree-3.38 { btree_data $::c1 } {6.00} do_test btree-3.39 { btree_next $::c1 btree_key $::c1 } {0} # This test case used to test that requesting data from an invalid cursor # returned SQLITE_INTERNAL. That is now an assert()ed condition. # # do_test btree-3.40 { # set rc [catch {btree_data $::c1} res] # lappend rc $res # } {1 SQLITE_INTERNAL} do_test btree-3.41 { lindex [btree_pager_stats $::b1] 1 } {1} # Now try a delete # |
︙ | ︙ | |||
485 486 487 488 489 490 491 | lindex [btree_get_meta $::b1] 0 } {0} do_test btree-6.9 { set ::c2 [btree_cursor $::b1 $::t2 1] lindex [btree_pager_stats $::b1] 1 } {2} | > > > | | | | | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 | lindex [btree_get_meta $::b1] 0 } {0} do_test btree-6.9 { set ::c2 [btree_cursor $::b1 $::t2 1] lindex [btree_pager_stats $::b1] 1 } {2} # This test case used to test that requesting the key from an invalid cursor # returned an empty string. But that is now an assert()ed condition. # # do_test btree-6.9.1 { # btree_move_to $::c2 {} # btree_key $::c2 # } {} # If we drop table 1 it just clears the table. Table 1 always exists. # do_test btree-6.10 { btree_close_cursor $::c2 btree_drop_table $::b1 1 set ::c2 [btree_cursor $::b1 $::t2 1] |
︙ | ︙ | |||
1031 1032 1033 1034 1035 1036 1037 | btree_rollback $::b1 lindex [btree_pager_stats $::b1] 1 } {0} btree_pager_ref_dump $::b1 # Miscellaneous tests. # | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 | btree_rollback $::b1 lindex [btree_pager_stats $::b1] 1 } {0} btree_pager_ref_dump $::b1 # Miscellaneous tests. # # btree-16.1 - Check that a statement cannot be started if a transaction # is not active. # btree-16.2 - Check that it is an error to request more payload from a # btree entry than the entry contains. do_test btree-16.1 { catch {btree_begin_statement $::b1} msg set msg } SQLITE_ERROR do_test btree-16.2 { btree_begin_transaction $::b1 set ::c1 [btree_cursor $::b1 2 1] btree_insert $::c1 1 helloworld btree_close_cursor $::c1 btree_commit $::b1 } {} do_test btree-16.3 { set ::c1 [btree_cursor $::b1 2 1] btree_first $::c1 } 0 do_test btree-16.4 { catch {btree_data $::c1 [expr [btree_payload_size $::c1] + 10]} msg set msg } SQLITE_ERROR if {$tcl_platform(platform)=="unix"} { do_test btree-16.5 { btree_close $::b1 set ::origperm [file attributes test1.bt -permissions] file attributes test1.bt -permissions o-w,g-w,a-w set ::b1 [btree_open test1.bt 2000 0] catch {btree_cursor $::b1 2 1} msg file attributes test1.bt -permissions $::origperm btree_close $::b1 set ::b1 [btree_open test1.bt 2000 0] set msg } {SQLITE_READONLY} } do_test btree-16.6 { set ::c1 [btree_cursor $::b1 2 1] set ::c2 [btree_cursor $::b1 2 1] btree_begin_transaction $::b1 for {set i 0} {$i<100} {incr i} { btree_insert $::c1 $i [string repeat helloworld 10] } btree_last $::c2 btree_insert $::c1 100 [string repeat helloworld 10] } {} do_test btree-16.7 { btree_close_cursor $::c1 btree_close_cursor $::c2 btree_commit $::b1 set ::c1 [btree_cursor $::b1 2 1] catch {btree_insert $::c1 101 helloworld} msg set msg } {SQLITE_ERROR} do_test btree-16.8 { btree_first $::c1 catch {btree_delete $::c1} msg set msg } {SQLITE_ERROR} do_test btree-16.9 { btree_close_cursor $::c1 btree_begin_transaction $::b1 set ::c1 [btree_cursor $::b1 2 0] catch {btree_insert $::c1 101 helloworld} msg set msg } {SQLITE_PERM} do_test btree-16.10 { catch {btree_delete $::c1} msg set msg } {SQLITE_PERM} do_test btree-16.11 { btree_close_cursor $::c1 set ::c2 [btree_cursor $::b1 2 1] set ::c1 [btree_cursor $::b1 2 0] catch {btree_insert $::c2 101 helloworld} msg set msg } {SQLITE_LOCKED} do_test btree-16.12 { btree_first $::c2 catch {btree_delete $::c2} msg set msg } {SQLITE_LOCKED} do_test btree-16.13 { catch {btree_clear_table $::b1 2} msg set msg } {SQLITE_LOCKED} do_test btree-16.14 { btree_close_cursor $::c1 btree_close_cursor $::c2 btree_commit $::b1 catch {btree_clear_table $::b1 2} msg set msg } {SQLITE_ERROR} do_test btree-16.15 { catch {btree_drop_table $::b1 2} msg set msg } {SQLITE_ERROR} do_test btree-16.16 { btree_begin_transaction $::b1 set ::c1 [btree_cursor $::b1 2 0] catch {btree_drop_table $::b1 2} msg set msg } {SQLITE_LOCKED} do_test btree-99.1 { btree_close $::b1 } {} catch {unset data} catch {unset key} finish_test |
Changes to test/btree2.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # # $Id: btree2.test,v 1.14 2005/01/11 10:25:07 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl if {[info commands btree_open]!=""} { |
︙ | ︙ | |||
139 140 141 142 143 144 145 | btree_move_to $::c4 {} btree_move_to $::c2 N set N [btree_data $::c2] btree_move_to $::c2 L set L [btree_data $::c2] set LM1 [expr {$L-1}] for {set i 1} {$i<=$N} {incr i} { | > > | > > > | > | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | btree_move_to $::c4 {} btree_move_to $::c2 N set N [btree_data $::c2] btree_move_to $::c2 L set L [btree_data $::c2] set LM1 [expr {$L-1}] for {set i 1} {$i<=$N} {incr i} { set key {} if {![btree_eof $::c3]} { set key [btree_key $::c3] } if {[scan $key %d k]<1} {set k 0} if {$k!=$i} { set key {} if {![btree_eof $::c4]} { set key [btree_key $::c4] } if {[scan $key %d k]<1} {set k 0} if {$k!=$i} { return "Key $i is missing from both foreground and background" } set data [btree_data $::c4] btree_next $::c4 } else { |
︙ | ︙ | |||
248 249 250 251 252 253 254 | } set data [make_payload $k $L $datalen] set basekey [format $format $k] if {[set c [btree_move_to $::c3 $basekey]]==0} { btree_delete $::c3 } else { if {$c<0} {btree_next $::c3} | > | | > > | | | | > > > | > | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | } set data [make_payload $k $L $datalen] set basekey [format $format $k] if {[set c [btree_move_to $::c3 $basekey]]==0} { btree_delete $::c3 } else { if {$c<0} {btree_next $::c3} if {![btree_eof $::c3]} { if {[string match $basekey* [btree_key $::c3]]} { btree_delete $::c3 } } } if {[set c [btree_move_to $::c4 $basekey]]==0} { btree_delete $::c4 } else { if {$c<0} {btree_next $::c4} if {![btree_eof $::c4]} { if {[string match $basekey* [btree_key $::c4]]} { btree_delete $::c4 } } } set kx -1 if {![btree_eof $::c4]} { if {[scan [btree_key $::c4] %d kx]<1} {set kx -1} } if {$kx==$k} { btree_delete $::c4 } # For debugging - change the "0" to "1" to integrity check after # every change. if 0 { incr chngcnt |
︙ | ︙ |
Added test/corrupt2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | # 2004 August 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to make sure SQLite does not crash or # segfault if it sees a corrupt database file. # # $Id: corrupt2.test,v 1.1 2005/01/11 10:25:07 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # The following tests - corrupt2-1.* - create some databases corrupted in # specific ways and ensure that SQLite detects them as corrupt. # do_test corrupt2-1.1 { execsql { CREATE TABLE abc(a, b, c); } } {} do_test corrupt2-1.2 { # Corrupt the 16 byte magic string at the start of the file file delete -force corrupt.db file delete -force corrupt.db-journal file copy test.db corrupt.db set f [open corrupt.db a] seek $f 8 start puts $f blah close $f sqlite3 db2 corrupt.db catchsql { SELECT * FROM sqlite_master; } db2 } {1 {file is encrypted or is not a database}} do_test corrupt2-1.3 { db2 close # Corrupt the page-size (bytes 16 and 17 of page 1). file delete -force corrupt.db file delete -force corrupt.db-journal file copy test.db corrupt.db set f [open corrupt.db a] fconfigure $f -encoding binary seek $f 16 start puts -nonewline $f "\x00\xFF" close $f sqlite3 db2 corrupt.db catchsql { SELECT * FROM sqlite_master; } db2 } {1 {file is encrypted or is not a database}} do_test corrupt2-1.4 { db2 close # Corrupt the free-block list on page 1. file delete -force corrupt.db file delete -force corrupt.db-journal file copy test.db corrupt.db set f [open corrupt.db a] fconfigure $f -encoding binary seek $f 101 start puts -nonewline $f "\xFF\xFF" close $f sqlite3 db2 corrupt.db catchsql { SELECT * FROM sqlite_master; } db2 } {1 {database disk image is malformed}} do_test corrupt2-1.5 { db2 close # Corrupt the free-block list on page 1. file delete -force corrupt.db file delete -force corrupt.db-journal file copy test.db corrupt.db set f [open corrupt.db a] fconfigure $f -encoding binary seek $f 101 start puts -nonewline $f "\x00\xC8" seek $f 200 start puts -nonewline $f "\x00\x00" puts -nonewline $f "\x10\x00" close $f sqlite3 db2 corrupt.db catchsql { SELECT * FROM sqlite_master; } db2 } {1 {database disk image is malformed}} db2 close finish_test |
Changes to test/ioerr.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # This file implements regression tests for SQLite library. The # focus of this file is testing for correct handling of I/O errors # such as writes failing because the disk is full. # # The tests in this file use special facilities that are only # available in the SQLite test fixture. # | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # This file implements regression tests for SQLite library. The # focus of this file is testing for correct handling of I/O errors # such as writes failing because the disk is full. # # The tests in this file use special facilities that are only # available in the SQLite test fixture. # # $Id: ioerr.test,v 1.9 2005/01/11 10:25:07 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set ::AV [execsql {pragma auto_vacuum}] set ::go 1 |
︙ | ︙ | |||
128 129 130 131 132 133 134 135 136 137 138 | set ::go [expr {$::sqlite_io_error_pending<=0}] expr {$::sqlite_io_error_pending>0 || $r!=0} set ::sqlite_io_error_pending 0 db close sqlite3 db test.db cksum } $cksum } set ::sqlite_io_error_pending 0 finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | set ::go [expr {$::sqlite_io_error_pending<=0}] expr {$::sqlite_io_error_pending>0 || $r!=0} set ::sqlite_io_error_pending 0 db close sqlite3 db test.db cksum } $cksum } set ::sqlite_io_error_pending 0 set ::go 1 for {set n 1} {$go} {incr n} { do_test ioerr-3.$n.1 { set ::sqlite_io_error_pending 0 db close catch {file delete -force test.db} catch {file delete -force test.db-journal} sqlite3 db test.db execsql { PRAGMA cache_size = 10; BEGIN; CREATE TABLE abc(a); INSERT INTO abc VALUES(randstr(1500,1500)); -- Page 4 is overflow } for {set i 0} {$i<150} {incr i} { execsql { INSERT INTO abc VALUES(randstr(100,100)); } } execsql COMMIT } {} do_test ioerr-3.$n.2 [subst { set ::sqlite_io_error_pending $n }] $n do_test ioerr-3.$n.3 { set r [catch {db eval { CREATE TABLE abc2(a); BEGIN; DELETE FROM abc WHERE length(a)>100; UPDATE abc SET a = randstr(90,90); COMMIT; CREATE TABLE abc3(a); }} msg] set ::go [expr {$::sqlite_io_error_pending<=0}] expr {$::sqlite_io_error_pending>0 || $r!=0} } {1} } set ::sqlite_io_error_pending 0 finish_test |