mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Add automatic recovery from the pager "error-state". Also add a new error code - SQLITE_IOERR_NOMEM. (CVS 4454)
FossilOrigin-Name: 12eca32a6a3d68d5b20eed03afdffe7599e66014
This commit is contained in:
50
manifest
50
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
|
||||
|
@ -1 +1 @@
|
||||
272959cc91d0c9299d6fca8a962eb563650af87b
|
||||
12eca32a6a3d68d5b20eed03afdffe7599e66014
|
@ -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{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 <ctype.h>
|
||||
@ -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; i<db->nDb; 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);
|
||||
|
27
src/mem2.c
27
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
|
||||
|
32
src/os.c
32
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){
|
||||
|
176
src/pager.c
176
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 && n<pPager->pageSize ){
|
||||
@ -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.
|
||||
*/
|
||||
if( pPager->state<EXCLUSIVE_LOCK ){
|
||||
rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
|
||||
if( rc!=SQLITE_OK ){
|
||||
pager_unlock(pPager);
|
||||
return pager_error(pPager, rc);
|
||||
}
|
||||
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.
|
||||
*/
|
||||
if( !isHot ){
|
||||
rc = SQLITE_BUSY;
|
||||
if( sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS) ){
|
||||
int fout = 0;
|
||||
int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
|
||||
int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
|
||||
assert( !pPager->tempFile );
|
||||
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, &fout);
|
||||
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.
|
||||
*/
|
||||
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
|
||||
|
@ -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 <ctype.h>
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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} {
|
||||
@ -84,6 +84,9 @@ proc do_malloc_test {tn args} {
|
||||
file copy $::mallocopts(-testdb) 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}
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user