diff --git a/manifest b/manifest index 6a0c78dbcd..4b8c8da745 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Extra\stest\scases\sto\simprove\scoverage\sof\sbtree.c\s(CVS\s2189) -D 2005-01-10T12:59:52 +C Test\scases\sto\simprove\scoverage\sof\sbtree.c\s(and\sminor\sbugfixes).\s(CVS\s2190) +D 2005-01-11T10:25:07 F Makefile.in ecf441ac5ca1ccfc8748a8a9537706e69893dfa4 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -29,7 +29,7 @@ F sqlite3.def dbaeb20c153e1d366e8f421b55a573f5dfc00863 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689 F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea -F src/btree.c 241e27b4640519a45ab55d35ee3ae300a478eb23 +F src/btree.c 5ec669c8839d98dd9e283cc6d4547da4adb37a81 F src/btree.h 861e40b759a195ba63819740e484390012cf81ab F src/build.c af1296e8a21a406b4f4c4f1e1365e075071219f3 F src/cursor.c f883813759742068890b1f699335872bfa8fdf41 @@ -53,10 +53,10 @@ F src/os_unix.c 08340c864822115bf87c6c1735780a0996278b81 F src/os_unix.h f3097815e041e82e24d92505e1ff61ba24172d13 F src/os_win.c 3c0b0a3bc33318cf555a1cd130232ad1b9a5a711 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c 4a14410a4e67173bb121a919c7f2033b93822186 +F src/pager.c c6b29d55c9755f35bd9d711865aaf83e410f730f F src/pager.h 9eba8c53dd91eae7f3f90743b2ee242da02a9862 F src/parse.y ceba179b9703657180963568f54b0e75f33e36e1 -F src/pragma.c 1b6f9f4caa2c441b18bf0c8793a4b4b8f3214d03 +F src/pragma.c ac594f74c90ffec043c43e49358719ffeb491eec F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c af6ffcf0201f8f4e2697eea25689077dc61c6109 @@ -76,7 +76,7 @@ F src/update.c 0979397c41ac29c54fe0cc687a356d8629a633af F src/utf.c e45ce11be6922408cd381561721f6cca7d3b992a F src/util.c 29f43c4a7b9ff29302f7899f793be6836b6cd7f9 F src/vacuum.c 1a9db113a027461daaf44724c71dd1ebbd064203 -F src/vdbe.c 53520958a7d63eaf138fa78f69efe225d502a9bf +F src/vdbe.c c9f00cc0298e025e61b4b65555a4a23dd13325dd F src/vdbe.h 067ca8d6750ba4f69a50284765e5883dee860181 F src/vdbeInt.h 0f74561e629af86172de7cdf0ecaea014c51696c F src/vdbeapi.c 0cf3bdc1072616bedc8eec7fc22e3f5a169d33fd @@ -93,12 +93,14 @@ F test/auth.test 559e0816b8100740624ebb0ab7aab05f5c92831c F test/autoinc.test c071e51ff167b8e889212273588d9cca71845b70 F test/autovacuum.test a4e8da39a6268378c4f9fc17fe2df1d5be16d631 F test/autovacuum_crash.test 2dca85cbcc497098e45e8847c86407eb3554f3d4 +F test/autovacuum_ioerr.test 55ea907df34edb9be78a910a1636c2eb3c17ecc4 +F test/autovacuum_ioerr2.test bf427c86e4daa8638a2eb849bbe1446c234c73d3 F test/bigfile.test d3744a8821ce9abb8697f2826a3e3d22b719e89f F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747 F test/bind.test 3635ddfe0fb15ecfd158708feff6ef707e15c0a9 F test/blob.test fc41fe95bdc10da51f0dee73ce86e75ce1d6eb9d -F test/btree.test ff754a2e68af75396fbbf8dfda009b4b93f086a6 -F test/btree2.test aa4a6d05b1ea90b1acaf83ba89039dd302a88635 +F test/btree.test 8aa7424aeec844df990273fe36447e5d7e407261 +F test/btree2.test dbce930b549d5ac883a7d8905c976209ea241db3 F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4 F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2 F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027 @@ -114,6 +116,7 @@ F test/collate5.test 7999fb3122386bae38acd8ccd61e0b7c5a30e289 F test/collate6.test 6c9470d1606ee3e564675b229653e320c49ec638 F test/conflict.test c5b849b01cfbe0a4f63a90cba6f68e2fe3a75f87 F test/corrupt.test 0080ddcece23e8ba47c44608c4fb73fd4d1d8ce2 +F test/corrupt2.test cb1f813df7559de3021e01170af0bba31507a9a5 F test/crash.test 637479504e137d065385c5b9379680d2b5372630 F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 F test/cursor.test d7c65ea0fc4e321e12fbcf5c7f3e2211ef45379b @@ -134,7 +137,7 @@ F test/insert.test 56f9c20c9adc8d707490c4ffa5d4daa94826ea03 F test/insert2.test 0bb50ff999e35a21549d8ee5dc44db8ac24d31a7 F test/interrupt.test 0aa230f8aedec0ad7caaf5edaced337e4cfb3820 F test/intpkey.test b57cf5236fde1bd8cbc1388fa0c91908f6fd9194 -F test/ioerr.test fd283e768301b26bc148012ea6ebea4c2295aa20 +F test/ioerr.test b37837850294c6cbafb0fd5211a4df40b10d46af F test/join.test ea8c77b9fbc377fe553cdb5ce5f1bd72021dca5d F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8 F test/join3.test 67dc0d7c8dab3fff25796d0f3c3fd9c999aeded3 @@ -263,7 +266,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl c3b50d3ac31c54be2a1af9b488a89d22f1e6e746 -P 5b7a5a4d69be425163135698d889797d15f56492 -R 8f87d57733bba8a8bebba0892812901d +P a461988661368bce799ef3d498a18e88559e14c7 +R 9631300063f5d334400b6e5706977e76 U danielk1977 -Z 23146f967500dcd597b4ae335d7f01e0 +Z 6f3669f1f4cea6222a3e8648182fde70 diff --git a/manifest.uuid b/manifest.uuid index bbc8e6ad96..743e01d3ce 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a461988661368bce799ef3d498a18e88559e14c7 \ No newline at end of file +8ced491588764b1e1066787d0abf3cde8b60970b \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 7fed5ee6fa..5551b0c02c 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.229 2005/01/10 12:59:52 danielk1977 Exp $ +** $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 @@ -356,7 +356,6 @@ struct BtCursor { 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 */ - u8 status; /* Set to SQLITE_ABORT if cursors is invalidated */ }; /* @@ -953,7 +952,6 @@ static int initPage( MemPage *pParent /* The parent. Might be NULL */ ){ int pc; /* Address of a freeblock within pPage->aData[] */ - int i; /* Loop counter */ int hdr; /* Offset to beginning of page header */ u8 *data; /* Equal to pPage->aData */ Btree *pBt; /* The main btree structure */ @@ -997,17 +995,12 @@ static int initPage( /* Compute the total free space on the page */ pc = get2byte(&data[hdr+1]); nFree = data[hdr+7] + top - (cellOffset + 2*pPage->nCell); - i = 0; while( pc>0 ){ int next, size; if( pc>usableSize-4 ){ /* Free block is off the page */ return SQLITE_CORRUPT; /* bkpt-CORRUPT */ } - if( i++>SQLITE_MAX_PAGE_SIZE/4 ){ - /* The free block list forms an infinite loop */ - return SQLITE_CORRUPT; /* bkpt-CORRUPT */ - } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); if( next>0 && next<=pc+size+3 ){ @@ -1295,6 +1288,9 @@ int sqlite3BtreeSetSafetyLevel(Btree *pBt, int level){ ** 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 ){ @@ -1904,6 +1900,7 @@ static void invalidateCursors(Btree *pBt){ ** 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; @@ -1914,6 +1911,7 @@ void sqlite3BtreeCursorList(Btree *pBt){ pCur->isValid ? "" : " eof" ); } +#endif } #endif @@ -2117,7 +2115,6 @@ int sqlite3BtreeCursor( pCur->pPrev = 0; pBt->pCursor = pCur; pCur->isValid = 0; - pCur->status = SQLITE_OK; *ppCur = pCur; return SQLITE_OK; @@ -2344,9 +2341,7 @@ static int getPayload( ** the available payload. */ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ - if( !pCur->isValid ){ - return pCur->status; - } + assert( pCur->isValid ); assert( pCur->pPage!=0 ); assert( pCur->pPage->intKey==0 ); assert( pCur->idx>=0 && pCur->idxpPage->nCell ); @@ -2363,9 +2358,7 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ ** the available payload. */ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ - if( !pCur->isValid ){ - return pCur->status ? pCur->status : SQLITE_INTERNAL; - } + assert( pCur->isValid ); assert( pCur->pPage!=0 ); assert( pCur->idx>=0 && pCur->idxpPage->nCell ); return getPayload(pCur, offset, amt, pBuf, 1); @@ -2603,9 +2596,6 @@ static int moveToRightmost(BtCursor *pCur){ */ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int rc; - if( pCur->status ){ - return pCur->status; - } rc = moveToRoot(pCur); if( rc ) return rc; if( pCur->isValid==0 ){ @@ -2625,9 +2615,6 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ */ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ int rc; - if( pCur->status ){ - return pCur->status; - } rc = moveToRoot(pCur); if( rc ) return rc; if( pCur->isValid==0 ){ @@ -2670,10 +2657,6 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ */ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){ int rc; - - if( pCur->status ){ - return pCur->status; - } rc = moveToRoot(pCur); if( rc ) return rc; assert( pCur->pPage ); @@ -3274,7 +3257,7 @@ static int fillInCell( #endif if( rc ){ releasePage(pToRelease); - clearCell(pPage, pCell); + /* clearCell(pPage, pCell); */ return rc; } put4byte(pPrior, pgnoOvfl); @@ -3873,7 +3856,8 @@ static int balance_nonroot(MemPage *pPage){ pNew = apNew[i] = apOld[i]; pgnoNew[i] = pgnoOld[i]; apOld[i] = 0; - sqlite3pager_write(pNew->aData); + 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; @@ -4236,9 +4220,6 @@ int sqlite3BtreeInsert( unsigned char *oldCell; unsigned char *newCell = 0; - if( pCur->status ){ - return pCur->status; /* A rollback destroyed this cursor */ - } if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction before doing an insert */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; @@ -4310,9 +4291,6 @@ int sqlite3BtreeDelete(BtCursor *pCur){ Btree *pBt = pCur->pBt; assert( pPage->isInit ); - if( pCur->status ){ - return pCur->status; /* A rollback destroyed this cursor */ - } if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction before doing a delete */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; @@ -4338,7 +4316,8 @@ int sqlite3BtreeDelete(BtCursor *pCur){ if( !pPage->leaf ){ pgnoChild = get4byte(pCell); } - clearCell(pPage, pCell); + rc = clearCell(pPage, pCell); + if( rc ) return rc; if( !pPage->leaf ){ /* @@ -4410,9 +4389,7 @@ int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){ /* Must start a transaction first */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } - if( pBt->readOnly ){ - return SQLITE_READONLY; - } + 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 @@ -4771,6 +4748,7 @@ int sqlite3BtreeFlags(BtCursor *pCur){ ** 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; @@ -4867,8 +4845,11 @@ static int btreePageDump(Btree *pBt, int pgno, int recursive, MemPage *pParent){ 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 diff --git a/src/pager.c b/src/pager.c index c59e3a8de3..9702f741f0 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.180 2005/01/08 12:42:39 danielk1977 Exp $ +** @(#) $Id: pager.c,v 1.181 2005/01/11 10:25:08 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -935,12 +935,14 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){ rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize); } if( pPg ){ - /* No page should ever be 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. + /* 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 ); + /* 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? ***/ diff --git a/src/pragma.c b/src/pragma.c index 53cdf663f0..7b9e151ef1 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.82 2005/01/08 15:44:26 drh Exp $ +** $Id: pragma.c,v 1.83 2005/01/11 10:25:08 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -285,7 +285,7 @@ void sqlite3Pragma( int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0; returnSingleInt(pParse, "page_size", size); }else{ - sqlite3BtreeSetPageSize(pBt, atoi(zRight), sqlite3BtreeGetReserve(pBt)); + sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1); } }else #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ diff --git a/src/vdbe.c b/src/vdbe.c index df61740eb0..a05345203d 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** 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.437 2005/01/10 12:59:53 danielk1977 Exp $ +** $Id: vdbe.c,v 1.438 2005/01/11 10:25:08 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -2565,12 +2565,18 @@ case OP_MoveGt: { pTos--; break; } - sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, &res); + 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); - sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); + rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); + if( rc!=SQLITE_OK ){ + goto abort_due_to_error; + } pC->recnoIsValid = 0; } pC->deferredMoveto = 0; @@ -2579,7 +2585,10 @@ case OP_MoveGt: { sqlite3_search_count++; if( oc==OP_MoveGe || oc==OP_MoveGt ){ if( res<0 ){ - sqlite3BtreeNext(pC->pCursor, &res); + rc = sqlite3BtreeNext(pC->pCursor, &res); + if( rc!=SQLITE_OK ){ + goto abort_due_to_error; + } pC->recnoIsValid = 0; }else{ res = 0; @@ -2800,12 +2809,14 @@ case OP_NotExists: { assert( pTos->flags & MEM_Int ); assert( p->apCsr[i]->intKey ); iKey = intToKey(pTos->i); - rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res); + // 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( rx!=SQLITE_OK || res!=0 ){ + if( res!=0 ){ pc = pOp->p2 - 1; pC->recnoIsValid = 0; } diff --git a/test/autovacuum_ioerr.test b/test/autovacuum_ioerr.test new file mode 100644 index 0000000000..e7584443c9 --- /dev/null +++ b/test/autovacuum_ioerr.test @@ -0,0 +1,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 + + + diff --git a/test/autovacuum_ioerr2.test b/test/autovacuum_ioerr2.test new file mode 100644 index 0000000000..9817f6d353 --- /dev/null +++ b/test/autovacuum_ioerr2.test @@ -0,0 +1,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 + + diff --git a/test/btree.test b/test/btree.test index ed719b687f..8e882951d9 100644 --- a/test/btree.test +++ b/test/btree.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # -# $Id: btree.test,v 1.34 2005/01/10 12:59:53 danielk1977 Exp $ +# $Id: btree.test,v 1.35 2005/01/11 10:25:07 danielk1977 Exp $ set testdir [file dirname $argv0] @@ -197,10 +197,13 @@ do_test btree-3.20.1 { do_test btree-3.20.2 { btree_eof $::c1 } {1} -do_test btree-3.21 { - set rc [catch {btree_data $::c1} res] - lappend rc $res -} {1 SQLITE_INTERNAL} +# 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 # @@ -278,10 +281,13 @@ do_test btree-3.39 { btree_next $::c1 btree_key $::c1 } {0} -do_test btree-3.40 { - set rc [catch {btree_data $::c1} res] - lappend rc $res -} {1 SQLITE_INTERNAL} +# 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} @@ -489,10 +495,13 @@ do_test btree-6.9 { lindex [btree_pager_stats $::b1] 1 } {2} -do_test btree-6.9.1 { - btree_move_to $::c2 {} - btree_key $::c2 -} {} +# 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. # @@ -1035,8 +1044,10 @@ 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.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 @@ -1058,6 +1069,89 @@ do_test btree-16.4 { 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 } {} diff --git a/test/btree2.test b/test/btree2.test index 65d32dfc1c..515ba8e76a 100644 --- a/test/btree2.test +++ b/test/btree2.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # -# $Id: btree2.test,v 1.13 2004/05/10 16:18:48 drh Exp $ +# $Id: btree2.test,v 1.14 2005/01/11 10:25:07 danielk1977 Exp $ set testdir [file dirname $argv0] @@ -143,10 +143,16 @@ proc check_invariants {} { set L [btree_data $::c2] set LM1 [expr {$L-1}] for {set i 1} {$i<=$N} {incr i} { - set key [btree_key $::c3] + 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 [btree_key $::c4] + 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" @@ -252,19 +258,26 @@ proc random_changes {n I K D} { btree_delete $::c3 } else { if {$c<0} {btree_next $::c3} - if {[string match $basekey* [btree_key $::c3]]} { - btree_delete $::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 {[string match $basekey* [btree_key $::c4]]} { - btree_delete $::c4 + if {![btree_eof $::c4]} { + if {[string match $basekey* [btree_key $::c4]]} { + btree_delete $::c4 + } } } - if {[scan [btree_key $::c4] %d kx]<1} {set kx -1} + set kx -1 + if {![btree_eof $::c4]} { + if {[scan [btree_key $::c4] %d kx]<1} {set kx -1} + } if {$kx==$k} { btree_delete $::c4 } diff --git a/test/corrupt2.test b/test/corrupt2.test new file mode 100644 index 0000000000..9b17fcaa67 --- /dev/null +++ b/test/corrupt2.test @@ -0,0 +1,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 + diff --git a/test/ioerr.test b/test/ioerr.test index 21e7ac4b59..06a32da33e 100644 --- a/test/ioerr.test +++ b/test/ioerr.test @@ -15,7 +15,7 @@ # The tests in this file use special facilities that are only # available in the SQLite test fixture. # -# $Id: ioerr.test,v 1.8 2005/01/10 12:59:53 danielk1977 Exp $ +# $Id: ioerr.test,v 1.9 2005/01/11 10:25:07 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -135,4 +135,43 @@ for {set n 1} {$go} {incr n} { } 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