/ Check-in [2b3e21ce]
Login

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

Overview
Comment:Tests to improve coverage of vdbeaux.c. (CVS 2201)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 2b3e21ce2e8126ec2851751546094c3a2c831942
User & Date: danielk1977 2005-01-12 09:10:40
Context
2005-01-12
12:44
Tests to improve coverage of main.c. (CVS 2202) check-in: 4e28c82a user: danielk1977 tags: trunk
09:10
Tests to improve coverage of vdbeaux.c. (CVS 2201) check-in: 2b3e21ce user: danielk1977 tags: trunk
07:15
Tests to improve coverage of vdbemem.c. (CVS 2200) check-in: 319bb4a9 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.441 2005/01/12 07:15:06 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
    assert( pTos<=&p->aStack[pc] );
#ifdef VDBE_PROFILE
    origPc = pc;
    start = hwtime();
#endif
    pOp = &p->aOp[pc];

    /* Only allow tracing if NDEBUG is not defined.
    */
#ifndef NDEBUG
    if( p->trace ){
      if( pc==0 ){
        printf("VDBE Execution Trace:\n");
        sqlite3VdbePrintSql(p);
      }
      sqlite3VdbePrintOp(p->trace, pc, pOp);
    }
#endif
#ifdef SQLITE_TEST
    if( p->trace==0 && pc==0 && sqlite3OsFileExists("vdbe_sqltrace") ){
      sqlite3VdbePrintSql(p);
    }
#endif
      

    /* Check to see if we need to simulate an interrupt.  This only happens







|







 







|

|







<
<







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489


490
491
492
493
494
495
496
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.442 2005/01/12 09:10:40 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
    assert( pTos<=&p->aStack[pc] );
#ifdef VDBE_PROFILE
    origPc = pc;
    start = hwtime();
#endif
    pOp = &p->aOp[pc];

    /* Only allow tracing if SQLITE_DEBUG is defined.
    */
#ifdef SQLITE_DEBUG
    if( p->trace ){
      if( pc==0 ){
        printf("VDBE Execution Trace:\n");
        sqlite3VdbePrintSql(p);
      }
      sqlite3VdbePrintOp(p->trace, pc, pOp);
    }


    if( p->trace==0 && pc==0 && sqlite3OsFileExists("vdbe_sqltrace") ){
      sqlite3VdbePrintSql(p);
    }
#endif
      

    /* Check to see if we need to simulate an interrupt.  This only happens

Changes to src/vdbeInt.h.

358
359
360
361
362
363
364
365
366
367

368

369
370
371
372
373
374
375
*/
void sqlite3VdbeFreeCursor(Cursor*);
void sqlite3VdbeSorterReset(Vdbe*);
int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *);
void sqlite3VdbeKeylistFree(Keylist*);
void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(Cursor*);
#if !defined(NDEBUG) || defined(VDBE_PROFILE)
void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif

void sqlite3VdbePrintSql(Vdbe*);

int sqlite3VdbeSerialTypeLen(u32);
u32 sqlite3VdbeSerialType(Mem*);
int sqlite3VdbeSerialPut(unsigned char*, Mem*);
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);

int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);







|


>

>







358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
*/
void sqlite3VdbeFreeCursor(Cursor*);
void sqlite3VdbeSorterReset(Vdbe*);
int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *);
void sqlite3VdbeKeylistFree(Keylist*);
void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(Cursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
#ifdef SQLITE_DEBUG
void sqlite3VdbePrintSql(Vdbe*);
#endif
int sqlite3VdbeSerialTypeLen(u32);
u32 sqlite3VdbeSerialType(Mem*);
int sqlite3VdbeSerialPut(unsigned char*, Mem*);
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);

int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);

Changes to src/vdbeaux.c.

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
...
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
...
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
....
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
....
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
  }
  pOp = &p->aOp[i];
  pOp->opcode = op;
  pOp->p1 = p1;
  pOp->p2 = p2;
  pOp->p3 = 0;
  pOp->p3type = P3_NOTUSED;
#ifndef NDEBUG
  if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
#endif
  return i;
}

/*
** Add an opcode that includes the p3 value.
................................................................................
      int p2 = pIn->p2;
      VdbeOp *pOut = &p->aOp[i+addr];
      pOut->opcode = pIn->opcode;
      pOut->p1 = pIn->p1;
      pOut->p2 = p2<0 ? addr + ADDR(p2) : p2;
      pOut->p3 = pIn->p3;
      pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED;
#ifndef NDEBUG
      if( sqlite3_vdbe_addop_trace ){
        sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
      }
#endif
    }
    p->nOp += nOp;
  }
................................................................................
    }
  }
  return zP3;
}
#endif


#if !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
** Print a single opcode.  This routine is used for debugging only.
*/
void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
  char *zP3;
  char zPtr[50];
  static const char *zFormat1 = "%4d %-13s %4d %4d %s\n";
................................................................................
  }
}

/*
** Free all resources allociated with AggElem pElem, an element of
** aggregate pAgg.
*/
void freeAggElem(AggElem *pElem, Agg *pAgg){
  int i;
  for(i=0; i<pAgg->nMem; i++){
    Mem *pMem = &pElem->aMem[i];
    if( pAgg->apFunc && pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
      sqlite3_context ctx;
      ctx.pFunc = pAgg->apFunc[i];
      ctx.s.flags = MEM_Null;
................................................................................
    assert( pAgg->pBtree );
    assert( pAgg->nTab>0 );

    rc=sqlite3BtreeFirst(pCsr, &res);
    while( res==0 && rc==SQLITE_OK ){
      AggElem *pElem;
      rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem);
      if( res!=SQLITE_OK ){
        return rc;
      }
      assert( pAgg->apFunc!=0 );
      freeAggElem(pElem, pAgg);
      rc=sqlite3BtreeNext(pCsr, &res);
    }
    if( rc!=SQLITE_OK ){
................................................................................


    /* Sync the master journal file. Before doing this, open the directory
    ** the master journal file is store in so that it gets synced too.
    */
    zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
    rc = sqlite3OsOpenDirectory(zMainFile, &master);
    if( rc!=SQLITE_OK ){
      sqlite3OsClose(&master);
      sqlite3OsDelete(zMaster);
      sqliteFree(zMaster);
      return rc;
    }
    rc = sqlite3OsSync(&master);
    if( rc!=SQLITE_OK ){
      sqlite3OsClose(&master);
      sqliteFree(zMaster);
      return rc;
    }

    /* Sync all the db files involved in the transaction. The same call
    ** sets the master journal pointer in each individual journal. If
    ** an error occurs here, do not delete the master journal file.
    **
    ** If the error occurs during the first call to sqlite3BtreeSync(),
    ** then there is a chance that the master journal file will be
................................................................................
      /* This is not good. The master journal file has been deleted, but
      ** the directory sync failed. There is no completely safe course of
      ** action from here. The individual journals contain the name of the
      ** master journal file, but there is no way of knowing if that
      ** master journal exists now or if it will exist after the operating
      ** system crash that may follow the fsync() failure.
      */
      assert(0);
      sqliteFree(zMaster);
      return rc;
    }

    /* All files and directories have already been synced, so the following
    ** calls to sqlite3BtreeCommit() are only closing files and deleting
    ** journals. If something goes wrong while this is happening we don't
    ** really care. The integrity of the transaction is already guaranteed,







|







 







|







 







|







 







|







 







|







 







|





<
<
<
<
<
<







 







<
<







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
...
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
...
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
....
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066






1067
1068
1069
1070
1071
1072
1073
....
1101
1102
1103
1104
1105
1106
1107


1108
1109
1110
1111
1112
1113
1114
  }
  pOp = &p->aOp[i];
  pOp->opcode = op;
  pOp->p1 = p1;
  pOp->p2 = p2;
  pOp->p3 = 0;
  pOp->p3type = P3_NOTUSED;
#ifdef SQLITE_DEBUG
  if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
#endif
  return i;
}

/*
** Add an opcode that includes the p3 value.
................................................................................
      int p2 = pIn->p2;
      VdbeOp *pOut = &p->aOp[i+addr];
      pOut->opcode = pIn->opcode;
      pOut->p1 = pIn->p1;
      pOut->p2 = p2<0 ? addr + ADDR(p2) : p2;
      pOut->p3 = pIn->p3;
      pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED;
#ifdef SQLITE_DEBUG
      if( sqlite3_vdbe_addop_trace ){
        sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
      }
#endif
    }
    p->nOp += nOp;
  }
................................................................................
    }
  }
  return zP3;
}
#endif


#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
** Print a single opcode.  This routine is used for debugging only.
*/
void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
  char *zP3;
  char zPtr[50];
  static const char *zFormat1 = "%4d %-13s %4d %4d %s\n";
................................................................................
  }
}

/*
** Free all resources allociated with AggElem pElem, an element of
** aggregate pAgg.
*/
static void freeAggElem(AggElem *pElem, Agg *pAgg){
  int i;
  for(i=0; i<pAgg->nMem; i++){
    Mem *pMem = &pElem->aMem[i];
    if( pAgg->apFunc && pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
      sqlite3_context ctx;
      ctx.pFunc = pAgg->apFunc[i];
      ctx.s.flags = MEM_Null;
................................................................................
    assert( pAgg->pBtree );
    assert( pAgg->nTab>0 );

    rc=sqlite3BtreeFirst(pCsr, &res);
    while( res==0 && rc==SQLITE_OK ){
      AggElem *pElem;
      rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem);
      if( rc!=SQLITE_OK ){
        return rc;
      }
      assert( pAgg->apFunc!=0 );
      freeAggElem(pElem, pAgg);
      rc=sqlite3BtreeNext(pCsr, &res);
    }
    if( rc!=SQLITE_OK ){
................................................................................


    /* Sync the master journal file. Before doing this, open the directory
    ** the master journal file is store in so that it gets synced too.
    */
    zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
    rc = sqlite3OsOpenDirectory(zMainFile, &master);
    if( rc!=SQLITE_OK || (rc = sqlite3OsSync(&master))!=SQLITE_OK ){
      sqlite3OsClose(&master);
      sqlite3OsDelete(zMaster);
      sqliteFree(zMaster);
      return rc;
    }







    /* Sync all the db files involved in the transaction. The same call
    ** sets the master journal pointer in each individual journal. If
    ** an error occurs here, do not delete the master journal file.
    **
    ** If the error occurs during the first call to sqlite3BtreeSync(),
    ** then there is a chance that the master journal file will be
................................................................................
      /* This is not good. The master journal file has been deleted, but
      ** the directory sync failed. There is no completely safe course of
      ** action from here. The individual journals contain the name of the
      ** master journal file, but there is no way of knowing if that
      ** master journal exists now or if it will exist after the operating
      ** system crash that may follow the fsync() failure.
      */


      return rc;
    }

    /* All files and directories have already been synced, so the following
    ** calls to sqlite3BtreeCommit() are only closing files and deleting
    ** journals. If something goes wrong while this is happening we don't
    ** really care. The integrity of the transaction is already guaranteed,

Changes to test/ioerr.test.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

28
29
30

31
32
33

34
35
36

37


38




39
40
41
42
43



44
45








46

47
48
49








50
51

















52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77
78
..
91
92
93
94
95
96
97


98
99
100
101
102
103
104
...
131
132
133
134
135
136
137
138

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184



185
186
187
188
189
190
191
192
193
194
195
196
197

198
199
200
201
202
203
204
205










206
# This file implements regression tests for SQLite library.  The
# focus of this file is testing for correct handling of I/O errors
# such as writes failing because the disk is full.
# 
# The tests in this file use special facilities that are only
# available in the SQLite test fixture.
#
# $Id: ioerr.test,v 1.10 2005/01/11 13:02:34 danielk1977 Exp $

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

set ::AV [execsql {pragma auto_vacuum}]

set ::go 1
for {set n 1} {$go} {incr n} {


  # If SQLITE_DEFAULT_AUTOVACUUM is set to true, then a simulated IO error
  # on the 8th IO operation in the SQL script below doesn't report an error.
  #

  # This is because the 8th IO call attempts to read page 2 of the database
  # file when the file on disk is only 1 page. The pager layer detects that
  # this has happened and suppresses the error returned by the OS layer.

  #
  if {$::AV} {
    if {$n==8} continue

  } 







  do_test ioerr-1.$n.1 {
    set ::sqlite_io_error_pending 0
    db close
    catch {file delete -force test.db}
    catch {file delete -force test.db-journal}



    sqlite3 db test.db
    execsql {SELECT * FROM sqlite_master}








  } {}

  do_test ioerr-1.$n.2 [subst {
    set ::sqlite_io_error_pending $n
  }] $n








  do_test ioerr-1.$n.3 {
    set r [catch {db eval {

















      CREATE TABLE t1(a,b,c);
      SELECT * FROM sqlite_master;
      BEGIN TRANSACTION;
      INSERT INTO t1 VALUES(1,2,3);
      INSERT INTO t1 VALUES(4,5,6);
      ROLLBACK;
      SELECT * FROM t1;
      BEGIN TRANSACTION;
      INSERT INTO t1 VALUES(1,2,3);
      INSERT INTO t1 VALUES(4,5,6);
      COMMIT;
      SELECT * FROM t1;
      DELETE FROM t1 WHERE a<100;
    }} msg]
    # if {$r} {puts $msg}
    set ::go [expr {$::sqlite_io_error_pending<=0}]
    expr {$::sqlite_io_error_pending>0 || $r!=0}
  } {1}

}
set ::sqlite_io_error_pending 0

proc cksum {{db db}} {
  set txt [$db eval {
      SELECT name, type, sql FROM sqlite_master order by name
  }]\n
  foreach tbl [$db eval {
      SELECT name FROM sqlite_master WHERE type='table' order by name
................................................................................
for {set n 1} {$go} {incr n} {
  if {$n==24} breakpoint
  do_test ioerr-2.$n.1 {
    set ::sqlite_io_error_pending 0
    db close
    catch {file delete -force test.db}
    catch {file delete -force test.db-journal}


    sqlite3 db test.db
    execsql {
      BEGIN;
      CREATE TABLE t1(a, b, c);
      INSERT INTO t1 VALUES(1, randstr(5,50), randstr(5,50));
      INSERT INTO t1 SELECT a+2, b||'-'||rowid, c||'-'||rowid FROM t1;
      INSERT INTO t1 SELECT a+4, b||'-'||rowid, c||'-'||rowid FROM t1;
................................................................................
    db close
    sqlite3 db test.db
    cksum
  } $cksum
}
set ::sqlite_io_error_pending 0

set ::go 1

for {set n 1} {$go} {incr n} {
  do_test ioerr-3.$n.1 {
    set ::sqlite_io_error_pending 0
    db close
    catch {file delete -force test.db}
    catch {file delete -force test.db-journal}
    sqlite3 db test.db
    execsql {
      PRAGMA cache_size = 10;
      BEGIN;
      CREATE TABLE abc(a);
      INSERT INTO abc VALUES(randstr(1500,1500)); -- Page 4 is overflow
    }
    for {set i 0} {$i<150} {incr i} {
      execsql {
        INSERT INTO abc VALUES(randstr(100,100)); 
      }
    }
    execsql COMMIT
  } {}
  do_test ioerr-3.$n.2 [subst {
    set ::sqlite_io_error_pending $n
  }] $n
  do_test ioerr-3.$n.3 {
    set r [catch {db eval {

      CREATE TABLE abc2(a);
      BEGIN;
      DELETE FROM abc WHERE length(a)>100;
      UPDATE abc SET a = randstr(90,90);
      COMMIT;
      CREATE TABLE abc3(a);
    }} msg]
    set ::go [expr {$::sqlite_io_error_pending<=0}]
    expr {$::sqlite_io_error_pending>0 || $r!=0}
  } {1}
}
set ::sqlite_io_error_pending 0

set ::go 1
for {set n 1} {$go} {incr n} {
  do_test ioerr-4.$n.1 {
    set ::sqlite_io_error_pending 0
    db close
    catch {file delete -force test.db}
    catch {file delete -force test.db-journal}
    sqlite3 db test.db



    set sql "CREATE TABLE abc(a1"
    for {set i 2} {$i<1300} {incr i} {
      append sql ", a$i"
    }
    append sql ");"
    execsql $sql
    execsql {INSERT INTO abc (a1) VALUES(NULL)}
  } {}
  do_test ioerr-4.$n.2 [subst {
    set ::sqlite_io_error_pending $n
  }] $n
  do_test ioerr-4.$n.3 {
    set r [catch {db eval {

      SELECT * FROM abc;
    }} msg]
    set ::go [expr {$::sqlite_io_error_pending<=0}]
    expr {$::sqlite_io_error_pending>0 || $r!=0}
  } {1}
}
set ::sqlite_io_error_pending 0











finish_test







|






|
<
|
>
|
<
|
>
|
|
|
>
|
<
|
>
|
>
>
|
>
>
>
>
|
|
|
|
|
>
>
>
|
<
>
>
>
>
>
>
>
>
|
>
|
|
|
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<
<
>
|
<







 







>
>







 







<
>
|
<
<
<
<
<
<
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<
<
<
>
|
|
|
|
|
|
<
<
<
<

<

<
<
<
<
<
<
<
<
>
>
>
|
|
|
|
|
|
|
<
<
<
<
<
<
>
|
<
<
<
<

<

>
>
>
>
>
>
>
>
>
>

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

26
27
28

29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107





108
109

110
111
112
113
114
115
116
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
...
171
172
173
174
175
176
177

178
179






180
181
182
183
184
185
186
187
188
189
190
191






192
193
194
195
196
197
198




199

200








201
202
203
204
205
206
207
208
209
210






211
212




213

214
215
216
217
218
219
220
221
222
223
224
225
# This file implements regression tests for SQLite library.  The
# focus of this file is testing for correct handling of I/O errors
# such as writes failing because the disk is full.
# 
# The tests in this file use special facilities that are only
# available in the SQLite test fixture.
#
# $Id: ioerr.test,v 1.11 2005/01/12 09:10:41 danielk1977 Exp $

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

set ::AV [execsql {pragma auto_vacuum}]

# Usage: do_ioerr_test <test number> <options...>

#
# The first argument, <test number>, is an integer used to name the
# tests executed by this proc. Options are as follows:

#
#     -tclprep          TCL script to run to prepare test.
#     -sqlprep          SQL script to run to prepare test.
#     -tclbody          TCL script to run with IO error simulation.
#     -sqlbody          TCL script to run with IO error simulation.
#     -exclude          List of 'N' values not to test.
#

proc do_ioerr_test {tn args} {
  array set ::ioerropts $args

  set ::go 1
  for {set n 1} {$::go} {incr n} {
 
    if {[info exists ::ioerropts(-exclude)]} {
      if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue
    }

    do_test ioerr-$tn.$n.1 {
      set ::sqlite_io_error_pending 0
      db close
      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}
  
      set ::DB [sqlite3 db test.db]

  
      if {[info exists ::ioerropts(-tclprep)]} {
        eval $::ioerropts(-tclprep)
      }
      if {[info exists ::ioerropts(-sqlprep)]} {
        execsql $::ioerropts(-sqlprep)
      }
      expr 0
    } {0}
  
    do_test ioerr-$tn.$n.2 [subst {
      set ::sqlite_io_error_pending $n
    }] $n
  
    set ::ioerrorbody {}
    if {[info exists ::ioerropts(-tclbody)]} {
      append ::ioerrorbody "$::ioerropts(-tclbody)\n"
    }
    if {[info exists ::ioerropts(-sqlbody)]} {
      append ::ioerrorbody "db eval {$::ioerropts(-sqlbody)}"
    }
    do_test ioerr-$tn.$n.3 {
      set r [catch $::ioerrorbody msg]
      set ::go [expr {$::sqlite_io_error_pending<=0}]
      expr {$::sqlite_io_error_pending>0 || $r!=0}
    } {1}
  }
  set ::sqlite_io_error_pending 0
}

# If SQLITE_DEFAULT_AUTOVACUUM is set to true, then a simulated IO error
# on the 8th IO operation in the SQL script below doesn't report an error.
#
# This is because the 8th IO call attempts to read page 2 of the database
# file when the file on disk is only 1 page. The pager layer detects that
# this has happened and suppresses the error returned by the OS layer.
#
do_ioerr_test 1 -sqlprep {
  SELECT * FROM sqlite_master;
} -sqlbody {
  CREATE TABLE t1(a,b,c);
  SELECT * FROM sqlite_master;
  BEGIN TRANSACTION;
  INSERT INTO t1 VALUES(1,2,3);
  INSERT INTO t1 VALUES(4,5,6);
  ROLLBACK;
  SELECT * FROM t1;
  BEGIN TRANSACTION;
  INSERT INTO t1 VALUES(1,2,3);
  INSERT INTO t1 VALUES(4,5,6);
  COMMIT;
  SELECT * FROM t1;
  DELETE FROM t1 WHERE a<100;





} -exclude [expr [execsql {pragma auto_vacuum}] ? 8 : 0]



proc cksum {{db db}} {
  set txt [$db eval {
      SELECT name, type, sql FROM sqlite_master order by name
  }]\n
  foreach tbl [$db eval {
      SELECT name FROM sqlite_master WHERE type='table' order by name
................................................................................
for {set n 1} {$go} {incr n} {
  if {$n==24} breakpoint
  do_test ioerr-2.$n.1 {
    set ::sqlite_io_error_pending 0
    db close
    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}
    sqlite3 db test.db
    execsql {
      BEGIN;
      CREATE TABLE t1(a, b, c);
      INSERT INTO t1 VALUES(1, randstr(5,50), randstr(5,50));
      INSERT INTO t1 SELECT a+2, b||'-'||rowid, c||'-'||rowid FROM t1;
      INSERT INTO t1 SELECT a+4, b||'-'||rowid, c||'-'||rowid FROM t1;
................................................................................
    db close
    sqlite3 db test.db
    cksum
  } $cksum
}
set ::sqlite_io_error_pending 0



do_ioerr_test 3 -tclprep {






  execsql {
    PRAGMA cache_size = 10;
    BEGIN;
    CREATE TABLE abc(a);
    INSERT INTO abc VALUES(randstr(1500,1500)); -- Page 4 is overflow
  }
  for {set i 0} {$i<150} {incr i} {
    execsql {
      INSERT INTO abc VALUES(randstr(100,100)); 
    }
  }
  execsql COMMIT






} -sqlbody {
  CREATE TABLE abc2(a);
  BEGIN;
  DELETE FROM abc WHERE length(a)>100;
  UPDATE abc SET a = randstr(90,90);
  COMMIT;
  CREATE TABLE abc3(a);




}










# Test IO errors that can occur retrieving a record header that flows over
# onto an overflow page.
do_ioerr_test 4 -tclprep {
  set sql "CREATE TABLE abc(a1"
  for {set i 2} {$i<1300} {incr i} {
    append sql ", a$i"
  }
  append sql ");"
  execsql $sql
  execsql {INSERT INTO abc (a1) VALUES(NULL)}






} -sqlbody {
 SELECT * FROM abc;




}


# Test IO errors that may occur during a multi-file commit.
do_ioerr_test 5 -sqlprep {
  ATTACH 'test2.db' AS test2;
} -sqlbody {
  BEGIN;
  CREATE TABLE t1(a,b,c);
  CREATE TABLE test2.t2(a,b,c);
  COMMIT;
}

finish_test

Changes to test/malloc.test.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
338
339
340
341
342
343
344


345
346


347
348
349
350
351
352
353
...
377
378
379
380
381
382
383








































384
385
386
387
388
389
390
391
392
#***********************************************************************
# This file attempts to check the library in an out-of-memory situation.
# When compiled with -DSQLITE_DEBUG=1, the SQLite library accepts a special
# command (sqlite_malloc_fail N) 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.14 2005/01/12 07:15:07 danielk1977 Exp $

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

# Only run these tests if memory debugging is turned on.
#
if {[info command sqlite_malloc_stat]==""} {
................................................................................
}

# This block is designed to test that some malloc failures that may
# occur in vdbeapi.c. Specifically, if a malloc failure that occurs
# when converting UTF-16 text to integers and real numbers is handled
# correctly. 
#


# This doesn't actually return an error to the user. That could be 
# viewed as a bug.


#
for {set go 1; set i 1} {$go && $::sqlite_options(utf16)} {incr i} {
  do_test malloc-8.$i {
     sqlite_malloc_fail 0
     catch {db close}
     catch {file delete -force test.db}
     catch {file delete -force test.db-journal}
................................................................................
     sqlite3_finalize $::STMT
     if {[lindex [sqlite_malloc_stat] 2]>0} {
       set ::go 0
     }
     expr 0
  } {0}
}









































# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
  catch {db close}
  set sqlite_open_file_count
} {0}

sqlite_malloc_fail 0
finish_test







|







 







>
>
|
|
>
>







 







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









10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
...
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
#***********************************************************************
# This file attempts to check the library in an out-of-memory situation.
# When compiled with -DSQLITE_DEBUG=1, the SQLite library accepts a special
# command (sqlite_malloc_fail N) 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.15 2005/01/12 09:10:41 danielk1977 Exp $

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

# Only run these tests if memory debugging is turned on.
#
if {[info command sqlite_malloc_stat]==""} {
................................................................................
}

# This block is designed to test that some malloc failures that may
# occur in vdbeapi.c. Specifically, if a malloc failure that occurs
# when converting UTF-16 text to integers and real numbers is handled
# correctly. 
#
# This is done by retrieving a string from the database engine and
# manipulating it using the sqlite3_column_*** APIs. This doesn't 
# actually return an error to the user when a malloc() fails.. That 
# could be viewed as a bug.
#
# These tests only run if UTF-16 support is compiled in.
#
for {set go 1; set i 1} {$go && $::sqlite_options(utf16)} {incr i} {
  do_test malloc-8.$i {
     sqlite_malloc_fail 0
     catch {db close}
     catch {file delete -force test.db}
     catch {file delete -force test.db-journal}
................................................................................
     sqlite3_finalize $::STMT
     if {[lindex [sqlite_malloc_stat] 2]>0} {
       set ::go 0
     }
     expr 0
  } {0}
}

# This block tests that malloc() failures that occur whilst commiting
# a multi-file transaction are handled correctly.
#
for {set go 1; set i 1} {$go} {incr i} {
  do_test malloc-9.$i {
     sqlite_malloc_fail 0
     catch {db close}
     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}

     sqlite3 db test.db
     execsql {
       ATTACH 'test2.db' as test2;
       CREATE TABLE abc1(a, b, c);
       CREATE TABLE test2.abc2(a, b, c);
     }

     sqlite_malloc_fail $i
     set v [catch {execsql {
       BEGIN;
       INSERT INTO abc1 VALUES(1, 2, 3);
       INSERT INTO abc2 VALUES(1, 2, 3);
       COMMIT;
     }} msg]
     set leftover [lindex [sqlite_malloc_stat] 2]
     if {$leftover>0} {
       if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v  Message=$msg"}
       set ::go 0
       set v {1 1}
     } else {
       set v2 [expr {$msg=="" || $msg=="out of memory"}]
       if {!$v2} {puts "\nError message returned: $msg"}
       lappend v $v2
     }
  } {1 1}
}


# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
  catch {db close}
  set sqlite_open_file_count
} {0}

sqlite_malloc_fail 0
finish_test