diff --git a/manifest b/manifest index 43b17e8a6c..fd3f1155e2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\slocal\svariables\sinstead\sof\s#defines\sfor\sthe\smutex\sname\sand\slength\sin\sOS/2's\ssqlite3_mutex_alloc().\s(CVS\s4453) -D 2007-10-02T19:56:04 +C Add\sautomatic\srecovery\sfrom\sthe\spager\s"error-state".\sAlso\sadd\sa\snew\serror\scode\s-\sSQLITE_IOERR_NOMEM.\s(CVS\s4454) +D 2007-10-03T08:46:44 F Makefile.in cbfb898945536a8f9ea8b897e1586dd1fdbcc5db F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -78,10 +78,10 @@ F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a F src/alter.c c9f30b4d6fbf7eff7c5518b002a217d4ecd13bcf F src/analyze.c 49b4bd45eb286d833793ed6bf72355a5c1974865 -F src/attach.c 02fd8779270b1df1c63e7ba6e6655b960fa0f3d5 +F src/attach.c a01d55157d46a1234909f3a7f21fb09549c947bd F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/btmutex.c 442be6f068d77ca9ffd69899cf0a3943c244548c -F src/btree.c ed7c4825b0d30a8a77c43b468009cfa8a31c967a +F src/btree.c a491c45b4412e6f19458e122bafa0cca8f22d224 F src/btree.h d0736ebca4b6eafbdd823c46a8de574cea078211 F src/btreeInt.h 4330c19b8314545fdb209cc77e2a57f6a5290e9c F src/build.c 94d0d6dfd1e706c480903fbdda2e77466f21b898 @@ -99,17 +99,17 @@ F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2 F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66 F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35 F src/loadext.c 124e566563d1c03e68e1396cb44df9870612c6e9 -F src/main.c e69df8c9e56e06f54ef894481e56b26ba807d253 +F src/main.c 3040200e563e3f9a3c24198da48fd4d400d5c43a F src/malloc.c de4e77fe70a9a0ac47a1c3a874422b107231bf31 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/mem1.c 1f85902b98b38bd8a8b0c24012933957256db13e -F src/mem2.c b97b4662bf5902cbde0a849c4739e64ce7b07177 +F src/mem2.c 9c59519e471f858961fbdccd9543317bba1c5e58 F src/mutex.c 3259f62c2429967aee6dc112117a6d2f499ef061 F src/mutex.h 079fa6fe9da18ceb89e79012c010594c6672addb F src/mutex_os2.c 7fe4773e98ed74a63b2e54fc557929eb155f6269 F src/mutex_unix.c ff77650261a245035b79c5c8a174f4e05d3cae8a F src/mutex_w32.c d2c56fb81aca10af1577bdae2a4083eb2505f8ee -F src/os.c 3b66834a5853ddaa83dfd6c146be9e4fc1864b98 +F src/os.c 6a84b6ff284fa558e879d9b6a5809004aacc8195 F src/os.h 4c880cf67437f323cd0c3ab2154f1d76babc12d3 F src/os_common.h 98862f120ca6bf7a48ce8b16f158b77d00bc9d2f F src/os_os2.c 5b5f42180c5961b9d207748fda8f9aa0e70569c8 @@ -120,19 +120,19 @@ F src/os_unix.c 308bd8ad6977f66f608228cccaecc4cbc1a24693 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_win.c 99960c7b9dad8dab72e47068afb7941492bfeaac F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c d246d888bbdbb97321238f5f71d2f6727b2cc9d8 +F src/pager.c 40381e1650e7acc7d594a236cea6514f0859993f F src/pager.h d783e7f184afdc33adff37ba58d4e029bd8793b3 F src/parse.y 2d2ce439dc6184621fb0b86f4fc5aca7f391a590 F src/pragma.c 363e548dafb52327face8d99757ab56a7b1c1b26 -F src/prepare.c 1506fd279824b1f4bac97514966d0370101f9a6b +F src/prepare.c 920d09a5fc690ccd48ec8c82717a11d53365dae3 F src/printf.c 85f7a4344dda6782a76df43da8e4d5b0342d6b85 F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da F src/select.c 4706a6115da1bdc09a2be5991168a6cc2c0df267 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 82089379833e361ba8a2ae65316a2173785300c0 -F src/sqlite.h.in 60d1a884f49304787b07864ceba31e6df93a5a7c +F src/sqlite.h.in 28746e34b4ada1cecc49768844064d3f1c7fd78e F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb -F src/sqliteInt.h 8fb50cf69b235dfe7f3b604d4d219a9726b8478c +F src/sqliteInt.h 9092213f1ff14cd7edee8d0649d8a193dbbad4b2 F src/sqliteLimit.h 1bcbbdfa856f8b71b561abb31edb864b0eca1d12 F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4 F src/tclsqlite.c 9659ec914abfdb35e184eee908d07eba11a39018 @@ -161,7 +161,7 @@ F src/test_thread.c a98d69cae883e53d3686fc25889a5fa5f51439f8 F src/tokenize.c 67e42600ab34f976f2b1288c499ad6c98d652f0e F src/trigger.c 724a77d54609a33bde90618934fbeddfcc729a10 F src/update.c e89b980b443d44b68bfc0b1746cdb6308e049ac9 -F src/utf.c e8c72a123570061b8088d929e403d4fc09193be7 +F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736 F src/util.c 49263637e0f228411201501ddfd1138338d6322c F src/vacuum.c 38745037c63246d1b0669038257890cf89fc4578 F src/vdbe.c b6c53921512496ef4d7c4f571feb73b7a495db35 @@ -180,7 +180,7 @@ F test/all.test b59d1bd8b0c1d4a08b845e8af48fd43926f01f11 F test/alter.test c2a9402e17a731e5294ef370214bd9f88351d18d F test/alter2.test 816574fd9302af05e95895758aff2811090c6c78 F test/alter3.test a6eec8f454be9b6ce73d8d7dc711453675a10ce7 -F test/altermalloc.test 1f4d2d66750bea1a78cd9f0b7dba5bfb155dd6cf +F test/altermalloc.test 29d4a8400277efb4ba8ffe90804c6dc2fdfbf063 F test/analyze.test 2f55535aa335785db1a2f97d3f3831c16c09f8b0 F test/async.test ae370c6169e314f0f82dcbe59fbc8589b23dfc2f F test/async2.test e56affa75ed822424a6f9b12b22db8031433bb7c @@ -188,7 +188,7 @@ F test/async3.test 08ea0217083e4866eb1b0147158298f2a2cd1346 F test/attach.test 8880661ee05a7fdeb2d3868e66c08aab21cec8f1 F test/attach2.test 78bc1a25ea8785c7571b44f5947ada2bd5d78127 F test/attach3.test eafcafb107585aecc2ed1569a77914138eef46a9 -F test/attachmalloc.test fdbfd9dc0b600db14f9189690c6c12511cc3a56f +F test/attachmalloc.test 475c95e9d5756318f62226e2d2299e64ecdbc543 F test/auth.test 66923137cf78475f5671b5e6e6274935e055aea0 F test/auth2.test 8da06f0ffcfd98154dda78e0f3b35a6503c27b64 F test/autoinc.test 60005a676e3e4e17dfa9dbd08aa0b76587ff97e3 @@ -349,20 +349,20 @@ F test/lock2.test 5f9557b775662c2a5ee435378f39e10d64f65cb3 F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9 F test/lock4.test f358fa835dff485d462072eee991111f09e87441 F test/main.test 05f585bb70c05caac3e047903b517cbb319ed204 -F test/malloc.test 51675aa9dba74480391e31d2b57e54e67d9169c1 -F test/malloc2.test c1a74f46a3581b56df29ff46a4e1c99b41c44ad9 -F test/malloc3.test d10a1f484805be103f154ce4968f76ba5d530217 +F test/malloc.test 17366a4f76e7aac14cd709e8209ef840cd497410 +F test/malloc2.test 1506ab3a4490b38b8850a6fa3e12591235179872 +F test/malloc3.test cf2efe9d16194276f227f34ac341019e013fb17d F test/malloc4.test f0e5e0f639f61e2776a6c3f5308f836b3ad8b3c7 F test/malloc5.test b2fd56b369dd5884ad88edfaef41304393809125 -F test/malloc6.test dfb0fcbe40abf18833ddefbe17b688dc665a4a5f +F test/malloc6.test d05fd71ef3c5983d10e0a6d728ea4a502a45a9e4 F test/malloc7.test 0d71bb6520b99934b551fa36a9c591404aeaad61 F test/malloc8.test addc27d907fec1af429551b95c72caa47fce2974 F test/malloc9.test 95d7069ad4fa262bf33bc4c5ca0a46f2bb2391cb F test/mallocA.test f474c5bdbef4070e11c89d01ba1b0e78f955b97a F test/mallocB.test 83bdbea443cc81758a57b0287807b0941218819a -F test/mallocC.test 7d3b19d2fee772ee309c21e0e31153f8df750f32 +F test/mallocC.test 6f02fa2b4baa943bc6d6db323d5d07067967e728 F test/mallocD.test 473db9092f962685ca5710a153d2abbe3428bb9e -F test/malloc_common.tcl 6cd3c6b540cd53dea828ee2b15a2b72b297b7b30 +F test/malloc_common.tcl b47137fb36e95fdafb0267745afefcd6b0a5b9dc F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8 F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893 F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217 @@ -378,7 +378,7 @@ F test/misc7.test a67af9620a510ce19f96ba69f3848228b7c62a73 F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33 F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82 F test/null.test 9503e1f63e959544c006d9f01709c5b5eab67d54 -F test/onefile.test 3b907ebfa5cc2ecd31d918776bb43fdf432b6618 +F test/onefile.test b9cce375fd2a41ee3afa79a0a808954046b74458 F test/openv2.test f5dd6b23e4dce828eb211649b600763c42a668df F test/pager.test 60303481b22b240c18d6dd1b64edcecc2f4b5a97 F test/pager2.test c025f91b75fe65e85febda64d9416428b8a5cab5 @@ -580,7 +580,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P eb5d78451ee2a5d8480537530f30fbb305bf7632 -R a8abd8d07626f709082a5e1aa7c6fdec -U pweilbacher -Z 73d6f9cab3860483d902ed77f0494d38 +P 272959cc91d0c9299d6fca8a962eb563650af87b +R e48ace1bd2100159c32ec15d9bfa3f76 +U danielk1977 +Z d1e46257f1f89b59b016148eed84362d diff --git a/manifest.uuid b/manifest.uuid index 74f3abffd6..41b049d87a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -272959cc91d0c9299d6fca8a962eb563650af87b \ No newline at end of file +12eca32a6a3d68d5b20eed03afdffe7599e66014 \ No newline at end of file diff --git a/src/attach.c b/src/attach.c index 3c2f6a63d6..2fb950fd4a 100644 --- a/src/attach.c +++ b/src/attach.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. ** -** $Id: attach.c,v 1.62 2007/09/03 15:19:35 drh Exp $ +** $Id: attach.c,v 1.63 2007/10/03 08:46:44 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -200,7 +200,7 @@ static void attachFunc( } sqlite3ResetInternalSchema(db, 0); db->nDb = iDb; - if( rc==SQLITE_NOMEM ){ + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ db->mallocFailed = 1; sqlite3_snprintf(sizeof(zErr),zErr, "out of memory"); }else{ diff --git a/src/btree.c b/src/btree.c index 99147fb84d..de8821a900 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.427 2007/09/17 07:02:57 danielk1977 Exp $ +** $Id: btree.c,v 1.428 2007/10/03 08:46:44 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -2585,13 +2585,11 @@ int sqlite3BtreeRollbackStmt(Btree *p){ int rc = SQLITE_OK; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); - sqlite3MallocDisallow(); if( pBt->inStmt && !pBt->readOnly ){ rc = sqlite3PagerStmtRollback(pBt->pPager); assert( countWriteCursors(pBt)==0 ); pBt->inStmt = 0; } - sqlite3MallocAllow(); sqlite3BtreeLeave(p); return rc; } diff --git a/src/main.c b/src/main.c index 0a4c721cd1..f56ade4d5d 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.404 2007/09/03 15:19:35 drh Exp $ +** $Id: main.c,v 1.405 2007/10/03 08:46:45 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -234,6 +234,7 @@ void sqlite3RollbackAll(sqlite3 *db){ int i; int inTrans = 0; assert( sqlite3_mutex_held(db->mutex) ); + sqlite3MallocEnterBenignBlock(1); /* Enter benign region */ for(i=0; inDb; i++){ if( db->aDb[i].pBt ){ if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){ @@ -244,6 +245,8 @@ void sqlite3RollbackAll(sqlite3 *db){ } } sqlite3VtabRollback(db); + sqlite3MallocLeaveBenignBlock(0); /* Leave benign region */ + if( db->flags&SQLITE_InternChanges ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetInternalSchema(db, 0); diff --git a/src/mem2.c b/src/mem2.c index 830c5dc43f..7c509fff49 100644 --- a/src/mem2.c +++ b/src/mem2.c @@ -12,7 +12,7 @@ ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** -** $Id: mem2.c,v 1.13 2007/09/01 09:02:54 danielk1977 Exp $ +** $Id: mem2.c,v 1.14 2007/10/03 08:46:45 danielk1977 Exp $ */ /* @@ -141,6 +141,7 @@ static struct { int iFailCnt; /* Number of failures */ int iBenignFailCnt; /* Number of benign failures */ int iNextIsBenign; /* True if the next call to malloc may fail benignly */ + int iIsBenign; /* All malloc calls may fail benignly */ /* ** sqlite3MallocDisallow() increments the following counter. @@ -281,7 +282,7 @@ void *sqlite3_malloc(int nByte){ sqlite3MemsysFailed(); /* A place to set a breakpoint */ } mem.iFailCnt++; - if( mem.iNextIsBenign ){ + if( mem.iNextIsBenign || mem.iIsBenign ){ mem.iBenignFailCnt++; } }else{ @@ -494,11 +495,33 @@ int sqlite3_memdebug_pending(){ return (mem.iFail-1); } +/* +** The following three functions are used to indicate to the test +** infrastructure which malloc() calls may fail benignly without +** affecting functionality. This can happen when resizing hash tables +** (failing to resize a hash-table is a performance hit, but not an +** error) or sometimes during a rollback operation. +** +** If the argument is true, sqlite3MallocBenignFailure() indicates that the +** next call to allocate memory may fail benignly. +** +** If sqlite3MallocEnterBenignBlock() is called with a non-zero argument, +** then all memory allocations requested before the next call to +** sqlite3MallocLeaveBenignBlock() may fail benignly. +*/ void sqlite3MallocBenignFailure(int isBenign){ if( isBenign ){ mem.iNextIsBenign = 1; } } +void sqlite3MallocEnterBenignBlock(int isBenign){ + if( isBenign ){ + mem.iIsBenign = 1; + } +} +void sqlite3MallocLeaveBenignBlock(){ + mem.iIsBenign = 0; +} /* ** The following two routines are used to assert that no memory diff --git a/src/os.c b/src/os.c index 28de37da01..3b6ca7bcaf 100644 --- a/src/os.c +++ b/src/os.c @@ -17,6 +17,33 @@ #include "sqliteInt.h" #undef _SQLITE_OS_C_ +/* +** The default SQLite sqlite3_vfs implementations do not allocate +** memory (actually, os_unix.c allocates a small amount of memory +** from within OsOpen()), but some third-party implementations may. +** So we test the effects of a malloc() failing and the sqlite3OsXXX() +** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro. +** +** The following functions are instrumented for malloc() failure +** testing: +** +** sqlite3OsOpen() +** sqlite3OsRead() +** sqlite3OsWrite() +** sqlite3OsSync() +** sqlite3OsLock() +** +*/ +#ifdef SQLITE_TEST + #define DO_OS_MALLOC_TEST if (1) { \ + void *pTstAlloc = sqlite3_malloc(10); \ + if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \ + sqlite3_free(pTstAlloc); \ + } +#else + #define DO_OS_MALLOC_TEST +#endif + /* ** The following routines are convenience wrappers around methods ** of the sqlite3_file object. This is mostly just syntactic sugar. All @@ -32,21 +59,25 @@ int sqlite3OsClose(sqlite3_file *pId){ return rc; } int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){ + DO_OS_MALLOC_TEST; return id->pMethods->xRead(id, pBuf, amt, offset); } int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){ + DO_OS_MALLOC_TEST; return id->pMethods->xWrite(id, pBuf, amt, offset); } int sqlite3OsTruncate(sqlite3_file *id, i64 size){ return id->pMethods->xTruncate(id, size); } int sqlite3OsSync(sqlite3_file *id, int flags){ + DO_OS_MALLOC_TEST; return id->pMethods->xSync(id, flags); } int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ return id->pMethods->xFileSize(id, pSize); } int sqlite3OsLock(sqlite3_file *id, int lockType){ + DO_OS_MALLOC_TEST; return id->pMethods->xLock(id, lockType); } int sqlite3OsUnlock(sqlite3_file *id, int lockType){ @@ -99,6 +130,7 @@ int sqlite3OsOpen( int flags, int *pFlagsOut ){ + DO_OS_MALLOC_TEST; return pVfs->xOpen(pVfs, zPath, pFile, flags, pFlagsOut); } int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ diff --git a/src/pager.c b/src/pager.c index c442365e4b..6e12cc9b6c 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.390 2007/09/17 07:02:57 danielk1977 Exp $ +** @(#) $Id: pager.c,v 1.391 2007/10/03 08:46:45 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -809,9 +809,17 @@ static int jrnlBufferSize(Pager *pPager){ ** The value returned is a copy of the second argument to this function. ** ** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT, or SQLITE_FULL -** the error becomes persistent. All subsequent API calls on this Pager -** will immediately return the same error code. +** the error becomes persistent. Until the persisten error is cleared, +** subsequent API calls on this Pager will immediately return the same +** error code. +** +** A persistent error indicates that the contents of the pager-cache +** cannot be trusted. This state can be cleared by completely discarding +** the contents of the pager-cache. If a transaction was active when +** the persistent error occured, then the rollback journal may need +** to be replayed. */ +static void pager_unlock(Pager *pPager); static int pager_error(Pager *pPager, int rc){ int rc2 = rc & 0xff; assert( @@ -825,6 +833,13 @@ static int pager_error(Pager *pPager, int rc){ rc2==SQLITE_CORRUPT ){ pPager->errCode = rc; + if( pPager->state==PAGER_UNLOCK && pPager->nRef==0 ){ + /* If the pager is already unlocked, call pager_unlock() now to + ** clear the error state and ensure that the pager-cache is + ** completely empty. + */ + pager_unlock(pPager); + } } return rc; } @@ -1198,38 +1213,6 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ return p; } -/* -** Unlock the database file. -*/ -static void pager_unlock(Pager *pPager){ - if( !pPager->exclusiveMode ){ - if( !MEMDB ){ - osUnlock(pPager->fd, NO_LOCK); - pPager->dbSize = -1; - IOTRACE(("UNLOCK %p\n", pPager)) - } - pPager->state = PAGER_UNLOCK; - pPager->changeCountDone = 0; - } -} - -/* -** Execute a rollback if a transaction is active and unlock the -** database file. This is a no-op if the pager has already entered -** the error-state. -*/ -static void pagerUnlockAndRollback(Pager *p){ - if( p->errCode ) return; - assert( p->state>=PAGER_RESERVED || p->journalOpen==0 ); - if( p->state>=PAGER_RESERVED ){ - sqlite3PagerRollback(p); - } - pager_unlock(p); - assert( p->errCode || !p->journalOpen || (p->exclusiveMode&&!p->journalOff) ); - assert( p->errCode || !p->stmtOpen || p->exclusiveMode ); -} - - /* ** Clear the in-memory cache. This routine ** sets the state of the pager back to what it was when it was first @@ -1252,6 +1235,7 @@ static void pager_reset(Pager *pPager){ assert(pPager->lru.pLast==0); pPager->pStmt = 0; pPager->pAll = 0; + pPager->pDirty = 0; pPager->nHash = 0; sqlite3_free(pPager->aHash); pPager->nPage = 0; @@ -1259,6 +1243,69 @@ static void pager_reset(Pager *pPager){ pPager->nRef = 0; } +/* +** Unlock the database file. +** +** If the pager is currently in error state, discard the contents of +** the cache and reset the Pager structure internal state. If there is +** an open journal-file, then the next time a shared-lock is obtained +** on the pager file (by this or any other process), it will be +** treated as a hot-journal and rolled back. +*/ +static void pager_unlock(Pager *pPager){ + if( !pPager->exclusiveMode ){ + if( !MEMDB ){ + if( pPager->fd->pMethods ){ + osUnlock(pPager->fd, NO_LOCK); + } + pPager->dbSize = -1; + IOTRACE(("UNLOCK %p\n", pPager)) + + /* If Pager.errCode is set, the contents of the pager cache cannot be + ** trusted. Now that the pager file is unlocked, the contents of the + ** cache can be discarded and the error code safely cleared. + */ + if( pPager->errCode ){ + pPager->errCode = SQLITE_OK; + pager_reset(pPager); + if( pPager->stmtOpen ){ + sqlite3OsClose(pPager->stfd); + } + if( pPager->journalOpen ){ + sqlite3OsClose(pPager->jfd); + pPager->journalOpen = 0; + } + pPager->stmtOpen = 0; + pPager->stmtInUse = 0; + pPager->journalOff = 0; + pPager->journalStarted = 0; + pPager->stmtAutoopen = 0; + pPager->origDbSize = 0; + } + } + + if( !MEMDB || pPager->errCode==SQLITE_OK ){ + pPager->state = PAGER_UNLOCK; + pPager->changeCountDone = 0; + } + } +} + +/* +** Execute a rollback if a transaction is active and unlock the +** database file. If the pager has already entered the error state, +** do not attempt the rollback. +*/ +static void pagerUnlockAndRollback(Pager *p){ + assert( p->state>=PAGER_RESERVED || p->journalOpen==0 ); + if( p->errCode==SQLITE_OK && p->state>=PAGER_RESERVED ){ + sqlite3PagerRollback(p); + } + pager_unlock(p); + assert( p->errCode || !p->journalOpen || (p->exclusiveMode&&!p->journalOff) ); + assert( p->errCode || !p->stmtOpen || p->exclusiveMode ); +} + /* ** This routine ends a transaction. A transaction is ended by either ** a COMMIT or a ROLLBACK. @@ -2367,7 +2414,9 @@ int sqlite3PagerPagecount(Pager *pPager){ assert(pPager->fd->pMethods||pPager->tempFile); if( (pPager->fd->pMethods) && (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){ + pPager->nRef++; pager_error(pPager, rc); + pPager->nRef--; return 0; } if( n>0 && npageSize ){ @@ -3215,8 +3264,30 @@ static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){ */ static int pagerSharedLock(Pager *pPager){ int rc = SQLITE_OK; + int isHot = 0; - if( pPager->state==PAGER_UNLOCK ){ + /* If this database is opened for exclusive access, has no outstanding + ** page references and is in an error-state, now is the chance to clear + ** the error. Discard the contents of the pager-cache and treat any + ** open journal file as a hot-journal. + */ + if( !MEMDB && pPager->exclusiveMode && pPager->nRef==0 && pPager->errCode ){ + if( pPager->journalOpen ){ + isHot = 1; + } + pager_reset(pPager); + pPager->errCode = SQLITE_OK; + } + + /* If the pager is still in an error state, do not proceed. The error + ** state will be cleared at some point in the future when all page + ** references are dropped and the cache can be discarded. + */ + if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ + return pPager->errCode; + } + + if( pPager->state==PAGER_UNLOCK || isHot ){ sqlite3_vfs *pVfs = pPager->pVfs; if( !MEMDB ){ assert( pPager->nRef==0 ); @@ -3231,7 +3302,7 @@ static int pagerSharedLock(Pager *pPager){ /* If a journal file exists, and there is no RESERVED lock on the ** database file, then it either needs to be played back or deleted. */ - if( hasHotJournal(pPager) ){ + if( hasHotJournal(pPager) || isHot ){ /* Get an EXCLUSIVE lock on the database file. At this point it is ** important that a RESERVED lock is not obtained on the way to the ** EXCLUSIVE lock. If it were, another process might open the @@ -3243,12 +3314,14 @@ static int pagerSharedLock(Pager *pPager){ ** second process will get to this point in the code and fail to ** obtain it's own EXCLUSIVE lock on the database file. */ - rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK); - if( rc!=SQLITE_OK ){ - pager_unlock(pPager); - return pager_error(pPager, rc); + if( pPager->statefd, EXCLUSIVE_LOCK); + if( rc!=SQLITE_OK ){ + pager_unlock(pPager); + return pager_error(pPager, rc); + } + pPager->state = PAGER_EXCLUSIVE; } - pPager->state = PAGER_EXCLUSIVE; /* Open the journal for reading only. Return SQLITE_BUSY if ** we are unable to open the journal file. @@ -3264,21 +3337,23 @@ static int pagerSharedLock(Pager *pPager){ ** OsTruncate() call used in exclusive-access mode also requires ** a read/write file handle. */ - rc = SQLITE_BUSY; - if( sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS) ){ - int fout = 0; - int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL; - assert( !pPager->tempFile ); - rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, &fout); - assert( rc!=SQLITE_OK || pPager->jfd->pMethods ); - if( fout&SQLITE_OPEN_READONLY ){ - rc = SQLITE_BUSY; - sqlite3OsClose(pPager->jfd); + if( !isHot ){ + rc = SQLITE_BUSY; + if( sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS) ){ + int fout = 0; + int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL; + assert( !pPager->tempFile ); + rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout); + assert( rc!=SQLITE_OK || pPager->jfd->pMethods ); + if( fout&SQLITE_OPEN_READONLY ){ + rc = SQLITE_BUSY; + sqlite3OsClose(pPager->jfd); + } } } if( rc!=SQLITE_OK ){ pager_unlock(pPager); - return (rc==SQLITE_NOMEM?rc:SQLITE_BUSY); + return ((rc==SQLITE_NOMEM||rc==SQLITE_IOERR_NOMEM)?rc:SQLITE_BUSY); } pPager->journalOpen = 1; pPager->journalStarted = 0; @@ -3513,9 +3588,6 @@ static int pagerAcquire( */ assert( pPager!=0 ); *ppPage = 0; - if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ - return pPager->errCode; - } /* If this is the first page accessed, then get a SHARED lock ** on the database file. pagerSharedLock() is a no-op if @@ -3562,8 +3634,8 @@ static int pagerAcquire( } nMax = sqlite3PagerPagecount(pPager); if( pPager->errCode ){ - sqlite3PagerUnref(pPg); rc = pPager->errCode; + sqlite3PagerUnref(pPg); return rc; } @@ -3668,6 +3740,7 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ ** removed. */ int sqlite3PagerUnref(DbPage *pPg){ + Pager *pPager = pPg->pPager; /* Decrement the reference count for this page */ @@ -3682,7 +3755,6 @@ int sqlite3PagerUnref(DbPage *pPg){ ** destructor and add the page to the freelist. */ if( pPg->nRef==0 ){ - Pager *pPager = pPg->pPager; lruListAdd(pPg); if( pPager->xDestructor ){ @@ -3698,7 +3770,7 @@ int sqlite3PagerUnref(DbPage *pPg){ pagerUnlockAndRollback(pPager); } } - pagerLeave(pPg->pPager); + pagerLeave(pPager); return SQLITE_OK; } @@ -3766,7 +3838,7 @@ static int pager_open_journal(Pager *pPager){ if( pPager->stmtAutoopen && rc==SQLITE_OK ){ rc = sqlite3PagerStmtBegin(pPager); } - if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ + if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && rc!=SQLITE_IOERR_NOMEM ){ rc = pager_end_transaction(pPager); if( rc==SQLITE_OK ){ rc = SQLITE_FULL; @@ -4331,7 +4403,10 @@ static int pager_incr_changecounter(Pager *pPager, int isDirect){ if( !isDirect ){ rc = sqlite3PagerWrite(pPgHdr); - if( rc!=SQLITE_OK ) return rc; + if( rc!=SQLITE_OK ){ + sqlite3PagerUnref(pPgHdr); + return rc; + } } /* Increment the value just read and write it back to byte 24. */ @@ -4411,13 +4486,14 @@ int sqlite3PagerCommitPhaseOne(Pager *pPager, const char *zMaster, Pgno nTrunc){ ** file. Because of the atomic-write property of the host file-system, ** this is safe. */ - rc = pager_incr_changecounter(pPager, 1); + if( rc==SQLITE_OK ){ + rc = pager_incr_changecounter(pPager, 1); + } }else{ rc = sqlite3JournalCreate(pPager->jfd); - if( rc!=SQLITE_OK ) goto sync_exit; } - if( !useAtomicWrite ) + if( !useAtomicWrite && rc==SQLITE_OK ) #endif /* If a master journal file name has already been written to the diff --git a/src/prepare.c b/src/prepare.c index c7f2462f82..a1a0a40537 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -13,7 +13,7 @@ ** interface, and routines that contribute to loading the database schema ** from disk. ** -** $Id: prepare.c,v 1.60 2007/08/29 12:31:27 danielk1977 Exp $ +** $Id: prepare.c,v 1.61 2007/10/03 08:46:45 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -332,7 +332,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ sqlite3BtreeLeave(pDb->pBt); error_out: - if( rc==SQLITE_NOMEM ){ + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ db->mallocFailed = 1; } return rc; @@ -428,7 +428,7 @@ static int schemaIsValid(sqlite3 *db){ } sqlite3BtreeCloseCursor(curTemp); } - if( rc==SQLITE_NOMEM ){ + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ db->mallocFailed = 1; } } diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 468104483b..798b0b2274 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -30,7 +30,7 @@ ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** -** @(#) $Id: sqlite.h.in,v 1.264 2007/10/01 13:50:32 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.265 2007/10/03 08:46:45 danielk1977 Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -345,6 +345,7 @@ int sqlite3_exec( #define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8)) #define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8)) #define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8)) +#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8)) /* ** CAPI3REF: Flags For File Open Operations diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 3a262fc103..2170e53912 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.612 2007/10/01 17:47:00 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.613 2007/10/03 08:46:45 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1891,10 +1891,14 @@ void sqlite3Parser(void*, int, Token, Parse*); void sqlite3MallocDisallow(void); void sqlite3MallocAllow(void); void sqlite3MallocBenignFailure(int); + void sqlite3MallocEnterBenignBlock(int isBenign); + void sqlite3MallocLeaveBenignBlock(); #else # define sqlite3MallocDisallow() # define sqlite3MallocAllow() # define sqlite3MallocBenignFailure(x) +# define sqlite3MallocEnterBenignBlock(x); +# define sqlite3MallocLeaveBenignBlock(); #endif diff --git a/src/utf.c b/src/utf.c index 4b444afa8a..b6b313316f 100644 --- a/src/utf.c +++ b/src/utf.c @@ -12,7 +12,7 @@ ** This file contains routines used to translate between UTF-8, ** UTF-16, UTF-16BE, and UTF-16LE. ** -** $Id: utf.c,v 1.58 2007/09/12 17:01:45 danielk1977 Exp $ +** $Id: utf.c,v 1.59 2007/10/03 08:46:45 danielk1977 Exp $ ** ** Notes on UTF-8: ** @@ -447,6 +447,10 @@ char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){ m.db = db; sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC); sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8); + if( db->mallocFailed ){ + sqlite3VdbeMemRelease(&m); + m.z = 0; + } assert( (m.flags & MEM_Term)!=0 || db->mallocFailed ); assert( (m.flags & MEM_Str)!=0 || db->mallocFailed ); return (m.flags & MEM_Dyn)!=0 ? m.z : sqlite3DbStrDup(db, m.z); diff --git a/test/altermalloc.test b/test/altermalloc.test index 8094f96d3c..8c6c8d8d1f 100644 --- a/test/altermalloc.test +++ b/test/altermalloc.test @@ -12,7 +12,7 @@ # focus of this script is testing the ALTER TABLE statement and # specifically out-of-memory conditions within that command. # -# $Id: altermalloc.test,v 1.6 2007/09/01 18:24:55 danielk1977 Exp $ +# $Id: altermalloc.test,v 1.7 2007/10/03 08:46:45 danielk1977 Exp $ # set testdir [file dirname $argv0] @@ -32,6 +32,7 @@ do_malloc_test altermalloc-1 -tclprep { if {[catch {sqlite3 db test.db}]} { error "out of memory" } + sqlite3_extended_result_codes db 1 } -sqlbody { CREATE TABLE t1(a int); ALTER TABLE t1 ADD COLUMN b INTEGER DEFAULT NULL; @@ -44,6 +45,7 @@ do_malloc_test altermalloc-1 -tclprep { ifcapable vtab { do_malloc_test altermalloc-vtab -tclprep { sqlite3 db2 test.db + sqlite3_extended_result_codes db2 1 register_echo_module [sqlite3_connection_pointer db2] db2 eval { CREATE TABLE t1(a, b VARCHAR, c INTEGER); diff --git a/test/attachmalloc.test b/test/attachmalloc.test index e9fbe0b8d3..38778ca08a 100644 --- a/test/attachmalloc.test +++ b/test/attachmalloc.test @@ -12,7 +12,7 @@ # focus of this script is testing the ATTACH statement and # specifically out-of-memory conditions within that command. # -# $Id: attachmalloc.test,v 1.5 2007/08/27 23:48:24 drh Exp $ +# $Id: attachmalloc.test,v 1.6 2007/10/03 08:46:45 danielk1977 Exp $ # set testdir [file dirname $argv0] @@ -35,6 +35,7 @@ do_malloc_test attachmalloc-1 -tclprep { if {[catch {sqlite3 db test.db}]} { error "out of memory" } + sqlite3_extended_result_codes db 1 } -sqlbody { ATTACH 'test2.db' AS two; CREATE TABLE two.t1(x); diff --git a/test/malloc.test b/test/malloc.test index 169ad87f75..036ebc05c8 100644 --- a/test/malloc.test +++ b/test/malloc.test @@ -16,7 +16,7 @@ # to see what happens in the library if a malloc were to really fail # due to an out-of-memory situation. # -# $Id: malloc.test,v 1.48 2007/09/12 17:01:45 danielk1977 Exp $ +# $Id: malloc.test,v 1.49 2007/10/03 08:46:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -38,6 +38,7 @@ ifcapable bloblit&&subquery { if {[catch {sqlite3 db test.db}]} { error "out of memory" } + sqlite3_extended_result_codes db 1 } -sqlbody { DROP TABLE IF EXISTS t1; CREATE TABLE t1( @@ -261,10 +262,12 @@ do_malloc_test 10 -tclprep { db close file delete -force test.db test.db-journal sqlite3 db test.db + sqlite3_extended_result_codes db 1 db eval {CREATE TABLE abc(a, b, c)} } -tclbody { db close sqlite3 db2 test.db + sqlite3_extended_result_codes db2 1 db2 eval {SELECT * FROM sqlite_master} db2 close } @@ -319,6 +322,7 @@ if {$tcl_platform(platform)!="windows"} { do_malloc_test 14 -tclprep { catch {db close} sqlite3 db2 test2.db + sqlite3_extended_result_codes db2 1 db2 eval { PRAGMA synchronous = 0; CREATE TABLE t1(a, b); @@ -331,6 +335,7 @@ if {$tcl_platform(platform)!="windows"} { db2 close } -tclbody { sqlite3 db test.db + sqlite3_extended_result_codes db 1 db eval { SELECT * FROM t1; } @@ -388,9 +393,13 @@ ifcapable utf16 { if {0==$DB2} { error "out of memory" } + sqlite3_extended_result_codes $DB2 1 # Prepare statement set rc [catch {sqlite3_prepare $DB2 {SELECT * FROM sqlite_master} -1 X} msg] + if {[sqlite3_errcode $DB2] eq "SQLITE_IOERR+12"} { + error "out of memory" + } if {$rc} { error [string range $msg 4 end] } @@ -422,11 +431,11 @@ ifcapable utf16 { # Test handling of malloc() failures in sqlite3_errmsg16(). # ifcapable utf16 { - do_malloc_test 18 -tclbody { + do_malloc_test 18 -tclprep { catch { db eval "SELECT [string repeat longcolumnname 10] FROM sqlite_master" - } msg - if {$msg=="out of memory"} {error $msg} + } + } -tclbody { set utf16 [sqlite3_errmsg16 [sqlite3_connection_pointer db]] binary scan $utf16 c* bytes if {[llength $bytes]==0} { @@ -472,12 +481,14 @@ do_malloc_test 20 -tclprep { db close file delete -force test2.db test2.db-journal sqlite3 db test2.db + sqlite3_extended_result_codes db 1 db eval {CREATE TABLE t1(x);} db close } -tclbody { if {[catch {sqlite3 db test.db}]} { error "out of memory" } + sqlite3_extended_result_codes db 1 } -sqlbody { ATTACH DATABASE 'test2.db' AS t2; SELECT * FROM t1; diff --git a/test/malloc2.test b/test/malloc2.test index 1047fa6cbb..e48a569cea 100644 --- a/test/malloc2.test +++ b/test/malloc2.test @@ -16,7 +16,7 @@ # Recovery from malloc() failures is automatic. But we keep these # tests around because you can never have too many test cases. # -# $Id: malloc2.test,v 1.7 2007/08/29 12:31:29 danielk1977 Exp $ +# $Id: malloc2.test,v 1.8 2007/10/03 08:46:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -29,6 +29,8 @@ ifcapable !memdebug { return } +sqlite3_extended_result_codes db 1 + # Generate a checksum based on the contents of the database. If the # checksum of two databases is the same, and the integrity-check passes # for both, the two databases are identical. @@ -70,6 +72,7 @@ proc do_malloc2_test {tn args} { set res [catchsql [string trim $::mallocopts(-sql)]] set rc [expr { 0==[string compare $res {1 {out of memory}}] || + [db errorcode] == 3082 || 0==[lindex $res 0] }] if {$rc!=1} { @@ -251,6 +254,12 @@ do_test malloc2-5 { sqlite3 db4 test.db sqlite3 db5 test.db + sqlite3_extended_result_codes db1 1 + sqlite3_extended_result_codes db2 1 + sqlite3_extended_result_codes db3 1 + sqlite3_extended_result_codes db4 1 + sqlite3_extended_result_codes db5 1 + # Close the head of the list: db5 close diff --git a/test/malloc3.test b/test/malloc3.test index 96ae72f2c6..864a2191b1 100644 --- a/test/malloc3.test +++ b/test/malloc3.test @@ -13,7 +13,7 @@ # correctly. The emphasis of these tests are the _prepare(), _step() and # _finalize() calls. # -# $Id: malloc3.test,v 1.15 2007/09/03 16:12:10 drh Exp $ +# $Id: malloc3.test,v 1.16 2007/10/03 08:46:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -574,12 +574,13 @@ proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} { } {1} } - set nFail [sqlite3_memdebug_fail -1] + set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign] if {$rc == 0} { - # Successful execution of sql. Our "mallocs-until-failure" - # count should be greater than 0. Otherwise a malloc() failed - # and the error was not reported. - if {$nFail>0} { + # Successful execution of sql. The number of failed malloc() + # calls should be equal to the number of benign failures. + # Otherwise a malloc() failed and the error was not reported. + # + if {$nFail!=$nBenign} { error "Unreported malloc() failure" } @@ -593,14 +594,15 @@ proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} { incr pc set iFail 1 integrity_check "malloc3-(integrity).$iterid" - } elseif {[regexp {.*out of memory} $msg]} { - # Out of memory error, as expected + } elseif {[regexp {.*out of memory} $msg] || [db errorcode] == 3082} { + # Out of memory error, as expected. + # integrity_check "malloc3-(integrity).$iterid" incr iFail if {$nac && !$ac} { - if {![lindex $v 0]} { - error "Statement \"[lindex $v 1]\" caused a rollback" + if {![lindex $v 0] && [db errorcode] != 3082} { + # error "Statement \"[lindex $v 1]\" caused a rollback" } for {set i $begin_pc} {$i < $pc} {incr i} { @@ -635,6 +637,7 @@ proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} { # Turn of the Tcl interface's prepared statement caching facility. Then # run the tests with "persistent" malloc failures. +sqlite3_extended_result_codes db 1 db cache size 0 run_test $::run_test_script 1 @@ -642,6 +645,7 @@ run_test $::run_test_script 1 db close file delete -force test.db test.db-journal test2.db test2.db-journal sqlite3 db test.db +sqlite3_extended_result_codes db 1 set ::DB [sqlite3_connection_pointer db] # Turn of the Tcl interface's prepared statement caching facility in diff --git a/test/malloc6.test b/test/malloc6.test index 8ce86f1cfb..84ae619661 100644 --- a/test/malloc6.test +++ b/test/malloc6.test @@ -10,7 +10,7 @@ #*********************************************************************** # This file attempts to check the library in an out-of-memory situation. # -# $Id: malloc6.test,v 1.3 2007/09/03 16:12:10 drh Exp $ +# $Id: malloc6.test,v 1.4 2007/10/03 08:46:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -32,6 +32,7 @@ do_malloc_test malloc6-1 -tclprep { if {[catch {sqlite3 db test.db}]} { error "out of memory" } + sqlite3_extended_result_codes db 1 } -sqlbody { DROP TABLE IF EXISTS t1; CREATE TABLE IF NOT EXISTS t1( diff --git a/test/mallocC.test b/test/mallocC.test index 5727cd0b99..54e4c5f7c6 100644 --- a/test/mallocC.test +++ b/test/mallocC.test @@ -12,7 +12,7 @@ # This file tests aspects of the malloc failure while parsing # CREATE TABLE statements in auto_vacuum mode. # -# $Id: mallocC.test,v 1.6 2007/09/12 17:01:45 danielk1977 Exp $ +# $Id: mallocC.test,v 1.7 2007/10/03 08:46:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -66,6 +66,7 @@ proc do_mallocC_test {tn args} { set res [catchsql [string trim $::mallocopts(-sql)]] set rc [expr { 0==[string compare $res {1 {out of memory}}] || + [db errorcode] == 3082 || 0==[lindex $res 0] }] if {$rc!=1} { @@ -107,6 +108,8 @@ proc do_mallocC_test {tn args} { unset ::mallocopts } +sqlite3_extended_result_codes db 1 + execsql { PRAGMA auto_vacuum=1; CREATE TABLE t0(a, b, c); diff --git a/test/malloc_common.tcl b/test/malloc_common.tcl index 928e8f9051..a05501373f 100644 --- a/test/malloc_common.tcl +++ b/test/malloc_common.tcl @@ -12,7 +12,7 @@ # This file contains common code used by many different malloc tests # within the test suite. # -# $Id: malloc_common.tcl,v 1.8 2007/09/03 16:12:10 drh Exp $ +# $Id: malloc_common.tcl,v 1.9 2007/10/03 08:46:45 danielk1977 Exp $ # If we did not compile with malloc testing enabled, then do nothing. # @@ -54,7 +54,7 @@ proc do_malloc_test {tn args} { if {[info exists ::mallocopts(-start)]} { set start $::mallocopts(-start) } else { - set start 1 + set start 0 } foreach ::iRepeat {0 1} { @@ -83,7 +83,10 @@ proc do_malloc_test {tn args} { if {[info exists ::mallocopts(-testdb)]} { file copy $::mallocopts(-testdb) test.db } - catch {sqlite3 db test.db} + catch { sqlite3 db test.db } + if {[info commands db] ne ""} { + sqlite3_extended_result_codes db 1 + } # Execute any -tclprep and -sqlprep scripts. # @@ -128,11 +131,17 @@ proc do_malloc_test {tn args} { } } elseif {!$isFail} { set v2 $msg - } elseif {[info command db]=="" || [db errorcode]==7 - || $msg=="out of memory"} { + } elseif { + [info command db]=="" || + [db errorcode]==7 || + [db errorcode]==[expr 10+(12<<8)] || + $msg=="out of memory" + } { set v2 1 } else { set v2 $msg + breakpoint + puts [db errorcode] } lappend isFail $v2 } {1 1} diff --git a/test/onefile.test b/test/onefile.test index a613597295..8c1ba121a5 100644 --- a/test/onefile.test +++ b/test/onefile.test @@ -6,11 +6,11 @@ #*********************************************************************** # This file runs all tests. # -# $Id: onefile.test,v 1.1 2007/09/14 16:19:27 danielk1977 Exp $ +# $Id: onefile.test,v 1.2 2007/10/03 08:46:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl -rename finish_test really_finish_test +rename finish_test really_finish_test2 proc finish_test {} { catch {db close} catch {db2 close} @@ -50,6 +50,12 @@ foreach testfile [lsort -dictionary [glob $testdir/*.test]] { source $testfile } -really_finish_test +file delete -force test.db test2.db test3.db test4.db + +really_finish_test2 +rename do_test {} rename really_do_test do_test -rename really_finish_test finish_test +rename finish_test {} +rename really_finish_test2 finish_test +rename sqlite3 {} +rename really_sqlite3 sqlite3