SQLite

Check-in [12eca32a6a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add automatic recovery from the pager "error-state". Also add a new error code - SQLITE_IOERR_NOMEM. (CVS 4454)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 12eca32a6a3d68d5b20eed03afdffe7599e66014
User & Date: danielk1977 2007-10-03 08:46:44.000
Context
2007-10-03
09:43
Fix a problem in test script malloc5.test. (CVS 4455) (check-in: 028ec36c71 user: danielk1977 tags: trunk)
08:46
Add automatic recovery from the pager "error-state". Also add a new error code - SQLITE_IOERR_NOMEM. (CVS 4454) (check-in: 12eca32a6a user: danielk1977 tags: trunk)
2007-10-02
19:56
Use local variables instead of #defines for the mutex name and length in OS/2's sqlite3_mutex_alloc(). (CVS 4453) (check-in: 272959cc91 user: pweilbacher tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/attach.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2003 April 6
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.62 2007/09/03 15:19:35 drh Exp $
*/
#include "sqliteInt.h"

#ifndef SQLITE_OMIT_ATTACH
/*
** Resolve an expression that was part of an ATTACH or DETACH statement. This
** is slightly different from resolving a normal SQL expression, because simple













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2003 April 6
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.63 2007/10/03 08:46:44 danielk1977 Exp $
*/
#include "sqliteInt.h"

#ifndef SQLITE_OMIT_ATTACH
/*
** Resolve an expression that was part of an ATTACH or DETACH statement. This
** is slightly different from resolving a normal SQL expression, because simple
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
    if( db->aDb[iDb].pBt ){
      sqlite3BtreeClose(db->aDb[iDb].pBt);
      db->aDb[iDb].pBt = 0;
      db->aDb[iDb].pSchema = 0;
    }
    sqlite3ResetInternalSchema(db, 0);
    db->nDb = iDb;
    if( rc==SQLITE_NOMEM ){
      db->mallocFailed = 1;
      sqlite3_snprintf(sizeof(zErr),zErr, "out of memory");
    }else{
      sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile);
    }
    goto attach_error;
  }







|







196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
    if( db->aDb[iDb].pBt ){
      sqlite3BtreeClose(db->aDb[iDb].pBt);
      db->aDb[iDb].pBt = 0;
      db->aDb[iDb].pSchema = 0;
    }
    sqlite3ResetInternalSchema(db, 0);
    db->nDb = iDb;
    if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
      db->mallocFailed = 1;
      sqlite3_snprintf(sizeof(zErr),zErr, "out of memory");
    }else{
      sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile);
    }
    goto attach_error;
  }
Changes to src/btree.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
** 2004 April 6
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.427 2007/09/17 07:02:57 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
** Including a description of file format and an overview of operation.
*/
#include "btreeInt.h"












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
** 2004 April 6
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.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.
** Including a description of file format and an overview of operation.
*/
#include "btreeInt.h"

2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
** to use a cursor that was open at the beginning of this operation
** will result in an error.
*/
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;
}

/*
** Default key comparison function to be used if no comparison function
** is specified on the sqlite3BtreeCursor() call.







<





<







2581
2582
2583
2584
2585
2586
2587

2588
2589
2590
2591
2592

2593
2594
2595
2596
2597
2598
2599
** to use a cursor that was open at the beginning of this operation
** will result in an error.
*/
int sqlite3BtreeRollbackStmt(Btree *p){
  int rc = SQLITE_OK;
  BtShared *pBt = p->pBt;
  sqlite3BtreeEnter(p);

  if( pBt->inStmt && !pBt->readOnly ){
    rc = sqlite3PagerStmtRollback(pBt->pPager);
    assert( countWriteCursors(pBt)==0 );
    pBt->inStmt = 0;
  }

  sqlite3BtreeLeave(p);
  return rc;
}

/*
** Default key comparison function to be used if no comparison function
** is specified on the sqlite3BtreeCursor() call.
Changes to src/main.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** 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 $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The version of the library
*/







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.405 2007/10/03 08:46:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The version of the library
*/
230
231
232
233
234
235
236

237
238
239
240
241
242
243
244
245
246


247
248
249
250
251
252
253
/*
** Rollback all database files.
*/
void sqlite3RollbackAll(sqlite3 *db){
  int i;
  int inTrans = 0;
  assert( sqlite3_mutex_held(db->mutex) );

  for(i=0; i<db->nDb; i++){
    if( db->aDb[i].pBt ){
      if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
        inTrans = 1;
      }
      sqlite3BtreeRollback(db->aDb[i].pBt);
      db->aDb[i].inTrans = 0;
    }
  }
  sqlite3VtabRollback(db);


  if( db->flags&SQLITE_InternChanges ){
    sqlite3ExpirePreparedStatements(db);
    sqlite3ResetInternalSchema(db, 0);
  }

  /* If one has been configured, invoke the rollback-hook callback */
  if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){







>










>
>







230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/*
** Rollback all database files.
*/
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) ){
        inTrans = 1;
      }
      sqlite3BtreeRollback(db->aDb[i].pBt);
      db->aDb[i].inTrans = 0;
    }
  }
  sqlite3VtabRollback(db);
  sqlite3MallocLeaveBenignBlock(0);                 /* Leave benign region */

  if( db->flags&SQLITE_InternChanges ){
    sqlite3ExpirePreparedStatements(db);
    sqlite3ResetInternalSchema(db, 0);
  }

  /* If one has been configured, invoke the rollback-hook callback */
  if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
Changes to src/mem2.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** 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 $
*/

/*
** This version of the memory allocator is used only if the
** SQLITE_MEMDEBUG macro is defined and SQLITE_OMIT_MEMORY_ALLOCATION
** is not defined.
*/







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the C functions that implement a memory
** allocation subsystem for use by SQLite.  
**
** $Id: mem2.c,v 1.14 2007/10/03 08:46:45 danielk1977 Exp $
*/

/*
** This version of the memory allocator is used only if the
** SQLITE_MEMDEBUG macro is defined and SQLITE_OMIT_MEMORY_ALLOCATION
** is not defined.
*/
137
138
139
140
141
142
143

144
145
146
147
148
149
150
  ** to iReset.
  */
  int iFail;    /* Decrement and fail malloc when this is 1 */
  int iReset;   /* When malloc fails set iiFail to this value */
  int iFailCnt;         /* Number of failures */
  int iBenignFailCnt;   /* Number of benign failures */
  int iNextIsBenign;    /* True if the next call to malloc may fail benignly */


  /* 
  ** sqlite3MallocDisallow() increments the following counter.
  ** sqlite3MallocAllow() decrements it.
  */
  int disallow; /* Do not allow memory allocation */
  







>







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  ** to iReset.
  */
  int iFail;    /* Decrement and fail malloc when this is 1 */
  int iReset;   /* When malloc fails set iiFail to this value */
  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.
  ** sqlite3MallocAllow() decrements it.
  */
  int disallow; /* Do not allow memory allocation */
  
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
      if( mem.iFail==1 ){
        p = 0;
        mem.iFail = mem.iReset;
        if( mem.iFailCnt==0 ){
          sqlite3MemsysFailed();  /* A place to set a breakpoint */
        }
        mem.iFailCnt++;
        if( mem.iNextIsBenign ){
          mem.iBenignFailCnt++;
        }
      }else{
        p = malloc(totalSize);
        mem.iFail--;
      }
    }else{







|







278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
      if( mem.iFail==1 ){
        p = 0;
        mem.iFail = mem.iReset;
        if( mem.iFailCnt==0 ){
          sqlite3MemsysFailed();  /* A place to set a breakpoint */
        }
        mem.iFailCnt++;
        if( mem.iNextIsBenign || mem.iIsBenign ){
          mem.iBenignFailCnt++;
        }
      }else{
        p = malloc(totalSize);
        mem.iFail--;
      }
    }else{
490
491
492
493
494
495
496














497
498
499
500








501
502
503
504
505
506
507
  return n;
}

int sqlite3_memdebug_pending(){
  return (mem.iFail-1);
}















void sqlite3MallocBenignFailure(int isBenign){
  if( isBenign ){
    mem.iNextIsBenign = 1;
  }








}

/*
** The following two routines are used to assert that no memory
** allocations occur between one call and the next.  The use of
** these routines does not change the computed results in any way.
** These routines are like asserts.







>
>
>
>
>
>
>
>
>
>
>
>
>
>




>
>
>
>
>
>
>
>







491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
  return n;
}

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
** allocations occur between one call and the next.  The use of
** these routines does not change the computed results in any way.
** These routines are like asserts.
Changes to src/os.c.
13
14
15
16
17
18
19



























20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

35
36
37

38
39
40
41
42
43

44
45
46
47
48
49

50
51
52
53
54
55
56
** This file contains OS interface code that is common to all
** architectures.
*/
#define _SQLITE_OS_C_ 1
#include "sqliteInt.h"
#undef _SQLITE_OS_C_




























/*
** The following routines are convenience wrappers around methods
** of the sqlite3_file object.  This is mostly just syntactic sugar. All
** of this would be completely automatic if SQLite were coded using
** C++ instead of plain old C.
*/
int sqlite3OsClose(sqlite3_file *pId){
  int rc = SQLITE_OK;
  if( pId->pMethods ){
    rc = pId->pMethods->xClose(pId);
    pId->pMethods = 0;
  }
  return rc;
}
int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){

  return id->pMethods->xRead(id, pBuf, amt, offset);
}
int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){

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

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

  return id->pMethods->xLock(id, lockType);
}
int sqlite3OsUnlock(sqlite3_file *id, int lockType){
  return id->pMethods->xUnlock(id, lockType);
}
int sqlite3OsCheckReservedLock(sqlite3_file *id){
  return id->pMethods->xCheckReservedLock(id);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>















>



>






>






>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
** This file contains OS interface code that is common to all
** architectures.
*/
#define _SQLITE_OS_C_ 1
#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
** of this would be completely automatic if SQLite were coded using
** C++ instead of plain old C.
*/
int sqlite3OsClose(sqlite3_file *pId){
  int rc = SQLITE_OK;
  if( pId->pMethods ){
    rc = pId->pMethods->xClose(pId);
    pId->pMethods = 0;
  }
  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){
  return id->pMethods->xUnlock(id, lockType);
}
int sqlite3OsCheckReservedLock(sqlite3_file *id){
  return id->pMethods->xCheckReservedLock(id);
95
96
97
98
99
100
101

102
103
104
105
106
107
108
int sqlite3OsOpen(
  sqlite3_vfs *pVfs, 
  const char *zPath, 
  sqlite3_file *pFile, 
  int flags, 
  int *pFlagsOut
){

  return pVfs->xOpen(pVfs, zPath, pFile, flags, pFlagsOut);
}
int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  return pVfs->xDelete(pVfs, zPath, dirSync);
}
int sqlite3OsAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){
  return pVfs->xAccess(pVfs, zPath, flags);







>







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
int sqlite3OsOpen(
  sqlite3_vfs *pVfs, 
  const char *zPath, 
  sqlite3_file *pFile, 
  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){
  return pVfs->xDelete(pVfs, zPath, dirSync);
}
int sqlite3OsAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){
  return pVfs->xAccess(pVfs, zPath, flags);
Changes to src/pager.c.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.390 2007/09/17 07:02:57 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include <assert.h>
#include <string.h>

/*







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.391 2007/10/03 08:46:45 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include <assert.h>
#include <string.h>

/*
805
806
807
808
809
810
811
812
813







814

815
816
817
818
819
820
821
822
823
824
825
826
827







828
829
830
831
832
833
834
/*
** This function should be called when an error occurs within the pager
** code. The first argument is a pointer to the pager structure, the
** second the error-code about to be returned by a pager API function. 
** 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.







*/

static int pager_error(Pager *pPager, int rc){
  int rc2 = rc & 0xff;
  assert(
       pPager->errCode==SQLITE_FULL ||
       pPager->errCode==SQLITE_OK ||
       (pPager->errCode & 0xff)==SQLITE_IOERR
  );
  if(
    rc2==SQLITE_FULL ||
    rc2==SQLITE_IOERR ||
    rc2==SQLITE_CORRUPT
  ){
    pPager->errCode = rc;







  }
  return rc;
}

/*
** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
** on the cache using a hash function.  This is used for testing







|
|
>
>
>
>
>
>
>

>













>
>
>
>
>
>
>







805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
/*
** This function should be called when an error occurs within the pager
** code. The first argument is a pointer to the pager structure, the
** second the error-code about to be returned by a pager API function. 
** 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. 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(
       pPager->errCode==SQLITE_FULL ||
       pPager->errCode==SQLITE_OK ||
       (pPager->errCode & 0xff)==SQLITE_IOERR
  );
  if(
    rc2==SQLITE_FULL ||
    rc2==SQLITE_IOERR ||
    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;
}

/*
** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
** on the cache using a hash function.  This is used for testing
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
  if( pPager->aHash==0 ) return 0;
  p = pPager->aHash[pgno & (pPager->nHash-1)];
  while( p && p->pgno!=pgno ){
    p = p->pNextHash;
  }
  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
** opened.  Any outstanding pages are invalidated and subsequent attempts
** to access those pages will likely result in a coredump.
*/







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1208
1209
1210
1211
1212
1213
1214
































1215
1216
1217
1218
1219
1220
1221
  if( pPager->aHash==0 ) return 0;
  p = pPager->aHash[pgno & (pPager->nHash-1)];
  while( p && p->pgno!=pgno ){
    p = p->pNextHash;
  }
  return p;
}

































/*
** Clear the in-memory cache.  This routine
** sets the state of the pager back to what it was when it was first
** opened.  Any outstanding pages are invalidated and subsequent attempts
** to access those pages will likely result in a coredump.
*/
1248
1249
1250
1251
1252
1253
1254

1255
1256
1257
1258
1259
1260































































1261
1262
1263
1264
1265
1266
1267
    sqlite3_free(pPg);
  }
  assert(pPager->lru.pFirst==0);
  assert(pPager->lru.pFirstSynced==0);
  assert(pPager->lru.pLast==0);
  pPager->pStmt = 0;
  pPager->pAll = 0;

  pPager->nHash = 0;
  sqlite3_free(pPager->aHash);
  pPager->nPage = 0;
  pPager->aHash = 0;
  pPager->nRef = 0;
}
































































/*
** This routine ends a transaction.  A transaction is ended by either
** a COMMIT or a ROLLBACK.
**
** When this routine is called, the pager has the journal file open and
** a RESERVED or EXCLUSIVE lock on the database.  This routine will release







>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
    sqlite3_free(pPg);
  }
  assert(pPager->lru.pFirst==0);
  assert(pPager->lru.pFirstSynced==0);
  assert(pPager->lru.pLast==0);
  pPager->pStmt = 0;
  pPager->pAll = 0;
  pPager->pDirty = 0;
  pPager->nHash = 0;
  sqlite3_free(pPager->aHash);
  pPager->nPage = 0;
  pPager->aHash = 0;
  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.
**
** When this routine is called, the pager has the journal file open and
** a RESERVED or EXCLUSIVE lock on the database.  This routine will release
2363
2364
2365
2366
2367
2368
2369

2370

2371
2372
2373
2374
2375
2376
2377
  }
  if( pPager->dbSize>=0 ){
    n = pPager->dbSize;
  } else {
    assert(pPager->fd->pMethods||pPager->tempFile);
    if( (pPager->fd->pMethods)
     && (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){

      pager_error(pPager, rc);

      return 0;
    }
    if( n>0 && n<pPager->pageSize ){
      n = 1;
    }else{
      n /= pPager->pageSize;
    }







>

>







2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
  }
  if( pPager->dbSize>=0 ){
    n = pPager->dbSize;
  } else {
    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 ){
      n = 1;
    }else{
      n /= pPager->pageSize;
    }
3211
3212
3213
3214
3215
3216
3217

3218





















3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245

3246
3247
3248
3249
3250
3251

3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266

3267
3268
3269
3270
3271
3272
3273
3274
3275
3276

3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
**
** Immediately after obtaining the shared lock (if required), this function
** checks for a hot-journal file. If one is found, an emergency rollback
** is performed immediately.
*/
static int pagerSharedLock(Pager *pPager){
  int rc = SQLITE_OK;























  if( pPager->state==PAGER_UNLOCK ){
    sqlite3_vfs *pVfs = pPager->pVfs;
    if( !MEMDB ){
      assert( pPager->nRef==0 );
      if( !pPager->noReadlock ){
        rc = pager_wait_on_lock(pPager, SHARED_LOCK);
        if( rc!=SQLITE_OK ){
          return pager_error(pPager, rc);
        }
        assert( pPager->state>=SHARED_LOCK );
      }
  
      /* 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) ){
        /* 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
        ** database file, detect the RESERVED lock, and conclude that the
        ** database is safe to read while this process is still rolling it 
        ** back.
        ** 
        ** Because the intermediate RESERVED lock is not requested, the
        ** 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);
        }
        pPager->state = PAGER_EXCLUSIVE;

 
        /* Open the journal for reading only.  Return SQLITE_BUSY if
        ** we are unable to open the journal file. 
        **
        ** The journal file does not need to be locked itself.  The
        ** journal file is never open unless the main database file holds
        ** a write lock, so there is never any chance of two or more
        ** processes opening the journal at the same time.
        **
        ** Open the journal for read/write access. This is because in 
        ** exclusive-access mode the file descriptor will be kept open and
        ** possibly used for a transaction later on. On some systems, the
        ** 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( rc!=SQLITE_OK ){
          pager_unlock(pPager);
          return (rc==SQLITE_NOMEM?rc:SQLITE_BUSY);
        }
        pPager->journalOpen = 1;
        pPager->journalStarted = 0;
        pPager->journalOff = 0;
        pPager->setMaster = 0;
        pPager->journalHdr = 0;
 







>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|














|











>
|
|
|
|
|
|
>















>
|
|
|
|
|
|
|
|
|
|
>




|







3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
**
** Immediately after obtaining the shared lock (if required), this function
** checks for a hot-journal file. If one is found, an emergency rollback
** is performed immediately.
*/
static int pagerSharedLock(Pager *pPager){
  int rc = SQLITE_OK;
  int isHot = 0;

  /* 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 );
      if( !pPager->noReadlock ){
        rc = pager_wait_on_lock(pPager, SHARED_LOCK);
        if( rc!=SQLITE_OK ){
          return pager_error(pPager, rc);
        }
        assert( pPager->state>=SHARED_LOCK );
      }
  
      /* 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) || 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
        ** database file, detect the RESERVED lock, and conclude that the
        ** database is safe to read while this process is still rolling it 
        ** back.
        ** 
        ** Because the intermediate RESERVED lock is not requested, the
        ** 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. 
        **
        ** The journal file does not need to be locked itself.  The
        ** journal file is never open unless the main database file holds
        ** a write lock, so there is never any chance of two or more
        ** processes opening the journal at the same time.
        **
        ** Open the journal for read/write access. This is because in 
        ** exclusive-access mode the file descriptor will be kept open and
        ** possibly used for a transaction later on. On some systems, the
        ** 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 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_IOERR_NOMEM)?rc:SQLITE_BUSY);
        }
        pPager->journalOpen = 1;
        pPager->journalStarted = 0;
        pPager->journalOff = 0;
        pPager->setMaster = 0;
        pPager->journalHdr = 0;
 
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
    return SQLITE_CORRUPT_BKPT;
  }

  /* Make sure we have not hit any critical errors.
  */ 
  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 
  ** a database lock is already held.
  */
  rc = pagerSharedLock(pPager);
  if( rc!=SQLITE_OK ){







<
<
<







3584
3585
3586
3587
3588
3589
3590



3591
3592
3593
3594
3595
3596
3597
    return SQLITE_CORRUPT_BKPT;
  }

  /* Make sure we have not hit any critical errors.
  */ 
  assert( pPager!=0 );
  *ppPage = 0;




  /* If this is the first page accessed, then get a SHARED lock
  ** on the database file. pagerSharedLock() is a no-op if 
  ** a database lock is already held.
  */
  rc = pagerSharedLock(pPager);
  if( rc!=SQLITE_OK ){
3558
3559
3560
3561
3562
3563
3564
3565
3566

3567
3568
3569
3570
3571
3572
3573

    pPager->nRef++;
    if( pPager->nExtra>0 ){
      memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
    }
    nMax = sqlite3PagerPagecount(pPager);
    if( pPager->errCode ){
      sqlite3PagerUnref(pPg);
      rc = pPager->errCode;

      return rc;
    }

    /* Populate the page with data, either by reading from the database
    ** file, or by setting the entire page to zero.
    */
    if( nMax<(int)pgno || MEMDB || (noContent && !pPager->alwaysRollback) ){







<

>







3630
3631
3632
3633
3634
3635
3636

3637
3638
3639
3640
3641
3642
3643
3644
3645

    pPager->nRef++;
    if( pPager->nExtra>0 ){
      memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
    }
    nMax = sqlite3PagerPagecount(pPager);
    if( pPager->errCode ){

      rc = pPager->errCode;
      sqlite3PagerUnref(pPg);
      return rc;
    }

    /* Populate the page with data, either by reading from the database
    ** file, or by setting the entire page to zero.
    */
    if( nMax<(int)pgno || MEMDB || (noContent && !pPager->alwaysRollback) ){
3664
3665
3666
3667
3668
3669
3670

3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
**
** If the number of references to the page drop to zero, then the
** page is added to the LRU list.  When all references to all pages
** are released, a rollback occurs and the lock on the database is
** removed.
*/
int sqlite3PagerUnref(DbPage *pPg){


  /* Decrement the reference count for this page
  */
  assert( pPg->nRef>0 );
  pagerEnter(pPg->pPager);
  pPg->nRef--;
  REFINFO(pPg);

  CHECK_PAGE(pPg);

  /* When the number of references to a page reach 0, call the
  ** destructor and add the page to the freelist.
  */
  if( pPg->nRef==0 ){
    Pager *pPager = pPg->pPager;

    lruListAdd(pPg);
    if( pPager->xDestructor ){
      pPager->xDestructor(pPg, pPager->pageSize);
    }
  
    /* When all pages reach the freelist, drop the read lock from
    ** the database file.
    */
    pPager->nRef--;
    assert( pPager->nRef>=0 );
    if( pPager->nRef==0 && (!pPager->exclusiveMode || pPager->journalOff>0) ){
      pagerUnlockAndRollback(pPager);
    }
  }
  pagerLeave(pPg->pPager);
  return SQLITE_OK;
}

/*
** Create a journal file for pPager.  There should already be a RESERVED
** or EXCLUSIVE lock on the database file when this routine is called.
**







>














<















|







3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757

3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
**
** If the number of references to the page drop to zero, then the
** page is added to the LRU list.  When all references to all pages
** are released, a rollback occurs and the lock on the database is
** removed.
*/
int sqlite3PagerUnref(DbPage *pPg){
  Pager *pPager = pPg->pPager;

  /* Decrement the reference count for this page
  */
  assert( pPg->nRef>0 );
  pagerEnter(pPg->pPager);
  pPg->nRef--;
  REFINFO(pPg);

  CHECK_PAGE(pPg);

  /* When the number of references to a page reach 0, call the
  ** destructor and add the page to the freelist.
  */
  if( pPg->nRef==0 ){


    lruListAdd(pPg);
    if( pPager->xDestructor ){
      pPager->xDestructor(pPg, pPager->pageSize);
    }
  
    /* When all pages reach the freelist, drop the read lock from
    ** the database file.
    */
    pPager->nRef--;
    assert( pPager->nRef>=0 );
    if( pPager->nRef==0 && (!pPager->exclusiveMode || pPager->journalOff>0) ){
      pagerUnlockAndRollback(pPager);
    }
  }
  pagerLeave(pPager);
  return SQLITE_OK;
}

/*
** Create a journal file for pPager.  There should already be a RESERVED
** or EXCLUSIVE lock on the database file when this routine is called.
**
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
  pPager->origDbSize = pPager->dbSize;

  rc = writeJournalHdr(pPager);

  if( pPager->stmtAutoopen && rc==SQLITE_OK ){
    rc = sqlite3PagerStmtBegin(pPager);
  }
  if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
    rc = pager_end_transaction(pPager);
    if( rc==SQLITE_OK ){
      rc = SQLITE_FULL;
    }
  }
  return rc;








|







3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
  pPager->origDbSize = pPager->dbSize;

  rc = writeJournalHdr(pPager);

  if( pPager->stmtAutoopen && rc==SQLITE_OK ){
    rc = sqlite3PagerStmtBegin(pPager);
  }
  if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && rc!=SQLITE_IOERR_NOMEM ){
    rc = pager_end_transaction(pPager);
    if( rc==SQLITE_OK ){
      rc = SQLITE_FULL;
    }
  }
  return rc;

4327
4328
4329
4330
4331
4332
4333
4334



4335
4336
4337
4338
4339
4340
4341
  if( !pPager->changeCountDone ){
    /* Open page 1 of the file for writing. */
    rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
    if( rc!=SQLITE_OK ) return rc;

    if( !isDirect ){
      rc = sqlite3PagerWrite(pPgHdr);
      if( rc!=SQLITE_OK ) return rc;



    }

    /* Increment the value just read and write it back to byte 24. */
    change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers);
    change_counter++;
    put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);








|
>
>
>







4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
  if( !pPager->changeCountDone ){
    /* Open page 1 of the file for writing. */
    rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
    if( rc!=SQLITE_OK ) return rc;

    if( !isDirect ){
      rc = sqlite3PagerWrite(pPgHdr);
      if( rc!=SQLITE_OK ){
        sqlite3PagerUnref(pPgHdr);
        return rc;
      }
    }

    /* Increment the value just read and write it back to byte 24. */
    change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers);
    change_counter++;
    put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);

4407
4408
4409
4410
4411
4412
4413

4414

4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427

      /* Update the db file change counter. The following call will modify
      ** the in-memory representation of page 1 to include the updated
      ** change counter and then write page 1 directly to the database
      ** file. Because of the atomic-write property of the host file-system, 
      ** this is safe.
      */

      rc = pager_incr_changecounter(pPager, 1);

    }else{
      rc = sqlite3JournalCreate(pPager->jfd);
      if( rc!=SQLITE_OK ) goto sync_exit;
    }

    if( !useAtomicWrite )
#endif

    /* If a master journal file name has already been written to the
    ** journal file, then no sync is required. This happens when it is
    ** written, then the process fails to upgrade from a RESERVED to an
    ** EXCLUSIVE lock. The next time the process tries to commit the
    ** transaction the m-j name will have already been written.







>
|
>


<


|







4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493

4494
4495
4496
4497
4498
4499
4500
4501
4502
4503

      /* Update the db file change counter. The following call will modify
      ** the in-memory representation of page 1 to include the updated
      ** change counter and then write page 1 directly to the database
      ** 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( !useAtomicWrite && rc==SQLITE_OK )
#endif

    /* If a master journal file name has already been written to the
    ** journal file, then no sync is required. This happens when it is
    ** written, then the process fails to upgrade from a RESERVED to an
    ** EXCLUSIVE lock. The next time the process tries to commit the
    ** transaction the m-j name will have already been written.
Changes to src/prepare.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the implementation of the sqlite3_prepare()
** 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 $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Fill the InitData structure with an error message that indicates
** that the database is corrupt.







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the implementation of the sqlite3_prepare()
** interface, and routines that contribute to loading the database schema
** from disk.
**
** $Id: prepare.c,v 1.61 2007/10/03 08:46:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Fill the InitData structure with an error message that indicates
** that the database is corrupt.
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
    */
    DbSetProperty(db, iDb, DB_SchemaLoaded);
    rc = SQLITE_OK;
  }
  sqlite3BtreeLeave(pDb->pBt);

error_out:
  if( rc==SQLITE_NOMEM ){
    db->mallocFailed = 1;
  }
  return rc;
}

/*
** Initialize all database files - the main database file, the file







|







328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
    */
    DbSetProperty(db, iDb, DB_SchemaLoaded);
    rc = SQLITE_OK;
  }
  sqlite3BtreeLeave(pDb->pBt);

error_out:
  if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
    db->mallocFailed = 1;
  }
  return rc;
}

/*
** Initialize all database files - the main database file, the file
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
    if( rc==SQLITE_OK ){
      rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
      if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
        allOk = 0;
      }
      sqlite3BtreeCloseCursor(curTemp);
    }
    if( rc==SQLITE_NOMEM ){
      db->mallocFailed = 1;
    }
  }
  return allOk;
}

/*







|







424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
    if( rc==SQLITE_OK ){
      rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
      if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
        allOk = 0;
      }
      sqlite3BtreeCloseCursor(curTemp);
    }
    if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
      db->mallocFailed = 1;
    }
  }
  return allOk;
}

/*
Changes to src/sqlite.h.in.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
** 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 $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
** @(#) $Id: sqlite.h.in,v 1.265 2007/10/03 08:46:45 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
341
342
343
344
345
346
347

348
349
350
351
352
353
354
#define SQLITE_IOERR_DIR_FSYNC     (SQLITE_IOERR | (5<<8))
#define SQLITE_IOERR_TRUNCATE      (SQLITE_IOERR | (6<<8))
#define SQLITE_IOERR_FSTAT         (SQLITE_IOERR | (7<<8))
#define SQLITE_IOERR_UNLOCK        (SQLITE_IOERR | (8<<8))
#define SQLITE_IOERR_RDLOCK        (SQLITE_IOERR | (9<<8))
#define SQLITE_IOERR_DELETE        (SQLITE_IOERR | (10<<8))
#define SQLITE_IOERR_BLOCKED       (SQLITE_IOERR | (11<<8))


/*
** CAPI3REF: Flags For File Open Operations
**
** Combination of the following bit values are used as the
** third argument to the [sqlite3_open_v2()] interface and
** as fourth argument to the xOpen method of the







>







341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
#define SQLITE_IOERR_DIR_FSYNC     (SQLITE_IOERR | (5<<8))
#define SQLITE_IOERR_TRUNCATE      (SQLITE_IOERR | (6<<8))
#define SQLITE_IOERR_FSTAT         (SQLITE_IOERR | (7<<8))
#define SQLITE_IOERR_UNLOCK        (SQLITE_IOERR | (8<<8))
#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
**
** Combination of the following bit values are used as the
** third argument to the [sqlite3_open_v2()] interface and
** as fourth argument to the xOpen method of the
Changes to src/sqliteInt.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.612 2007/10/01 17:47:00 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
#include "sqliteLimit.h"

/*
** For testing purposes, the various size limit constants are really













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.613 2007/10/03 08:46:45 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
#include "sqliteLimit.h"

/*
** For testing purposes, the various size limit constants are really
1887
1888
1889
1890
1891
1892
1893


1894
1895
1896
1897


1898
1899
1900
1901
1902
1903
1904
** Call them around a section of code that you do not expect to do
** any memory allocation.
*/
#ifdef SQLITE_MEMDEBUG
  void sqlite3MallocDisallow(void);
  void sqlite3MallocAllow(void);
  void sqlite3MallocBenignFailure(int);


#else
# define sqlite3MallocDisallow()
# define sqlite3MallocAllow()
# define sqlite3MallocBenignFailure(x)


#endif


#ifdef SQLITE_OMIT_VIRTUALTABLE
#  define sqlite3VtabClear(X)
#  define sqlite3VtabSync(X,Y) (Y)
#  define sqlite3VtabRollback(X)







>
>




>
>







1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
** Call them around a section of code that you do not expect to do
** any memory allocation.
*/
#ifdef SQLITE_MEMDEBUG
  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


#ifdef SQLITE_OMIT_VIRTUALTABLE
#  define sqlite3VtabClear(X)
#  define sqlite3VtabSync(X,Y) (Y)
#  define sqlite3VtabRollback(X)
Changes to src/utf.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** 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 $
**
** Notes on UTF-8:
**
**   Byte-0    Byte-1    Byte-2    Byte-3    Value
**  0xxxxxxx                                 00000000 00000000 0xxxxxxx
**  110yyyyy  10xxxxxx                       00000000 00000yyy yyxxxxxx
**  1110zzzz  10yyyyyy  10xxxxxx             00000000 zzzzyyyy yyxxxxxx







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used to translate between UTF-8, 
** UTF-16, UTF-16BE, and UTF-16LE.
**
** $Id: utf.c,v 1.59 2007/10/03 08:46:45 danielk1977 Exp $
**
** Notes on UTF-8:
**
**   Byte-0    Byte-1    Byte-2    Byte-3    Value
**  0xxxxxxx                                 00000000 00000000 0xxxxxxx
**  110yyyyy  10xxxxxx                       00000000 00000yyy yyxxxxxx
**  1110zzzz  10yyyyyy  10xxxxxx             00000000 zzzzyyyy yyxxxxxx
443
444
445
446
447
448
449




450
451
452
453
454
455
456
*/
char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){
  Mem m;
  memset(&m, 0, sizeof(m));
  m.db = db;
  sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC);
  sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);




  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);
}

/*
** pZ is a UTF-16 encoded unicode string. If nChar is less than zero,







>
>
>
>







443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
*/
char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){
  Mem m;
  memset(&m, 0, sizeof(m));
  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);
}

/*
** pZ is a UTF-16 encoded unicode string. If nChar is less than zero,
Changes to test/altermalloc.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
#    May you share freely, never taking more than you give.
#
#*************************************************************************
# This file implements regression tests for SQLite library.  The
# 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 $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable||!memdebug {
  finish_test
  return
}

source $testdir/malloc_common.tcl

do_malloc_test altermalloc-1 -tclprep {
  db close
} -tclbody {
  if {[catch {sqlite3 db test.db}]} {
    error "out of memory"
  }

} -sqlbody {
  CREATE TABLE t1(a int);
  ALTER TABLE t1 ADD COLUMN b INTEGER DEFAULT NULL;
  ALTER TABLE t1 ADD COLUMN c TEXT DEFAULT 'default-text';
  ALTER TABLE t1 RENAME TO t2;
}

# Test malloc() failure on an ALTER TABLE on a virtual table.
#
ifcapable vtab {
  do_malloc_test altermalloc-vtab -tclprep {
    sqlite3 db2 test.db 

    register_echo_module [sqlite3_connection_pointer db2]
    db2 eval {
      CREATE TABLE t1(a, b VARCHAR, c INTEGER);
      CREATE VIRTUAL TABLE t1echo USING echo(t1);
    }
    db2 close








|



















>












>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#    May you share freely, never taking more than you give.
#
#*************************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ALTER TABLE statement and
# specifically out-of-memory conditions within that command.
#
# $Id: altermalloc.test,v 1.7 2007/10/03 08:46:45 danielk1977 Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable||!memdebug {
  finish_test
  return
}

source $testdir/malloc_common.tcl

do_malloc_test altermalloc-1 -tclprep {
  db close
} -tclbody {
  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;
  ALTER TABLE t1 ADD COLUMN c TEXT DEFAULT 'default-text';
  ALTER TABLE t1 RENAME TO t2;
}

# Test malloc() failure on an ALTER TABLE on a virtual table.
#
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);
      CREATE VIRTUAL TABLE t1echo USING echo(t1);
    }
    db2 close

Changes to test/attachmalloc.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#*************************************************************************
# This file implements regression tests for SQLite library.  The
# 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 $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !memdebug {
  finish_test







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#*************************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH statement and
# specifically out-of-memory conditions within that command.
#
# $Id: attachmalloc.test,v 1.6 2007/10/03 08:46:45 danielk1977 Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !memdebug {
  finish_test
31
32
33
34
35
36
37

38
39
40
41
42
43
44
45
46
47
    file delete -force test$i.db
    file delete -force test$i.db-journal
  }
} -tclbody {
  if {[catch {sqlite3 db test.db}]} {
    error "out of memory"
  }

} -sqlbody {
  ATTACH 'test2.db' AS two;
  CREATE TABLE two.t1(x);
  ATTACH 'test3.db' AS three;
  CREATE TABLE three.t1(x);
  ATTACH 'test4.db' AS four;
  CREATE TABLE four.t1(x);
}

finish_test







>










31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    file delete -force test$i.db
    file delete -force test$i.db-journal
  }
} -tclbody {
  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);
  ATTACH 'test3.db' AS three;
  CREATE TABLE three.t1(x);
  ATTACH 'test4.db' AS four;
  CREATE TABLE four.t1(x);
}

finish_test
Changes to test/malloc.test.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# This file attempts to check the behavior of the SQLite library in 
# an out-of-memory situation. When compiled with -DSQLITE_DEBUG=1, 
# the SQLite library accepts a special command (sqlite3_memdebug_fail N C)
# which causes the N-th malloc to fail.  This special feature is used
# 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 $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
ifcapable !memdebug {







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# This file attempts to check the behavior of the SQLite library in 
# an out-of-memory situation. When compiled with -DSQLITE_DEBUG=1, 
# the SQLite library accepts a special command (sqlite3_memdebug_fail N C)
# which causes the N-th malloc to fail.  This special feature is used
# 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.49 2007/10/03 08:46:45 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
ifcapable !memdebug {
34
35
36
37
38
39
40

41
42
43
44
45
46
47
ifcapable bloblit&&subquery {
  do_malloc_test 1 -tclprep {
    db close
  } -tclbody {
    if {[catch {sqlite3 db test.db}]} {
      error "out of memory"
    }

  } -sqlbody {
    DROP TABLE IF EXISTS t1;
    CREATE TABLE t1(
       a int, b float, c double, d text, e varchar(20),
       primary key(a,b,c)
    );
    CREATE INDEX i1 ON t1(a,b);







>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
ifcapable bloblit&&subquery {
  do_malloc_test 1 -tclprep {
    db close
  } -tclbody {
    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(
       a int, b float, c double, d text, e varchar(20),
       primary key(a,b,c)
    );
    CREATE INDEX i1 ON t1(a,b);
257
258
259
260
261
262
263

264
265
266
267

268
269
270
271
272
273
274
# This block tests malloc() failures that occur while opening a 
# connection to a database.
do_malloc_test 10 -tclprep {
  catch {db2 close}
  db close
  file delete -force test.db test.db-journal
  sqlite3 db test.db

  db eval {CREATE TABLE abc(a, b, c)}
} -tclbody {
  db close
  sqlite3 db2 test.db

  db2 eval {SELECT * FROM sqlite_master}
  db2 close
} 

# This block tests malloc() failures that occur within calls to
# sqlite3_create_function().
do_malloc_test 11 -tclbody {







>




>







258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# This block tests malloc() failures that occur while opening a 
# connection to a database.
do_malloc_test 10 -tclprep {
  catch {db2 close}
  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
} 

# This block tests malloc() failures that occur within calls to
# sqlite3_create_function().
do_malloc_test 11 -tclbody {
315
316
317
318
319
320
321

322
323
324
325
326
327
328
329
330
331
332
333

334
335
336
337
338
339
340
  }
}

if {$tcl_platform(platform)!="windows"} {
  do_malloc_test 14 -tclprep {
    catch {db close}
    sqlite3 db2 test2.db

    db2 eval {
      PRAGMA synchronous = 0;
      CREATE TABLE t1(a, b);
      INSERT INTO t1 VALUES(1, 2);
      BEGIN;
      INSERT INTO t1 VALUES(3, 4);
    }
    copy_file test2.db test.db
    copy_file test2.db-journal test.db-journal
    db2 close
  } -tclbody {
    sqlite3 db test.db

    db eval {
      SELECT * FROM t1;
    }  
  }
}

proc string_compare {a b} {







>












>







318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
  }
}

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);
      INSERT INTO t1 VALUES(1, 2);
      BEGIN;
      INSERT INTO t1 VALUES(3, 4);
    }
    copy_file test2.db test.db
    copy_file test2.db-journal test.db-journal
    db2 close
  } -tclbody {
    sqlite3 db test.db
    sqlite3_extended_result_codes db 1
    db eval {
      SELECT * FROM t1;
    }  
  }
}

proc string_compare {a b} {
384
385
386
387
388
389
390

391
392
393



394
395
396
397
398
399
400
    # open database using sqlite3_open16()
    set filename [encoding convertto unicode test.db]
    append filename "\x00\x00"
    set DB2 [sqlite3_open16 $filename -unused]
    if {0==$DB2} {
      error "out of memory"
    }

  
    # Prepare statement
    set rc [catch {sqlite3_prepare $DB2 {SELECT * FROM sqlite_master} -1 X} msg]



    if {$rc} {
      error [string range $msg 4 end]
    }
    set STMT $msg
  
    # Finalize statement
    set rc [sqlite3_finalize $STMT]







>



>
>
>







389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    # open database using sqlite3_open16()
    set filename [encoding convertto unicode test.db]
    append filename "\x00\x00"
    set DB2 [sqlite3_open16 $filename -unused]
    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]
    }
    set STMT $msg
  
    # Finalize statement
    set rc [sqlite3_finalize $STMT]
418
419
420
421
422
423
424
425
426
427

428
429
430
431
432
433
434
435
436
    }
  }
}

# Test handling of malloc() failures in sqlite3_errmsg16().
#
ifcapable utf16 {
  do_malloc_test 18 -tclbody {
    catch {
      db eval "SELECT [string repeat longcolumnname 10] FROM sqlite_master"

    } msg
    if {$msg=="out of memory"} {error $msg}
    set utf16 [sqlite3_errmsg16 [sqlite3_connection_pointer db]]
    binary scan $utf16 c* bytes
    if {[llength $bytes]==0} {
      error "out of memory"
    }
  }
}







|


>
|
<







427
428
429
430
431
432
433
434
435
436
437
438

439
440
441
442
443
444
445
    }
  }
}

# Test handling of malloc() failures in sqlite3_errmsg16().
#
ifcapable utf16 {
  do_malloc_test 18 -tclprep {
    catch {
      db eval "SELECT [string repeat longcolumnname 10] FROM sqlite_master"
    }
  } -tclbody {

    set utf16 [sqlite3_errmsg16 [sqlite3_connection_pointer db]]
    binary scan $utf16 c* bytes
    if {[llength $bytes]==0} {
      error "out of memory"
    }
  }
}
468
469
470
471
472
473
474

475
476
477
478
479
480

481
482
483
484
485
486
487
# Make sure SQLITE_NOMEM is reported out on an ATTACH failure even
# when the malloc failure occurs within the nested parse.
#
do_malloc_test 20 -tclprep {
  db close
  file delete -force test2.db test2.db-journal
  sqlite3 db test2.db

  db eval {CREATE TABLE t1(x);}
  db close
} -tclbody {
  if {[catch {sqlite3 db test.db}]} {
    error "out of memory"
  }

} -sqlbody {
  ATTACH DATABASE 'test2.db' AS t2;
  SELECT * FROM t1;
  DETACH DATABASE t2;
} 

# Test malloc failure whilst installing a foreign key.







>






>







477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
# Make sure SQLITE_NOMEM is reported out on an ATTACH failure even
# when the malloc failure occurs within the nested parse.
#
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;
  DETACH DATABASE t2;
} 

# Test malloc failure whilst installing a foreign key.
Changes to test/malloc2.test.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30


31
32
33
34
35
36
37
# This file attempts to check that the library can recover from a malloc()
# failure when sqlite3_global_recover() is invoked.
#
# (Later:) The sqlite3_global_recover() interface is now a no-op.
# 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 $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
ifcapable !memdebug {
   puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..."
   finish_test
   return
}



# 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.
#
proc cksum {db} {
  set ret [list]







|











>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# This file attempts to check that the library can recover from a malloc()
# failure when sqlite3_global_recover() is invoked.
#
# (Later:) The sqlite3_global_recover() interface is now a no-op.
# 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.8 2007/10/03 08:46:45 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
ifcapable !memdebug {
   puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..."
   finish_test
   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.
#
proc cksum {db} {
  set ret [list]
66
67
68
69
70
71
72

73
74
75
76
77
78
79
    # Run the SQL. Malloc number $::n is set to fail. A malloc() failure
    # may or may not be reported.
    sqlite3_memdebug_fail $::n -repeat 1
    do_test malloc2-$tn.$::n.2 {
      set res [catchsql [string trim $::mallocopts(-sql)]]
      set rc [expr { 
        0==[string compare $res {1 {out of memory}}] ||

        0==[lindex $res 0]
      }]
      if {$rc!=1} {
        puts "Error: $res"
      }
      set rc
    } {1}







>







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    # Run the SQL. Malloc number $::n is set to fail. A malloc() failure
    # may or may not be reported.
    sqlite3_memdebug_fail $::n -repeat 1
    do_test malloc2-$tn.$::n.2 {
      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} {
        puts "Error: $res"
      }
      set rc
    } {1}
246
247
248
249
250
251
252






253
254
255
256
257
258
259
# will fail if there is some problem.
do_test malloc2-5 {
  sqlite3 db1 test.db
  sqlite3 db2 test.db
  sqlite3 db3 test.db
  sqlite3 db4 test.db
  sqlite3 db5 test.db







  # Close the head of the list:
  db5 close
  
  # Close the end of the list:
  db1 close








>
>
>
>
>
>







249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# will fail if there is some problem.
do_test malloc2-5 {
  sqlite3 db1 test.db
  sqlite3 db2 test.db
  sqlite3 db3 test.db
  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
  
  # Close the end of the list:
  db1 close

Changes to test/malloc3.test.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
#***********************************************************************
#
# This file contains tests to ensure that the library handles malloc() failures
# 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 $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
ifcapable !memdebug {







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
#***********************************************************************
#
# This file contains tests to ensure that the library handles malloc() failures
# correctly. The emphasis of these tests are the _prepare(), _step() and
# _finalize() calls.
#
# $Id: malloc3.test,v 1.16 2007/10/03 08:46:45 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
ifcapable !memdebug {
570
571
572
573
574
575
576
577
578
579
580
581

582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597

598
599
600
601
602
603
604
605
606
607
608
609
610
	  # commit - therefore a rollback occured. Check that the
	  # rollback-hook was invoked.
          do_test malloc3-rollback_hook.$iterid {
            set ::rollback_hook_count
          } {1}
        }

        set nFail [sqlite3_memdebug_fail -1]
        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} {
              error "Unreported malloc() failure"
            }

            if {$ac && !$nac} {
              # Before the [db eval] the auto-commit flag was set, now it
              # is clear. We can deduce that a "BEGIN" statement has just
              # been successfully executed.
              set begin_pc $pc
            } 

            incr pc
            set iFail 1
            integrity_check "malloc3-(integrity).$iterid"
        } elseif {[regexp {.*out of memory} $msg]} {
            # 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"
              }

              for {set i $begin_pc} {$i < $pc} {incr i} {
                set k2 [lindex $arglist [expr 2 * $i]]
                set v2 [lindex $arglist [expr 2 * $i + 1]]
                set catchupsql ""
                switch -- $k2 {







|

|
|
|
>
|













|
|
>




|
|







570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
	  # commit - therefore a rollback occured. Check that the
	  # rollback-hook was invoked.
          do_test malloc3-rollback_hook.$iterid {
            set ::rollback_hook_count
          } {1}
        }

        set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
        if {$rc == 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"
            }

            if {$ac && !$nac} {
              # Before the [db eval] the auto-commit flag was set, now it
              # is clear. We can deduce that a "BEGIN" statement has just
              # been successfully executed.
              set begin_pc $pc
            } 

            incr pc
            set iFail 1
            integrity_check "malloc3-(integrity).$iterid"
        } 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] && [db errorcode] != 3082} {
                # error "Statement \"[lindex $v 1]\" caused a rollback"
              }

              for {set i $begin_pc} {$i < $pc} {incr i} {
                set k2 [lindex $arglist [expr 2 * $i]]
                set v2 [lindex $arglist [expr 2 * $i + 1]]
                set catchupsql ""
                switch -- $k2 {
631
632
633
634
635
636
637

638
639
640
641
642
643
644

645
646
647
648
649
650
651
652
653
      default { error "Unknown switch: $k" }
    }
  }
}

# Turn of the Tcl interface's prepared statement caching facility. Then
# run the tests with "persistent" malloc failures.

db cache size 0
run_test $::run_test_script 1

# Close and reopen the db.
db close
file delete -force test.db test.db-journal test2.db test2.db-journal
sqlite3 db test.db

set ::DB [sqlite3_connection_pointer db]

# Turn of the Tcl interface's prepared statement caching facility in
# the new connnection. Then run the tests with "transient" malloc failures.
db cache size 0
run_test $::run_test_script 0

sqlite3_memdebug_fail -1
finish_test







>







>









633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
      default { error "Unknown switch: $k" }
    }
  }
}

# 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

# Close and reopen the db.
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
# the new connnection. Then run the tests with "transient" malloc failures.
db cache size 0
run_test $::run_test_script 0

sqlite3_memdebug_fail -1
finish_test
Changes to test/malloc6.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2006 June 25
#
# 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 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 $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
ifcapable !memdebug {












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2006 June 25
#
# 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 attempts to check the library in an out-of-memory situation.
#
# $Id: malloc6.test,v 1.4 2007/10/03 08:46:45 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
ifcapable !memdebug {
28
29
30
31
32
33
34

35
36
37
38
39
40
41
set sqlite_os_trace 0
do_malloc_test malloc6-1 -tclprep {
  db close
} -tclbody {
  if {[catch {sqlite3 db test.db}]} {
    error "out of memory"
  }

} -sqlbody {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE IF NOT EXISTS t1(
     a int, b float, c double, d text, e varchar(20),
     primary key(a,b,c)
  );
  CREATE TABLE IF NOT EXISTS t1(







>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
set sqlite_os_trace 0
do_malloc_test malloc6-1 -tclprep {
  db close
} -tclbody {
  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(
     a int, b float, c double, d text, e varchar(20),
     primary key(a,b,c)
  );
  CREATE TABLE IF NOT EXISTS t1(
Changes to test/mallocC.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# 
# 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 $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
ifcapable !memdebug||!compound {







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# 
# This file tests aspects of the malloc failure while parsing
# CREATE TABLE statements in auto_vacuum mode.
#
# $Id: mallocC.test,v 1.7 2007/10/03 08:46:45 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Only run these tests if memory debugging is turned on.
#
ifcapable !memdebug||!compound {
62
63
64
65
66
67
68

69
70
71
72
73
74
75
    # Run the SQL. Malloc number $::n is set to fail. A malloc() failure
    # may or may not be reported.
    sqlite3_memdebug_fail $::n -repeat 1
    do_test mallocC-$tn.$::n.1 {
      set res [catchsql [string trim $::mallocopts(-sql)]]
      set rc [expr { 
        0==[string compare $res {1 {out of memory}}] ||

        0==[lindex $res 0]
      }]
      if {$rc!=1} {
        puts "Error: $res"
      }
      set rc
    } {1}







>







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
    # Run the SQL. Malloc number $::n is set to fail. A malloc() failure
    # may or may not be reported.
    sqlite3_memdebug_fail $::n -repeat 1
    do_test mallocC-$tn.$::n.1 {
      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} {
        puts "Error: $res"
      }
      set rc
    } {1}
102
103
104
105
106
107
108


109
110
111
112
113
114
115
    #} $sum

    #integrity_check mallocC-$tn.$::n.4
  if {$::nErr>1} return
  }
  unset ::mallocopts
}



execsql {
  PRAGMA auto_vacuum=1;
  CREATE TABLE t0(a, b, c);
}
do_mallocC_test 1 -sql {
  BEGIN;







>
>







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
    #} $sum

    #integrity_check mallocC-$tn.$::n.4
  if {$::nErr>1} return
  }
  unset ::mallocopts
}

sqlite3_extended_result_codes db 1

execsql {
  PRAGMA auto_vacuum=1;
  CREATE TABLE t0(a, b, c);
}
do_mallocC_test 1 -sql {
  BEGIN;
Changes to test/malloc_common.tcl.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# 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 $

# If we did not compile with malloc testing enabled, then do nothing.
#
ifcapable !memdebug {
  return 0
}








|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains common code used by many different malloc tests
# within the test suite.
#
# $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.
#
ifcapable !memdebug {
  return 0
}

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

  if {[string is integer $tn]} {
    set tn malloc-$tn
  }
  if {[info exists ::mallocopts(-start)]} {
    set start $::mallocopts(-start)
  } else {
    set start 1
  }

  foreach ::iRepeat {0 1} {
    set ::go 1
    for {set ::n $start} {$::go && $::n < 50000} {incr ::n} {

      # If $::iRepeat is 0, then the malloc() failure is transient - it







|







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

  if {[string is integer $tn]} {
    set tn malloc-$tn
  }
  if {[info exists ::mallocopts(-start)]} {
    set start $::mallocopts(-start)
  } else {
    set start 0
  }

  foreach ::iRepeat {0 1} {
    set ::go 1
    for {set ::n $start} {$::go && $::n < 50000} {incr ::n} {

      # If $::iRepeat is 0, then the malloc() failure is transient - it
79
80
81
82
83
84
85
86



87
88
89
90
91
92
93
        catch {file delete -force test.db}
        catch {file delete -force test.db-journal}
        catch {file delete -force test2.db}
        catch {file delete -force test2.db-journal}
        if {[info exists ::mallocopts(-testdb)]} {
          file copy $::mallocopts(-testdb) test.db
        }
        catch {sqlite3 db test.db} 



  
        # Execute any -tclprep and -sqlprep scripts.
        #
        if {[info exists ::mallocopts(-tclprep)]} {
          eval $::mallocopts(-tclprep)
        }
        if {[info exists ::mallocopts(-sqlprep)]} {







|
>
>
>







79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
        catch {file delete -force test.db}
        catch {file delete -force test.db-journal}
        catch {file delete -force test2.db}
        catch {file delete -force test2.db-journal}
        if {[info exists ::mallocopts(-testdb)]} {
          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.
        #
        if {[info exists ::mallocopts(-tclprep)]} {
          eval $::mallocopts(-tclprep)
        }
        if {[info exists ::mallocopts(-sqlprep)]} {
124
125
126
127
128
129
130

131


132

133
134
135


136
137
138
139
140
141
142
143
144
145
146
147
            set v2 $msg
          } else {
            set isFail 1
            set v2 1
          }
        } elseif {!$isFail} {
          set v2 $msg

        } elseif {[info command db]=="" || [db errorcode]==7


                     || $msg=="out of memory"} {

          set v2 1
        } else {
          set v2 $msg


        }
        lappend isFail $v2
      } {1 1}
  
      if {[info exists ::mallocopts(-cleanup)]} {
        catch [list uplevel #0 $::mallocopts(-cleanup)] msg
      }
    }
  }
  unset ::mallocopts
  sqlite3_memdebug_fail -1
}







>
|
>
>
|
>



>
>












127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
            set v2 $msg
          } else {
            set isFail 1
            set v2 1
          }
        } elseif {!$isFail} {
          set v2 $msg
        } 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}
  
      if {[info exists ::mallocopts(-cleanup)]} {
        catch [list uplevel #0 $::mallocopts(-cleanup)] msg
      }
    }
  }
  unset ::mallocopts
  sqlite3_memdebug_fail -1
}
Changes to test/onefile.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#
#    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 all tests.
#
# $Id: onefile.test,v 1.1 2007/09/14 16:19:27 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
rename finish_test really_finish_test
proc finish_test {} {
  catch {db close}
  catch {db2 close}
  catch {db3 close}
}
set ISQUICK 1









|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#
#    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 all tests.
#
# $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_test2
proc finish_test {} {
  catch {db close}
  catch {db2 close}
  catch {db3 close}
}
set ISQUICK 1

46
47
48
49
50
51
52


53

54

55



foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
  set tail [file tail $testfile]
  if {[lsearch -exact $INCLUDE $tail]<0} continue
  source $testfile
}



really_finish_test

rename really_do_test do_test

rename really_finish_test finish_test









>
>
|
>

>
|
>
>
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
  set tail [file tail $testfile]
  if {[lsearch -exact $INCLUDE $tail]<0} continue
  source $testfile
}

file delete -force test.db test2.db test3.db test4.db

really_finish_test2
rename do_test {}
rename really_do_test do_test
rename finish_test {}
rename really_finish_test2 finish_test
rename sqlite3 {}
rename really_sqlite3 sqlite3