/ Check-in [c4be8d99]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Modifications to crash-test infrastructure. (CVS 3695)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c4be8d9949fc7b5e1bed757423c5195f38069048
User & Date: danielk1977 2007-03-17 10:26:59
Context
2007-03-17
10:28
Add crash2.test, for robustness testing with variable disk block size. (CVS 3696) check-in: b0f8203d user: danielk1977 tags: trunk
10:26
Modifications to crash-test infrastructure. (CVS 3695) check-in: c4be8d99 user: danielk1977 tags: trunk
07:22
Combine the two very similar definitions of (crashsql) in the test scripts. (CVS 3694) check-in: eaf434d5 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
....
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
**     CREATE INDEX
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**
** $Id: build.c,v 1.414 2007/03/13 16:32:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Initialize the pParse structure as needed.
................................................................................
    if( !db->init.busy ){
      if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
      if( sqlite3FindTable(db, zName, 0)!=0 ){
        sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
        goto exit_create_index;
      }
    }
      if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
        if( !ifNotExist ){
          sqlite3ErrorMsg(pParse, "index %s already exists", zName);
        }
        goto exit_create_index;
      }
  }else{
    char zBuf[30];
    int n;
    Index *pLoop;
    for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
    sprintf(zBuf,"_%d",n);
    zName = 0;







|







 







|
|
|
|
|
|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
....
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
**     CREATE INDEX
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**
** $Id: build.c,v 1.415 2007/03/17 10:26:59 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Initialize the pParse structure as needed.
................................................................................
    if( !db->init.busy ){
      if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
      if( sqlite3FindTable(db, zName, 0)!=0 ){
        sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
        goto exit_create_index;
      }
    }
    if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
      if( !ifNotExist ){
        sqlite3ErrorMsg(pParse, "index %s already exists", zName);
      }
      goto exit_create_index;
    }
  }else{
    char zBuf[30];
    int n;
    Index *pLoop;
    for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
    sprintf(zBuf,"_%d",n);
    zName = 0;

Changes to src/test6.c.

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
54
55
56
57
58
59
60





61
62
63
64
65
66
67
68
69
70










71
72
73
74
75
76
77
..
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
...
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
531
532
533
534
535
536
537










538
539
540
541
542
543
544
  int nMaxWrite;           /* Largest offset written to. */
  char *zName;             /* File name */
  OsFile *pBase;           /* The real file */
  crashFile *pNext;        /* Next in a list of them all */
};

/*
** Size of a simulated disk block
*/
#define BLOCKSIZE 512
#define BLOCK_OFFSET(x) ((x) * BLOCKSIZE)


/*
** The following variables control when a simulated crash occurs.
**
** If iCrashDelay is non-zero, then zCrashFile contains (full path) name of
................................................................................
**
** In other words, a crash occurs the iCrashDelay'th time zCrashFile is
** synced.
*/
static int iCrashDelay = 0;
static char zCrashFile[500];






/*
** Set the value of the two crash parameters.
*/
static void setCrashParams(int iDelay, char const *zFile){
  sqlite3OsEnterMutex();
  assert( strlen(zFile)<sizeof(zCrashFile) );
  strcpy(zCrashFile, zFile);
  iCrashDelay = iDelay;
  sqlite3OsLeaveMutex();
}











/*
** File zPath is being sync()ed. Return non-zero if this should
** cause a crash.
*/
static int crashRequired(char const *zPath){
  int r;
................................................................................
      r = 1;
    }
  }
  sqlite3OsLeaveMutex();
  return r;
}

/*
** A list of all open files.
*/
static crashFile *pAllFiles = 0;

/* Forward reference */
static void initFile(OsFile **pId, char const *zName, OsFile *pBase);

/*
** Undo the work done by initFile. Delete the OsFile structure
** and unlink the structure from the pAllFiles list.
*/
................................................................................
  pFile->pNext = pAllFiles;
  pAllFiles = pFile;
  *pId = (OsFile*)pFile;
}


/*
** tclcmd:   sqlite_crashparams DELAY CRASHFILE
**
** This procedure implements a TCL command that enables crash testing
** in testfixture.  Once enabled, crash testing cannot be disabled.
*/
static int crashParamsObjCmd(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int delay;
  const char *zFile;
  int nFile;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DELAY CRASHFILE");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[1], &delay) ) return TCL_ERROR;
  zFile = Tcl_GetStringFromObj(objv[2], &nFile);
  if( nFile>=sizeof(zCrashFile)-1 ){
    Tcl_AppendResult(interp, "crash file name too big", 0);
    return TCL_ERROR;
  }
  setCrashParams(delay, zFile);










  sqlite3CrashTestEnable = 1;
  return TCL_OK;
}

#endif /* SQLITE_OMIT_DISKIO */

/*







|

|







 







>
>
>
>
>










>
>
>
>
>
>
>
>
>
>







 







<
<
<
<
<







 







|










|


>
|
|


|





|
>
>
>
>
>
>
>
>
>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
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
...
105
106
107
108
109
110
111





112
113
114
115
116
117
118
...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  int nMaxWrite;           /* Largest offset written to. */
  char *zName;             /* File name */
  OsFile *pBase;           /* The real file */
  crashFile *pNext;        /* Next in a list of them all */
};

/*
** Size of a simulated disk block. Default is 512 bytes.
*/
static int BLOCKSIZE = 512;
#define BLOCK_OFFSET(x) ((x) * BLOCKSIZE)


/*
** The following variables control when a simulated crash occurs.
**
** If iCrashDelay is non-zero, then zCrashFile contains (full path) name of
................................................................................
**
** In other words, a crash occurs the iCrashDelay'th time zCrashFile is
** synced.
*/
static int iCrashDelay = 0;
static char zCrashFile[500];

/*
** A list of all open files.
*/
static crashFile *pAllFiles = 0;

/*
** Set the value of the two crash parameters.
*/
static void setCrashParams(int iDelay, char const *zFile){
  sqlite3OsEnterMutex();
  assert( strlen(zFile)<sizeof(zCrashFile) );
  strcpy(zCrashFile, zFile);
  iCrashDelay = iDelay;
  sqlite3OsLeaveMutex();
}

/*
** Set the value of the simulated disk block size.
*/
static void setBlocksize(int iBlockSize){
  sqlite3OsEnterMutex();
  assert( !pAllFiles );
  BLOCKSIZE = iBlockSize;
  sqlite3OsLeaveMutex();
}

/*
** File zPath is being sync()ed. Return non-zero if this should
** cause a crash.
*/
static int crashRequired(char const *zPath){
  int r;
................................................................................
      r = 1;
    }
  }
  sqlite3OsLeaveMutex();
  return r;
}






/* Forward reference */
static void initFile(OsFile **pId, char const *zName, OsFile *pBase);

/*
** Undo the work done by initFile. Delete the OsFile structure
** and unlink the structure from the pAllFiles list.
*/
................................................................................
  pFile->pNext = pAllFiles;
  pAllFiles = pFile;
  *pId = (OsFile*)pFile;
}


/*
** tclcmd:   sqlite_crashparams DELAY CRASHFILE ?BLOCKSIZE?
**
** This procedure implements a TCL command that enables crash testing
** in testfixture.  Once enabled, crash testing cannot be disabled.
*/
static int crashParamsObjCmd(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int iDelay;
  const char *zFile;
  int nFile;

  if( objc!=3 && objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DELAY CRASHFILE ?BLOCKSIZE?");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[1], &iDelay) ) return TCL_ERROR;
  zFile = Tcl_GetStringFromObj(objv[2], &nFile);
  if( nFile>=sizeof(zCrashFile)-1 ){
    Tcl_AppendResult(interp, "crash file name too big", 0);
    return TCL_ERROR;
  }
  setCrashParams(iDelay, zFile);
  if( objc==4 ){
    int iBlockSize = 0;
    if( Tcl_GetIntFromObj(interp, objv[3], &iBlockSize) ) return TCL_ERROR;
    if( pAllFiles ){
      char *zErr = "Cannot modify blocksize after opening files";
      Tcl_SetResult(interp, zErr, TCL_STATIC);
      return TCL_ERROR;
    }
    setBlocksize(iBlockSize);
  }
  sqlite3CrashTestEnable = 1;
  return TCL_OK;
}

#endif /* SQLITE_OMIT_DISKIO */

/*

Changes to test/all.test.

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
47
48
49
50
51
52
53

54
55
56
57
58
59
60
#    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: all.test,v 1.36 2006/11/23 21:09:11 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
rename finish_test really_finish_test
proc finish_test {} {memleak_check}

if {[file exists ./sqlite_test_count]} {
................................................................................
#
set LeakList {}

set EXCLUDE {
  all.test
  async.test
  crash.test

  autovacuum_crash.test
  quick.test
  malloc.test
  misuse.test
  memleak.test
  speed1.test
}







|







 







>







6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#    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: all.test,v 1.37 2007/03/17 10:26:59 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
rename finish_test really_finish_test
proc finish_test {} {memleak_check}

if {[file exists ./sqlite_test_count]} {
................................................................................
#
set LeakList {}

set EXCLUDE {
  all.test
  async.test
  crash.test
  crash2.test
  autovacuum_crash.test
  quick.test
  malloc.test
  misuse.test
  memleak.test
  speed1.test
}

Changes to test/crash.test.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
..
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
...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
...
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
...
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# The focus of this file is testing the ability of the database to
# uses its rollback journal to recover intact (no database corruption)
# from a power failure during the middle of a COMMIT.  The OS interface
# modules are overloaded in a separate instance of testfixture using
# the modified I/O routines found in test6.c.  These routines allow us
# to simulate the kind of file damage that occurs after a power failure.
#
# $Id: crash.test,v 1.22 2007/03/17 07:22:43 danielk1977 Exp $

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

ifcapable !crashtest {
  finish_test
  return
................................................................................
    INSERT INTO abc VALUES(1, 2, 3);
    INSERT INTO abc VALUES(4, 5, 6);
  }
  set ::sig [signature]
  expr 0
} {0}
do_test crash-1.2 {
  crashsql 1 test.db-journal {
    DELETE FROM abc WHERE a = 1;
  }
} {1 {child process exited abnormally}}
do_test crash-1.3 {
  signature
} $::sig
do_test crash-1.4 {
  crashsql 1 test.db {
    DELETE FROM abc WHERE a = 1;
  }
} {1 {child process exited abnormally}}
do_test crash-1.5 {
  signature
} $::sig
do_test crash-1.6 {
  crashsql 2 test.db-journal {
    DELETE FROM abc WHERE a = 1;
  }
} {1 {child process exited abnormally}}
do_test crash-1.7 {
  catchsql {
    SELECT * FROM abc;
  }
} {0 {1 2 3 4 5 6}}

do_test crash-1.8 {
  crashsql 3 test.db-journal {
    DELETE FROM abc WHERE a = 1;
  }
} {0 {}}
do_test crash-1.9 {
  catchsql {
    SELECT * FROM abc;
  }
} {0 {4 5 6}}
do_test crash-1.10 {
  crashsql 2 test.db {
    DELETE FROM abc WHERE a = 4;
  }
} {0 {}}
do_test crash-1.11 {
  catchsql {
    SELECT * FROM abc;
  }
................................................................................
  set ::sig [signature]
  execsql { SELECT sum(a), sum(b), sum(c) from abc }
} {499500 999000 1498500}
do_test crash-2.2 {
  expr ([file size test.db] / 1024)>16
} {1}
do_test crash-2.3 {
  crashsql 2 test.db-journal {
    DELETE FROM abc WHERE a < 800;
  }
} {1 {child process exited abnormally}}
do_test crash-2.4 {
  signature
} $sig
do_test crash-2.5 {
  crashsql 1 test.db {
    DELETE FROM abc WHERE a<800;
  }
} {1 {child process exited abnormally}}
do_test crash-2.6 {
  signature
} $sig

................................................................................
    INSERT INTO abc SELECT * FROM abc;
  }
  expr ([file size test.db] / 1024) > 450
} {1}
for {set i 1} {$i < $repeats} {incr i} {
  set sig [signature]
  do_test crash-3.$i.1 {
     crashsql [expr $i%5 + 1] test.db-journal "
       BEGIN;
       SELECT random() FROM abc LIMIT $i;
       INSERT INTO abc VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc WHERE random()%10!=0;
       COMMIT;
     "
  } {1 {child process exited abnormally}}
................................................................................
  expr ([file size test2.db] / 1024) > 450
} {1}

for {set i 1} {$i<$repeats} {incr i} {
  set sig [signature]
  set sig2 [signature2]
  do_test crash-4.1.$i.1 {
     set c [crashsql $i test.db-journal "
       ATTACH 'test2.db' AS aux;
       BEGIN;
       SELECT random() FROM abc LIMIT $i;
       INSERT INTO abc VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc WHERE random()%10!=0;
       INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc2 WHERE random()%10!=0;
................................................................................
} 
set i 0
while {[incr i]} {
  set sig [signature]
  set sig2 [signature2]
  set ::fin 0
  do_test crash-4.2.$i.1 {
     set c [crashsql $i test2.db-journal "
       ATTACH 'test2.db' AS aux;
       BEGIN;
       SELECT random() FROM abc LIMIT $i;
       INSERT INTO abc VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc WHERE random()%10!=0;
       INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc2 WHERE random()%10!=0;
................................................................................
    signature2
  } $sig2
} 
for {set i 1} {$i < 5} {incr i} {
  set sig [signature]
  set sig2 [signature2]
  do_test crash-4.3.$i.1 {
     crashsql 1 test.db-mj* "
       ATTACH 'test2.db' AS aux;
       BEGIN;
       SELECT random() FROM abc LIMIT $i;
       INSERT INTO abc VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc WHERE random()%10!=0;
       INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc2 WHERE random()%10!=0;
................................................................................
#    is sync()hronized.
# 6: Commit. A crash occurs during the sync of the journal file.
#
# End result: Before the bug was fixed, data has been written to page 4 of the
# database file and the journal file does not contain trustworthy rollback
# data for this page.
#
  crashsql 1 test.db-journal {
    BEGIN;                                             -- 1
    DELETE FROM abc WHERE oid = 1;                     -- 2
    INSERT INTO abc VALUES(randstr(1500,1500), 0, 0);  -- 3
    CREATE TABLE abc2(a, b, c);                        -- 4
    SELECT * FROM abc;                                 -- 5
    COMMIT;                                            -- 6
  }
................................................................................
#--------------------------------------------------------------------------
# The following test cases - crash-6.* - test that a DROP TABLE operation
# is correctly rolled back in the event of a crash while the database file
# is being written. This is mainly to test that all pages are written to the
# journal file before truncation in an auto-vacuum database.
#
do_test crash-6.1 {
  crashsql 1 test.db {
    DROP TABLE abc;
  }
} {1 {child process exited abnormally}}
do_test crash-6.2 {
  signature
} $sig

#--------------------------------------------------------------------------
# These test cases test the case where the master journal file name is 
# corrupted slightly so that the corruption has to be detected by the
# checksum.
do_test crash-7.1 {
  crashsql 1 test.db {
    ATTACH 'test2.db' AS aux;
    BEGIN;
    INSERT INTO abc VALUES(randstr(1500,1500), 0, 0);
    INSERT INTO abc2 VALUES(randstr(1500,1500), 0, 0);
    COMMIT;
  }








|
|
|

|







 







|







|







|










|









|







 







|







|







 







|







 







|







 







|







 







|







 







|







 







|












|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
..
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
...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
...
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
...
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# The focus of this file is testing the ability of the database to
# uses its rollback journal to recover intact (no database corruption)
# from a power failure during the middle of a COMMIT.  The OS interface
# modules are overloaded using the modified I/O routines found in test6.c.  
# These routines allow us to simulate the kind of file damage that 
# occurs after a power failure.
#
# $Id: crash.test,v 1.23 2007/03/17 10:26:59 danielk1977 Exp $

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

ifcapable !crashtest {
  finish_test
  return
................................................................................
    INSERT INTO abc VALUES(1, 2, 3);
    INSERT INTO abc VALUES(4, 5, 6);
  }
  set ::sig [signature]
  expr 0
} {0}
do_test crash-1.2 {
  crashsql -delay 1 -file test.db-journal {
    DELETE FROM abc WHERE a = 1;
  }
} {1 {child process exited abnormally}}
do_test crash-1.3 {
  signature
} $::sig
do_test crash-1.4 {
  crashsql -delay 1 -file test.db {
    DELETE FROM abc WHERE a = 1;
  }
} {1 {child process exited abnormally}}
do_test crash-1.5 {
  signature
} $::sig
do_test crash-1.6 {
  crashsql -delay 2 -file test.db-journal {
    DELETE FROM abc WHERE a = 1;
  }
} {1 {child process exited abnormally}}
do_test crash-1.7 {
  catchsql {
    SELECT * FROM abc;
  }
} {0 {1 2 3 4 5 6}}

do_test crash-1.8 {
  crashsql -delay 3 -file test.db-journal {
    DELETE FROM abc WHERE a = 1;
  }
} {0 {}}
do_test crash-1.9 {
  catchsql {
    SELECT * FROM abc;
  }
} {0 {4 5 6}}
do_test crash-1.10 {
  crashsql -delay 2 -file test.db {
    DELETE FROM abc WHERE a = 4;
  }
} {0 {}}
do_test crash-1.11 {
  catchsql {
    SELECT * FROM abc;
  }
................................................................................
  set ::sig [signature]
  execsql { SELECT sum(a), sum(b), sum(c) from abc }
} {499500 999000 1498500}
do_test crash-2.2 {
  expr ([file size test.db] / 1024)>16
} {1}
do_test crash-2.3 {
  crashsql -delay 2 -file test.db-journal {
    DELETE FROM abc WHERE a < 800;
  }
} {1 {child process exited abnormally}}
do_test crash-2.4 {
  signature
} $sig
do_test crash-2.5 {
  crashsql -delay 1 -file test.db {
    DELETE FROM abc WHERE a<800;
  }
} {1 {child process exited abnormally}}
do_test crash-2.6 {
  signature
} $sig

................................................................................
    INSERT INTO abc SELECT * FROM abc;
  }
  expr ([file size test.db] / 1024) > 450
} {1}
for {set i 1} {$i < $repeats} {incr i} {
  set sig [signature]
  do_test crash-3.$i.1 {
     crashsql -delay [expr $i%5 + 1] -file test.db-journal "
       BEGIN;
       SELECT random() FROM abc LIMIT $i;
       INSERT INTO abc VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc WHERE random()%10!=0;
       COMMIT;
     "
  } {1 {child process exited abnormally}}
................................................................................
  expr ([file size test2.db] / 1024) > 450
} {1}

for {set i 1} {$i<$repeats} {incr i} {
  set sig [signature]
  set sig2 [signature2]
  do_test crash-4.1.$i.1 {
     set c [crashsql -delay $i -file test.db-journal "
       ATTACH 'test2.db' AS aux;
       BEGIN;
       SELECT random() FROM abc LIMIT $i;
       INSERT INTO abc VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc WHERE random()%10!=0;
       INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc2 WHERE random()%10!=0;
................................................................................
} 
set i 0
while {[incr i]} {
  set sig [signature]
  set sig2 [signature2]
  set ::fin 0
  do_test crash-4.2.$i.1 {
     set c [crashsql -delay $i -file test2.db-journal "
       ATTACH 'test2.db' AS aux;
       BEGIN;
       SELECT random() FROM abc LIMIT $i;
       INSERT INTO abc VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc WHERE random()%10!=0;
       INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc2 WHERE random()%10!=0;
................................................................................
    signature2
  } $sig2
} 
for {set i 1} {$i < 5} {incr i} {
  set sig [signature]
  set sig2 [signature2]
  do_test crash-4.3.$i.1 {
     crashsql -delay 1 -file test.db-mj* "
       ATTACH 'test2.db' AS aux;
       BEGIN;
       SELECT random() FROM abc LIMIT $i;
       INSERT INTO abc VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc WHERE random()%10!=0;
       INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
       DELETE FROM abc2 WHERE random()%10!=0;
................................................................................
#    is sync()hronized.
# 6: Commit. A crash occurs during the sync of the journal file.
#
# End result: Before the bug was fixed, data has been written to page 4 of the
# database file and the journal file does not contain trustworthy rollback
# data for this page.
#
  crashsql -delay 1 -file test.db-journal {
    BEGIN;                                             -- 1
    DELETE FROM abc WHERE oid = 1;                     -- 2
    INSERT INTO abc VALUES(randstr(1500,1500), 0, 0);  -- 3
    CREATE TABLE abc2(a, b, c);                        -- 4
    SELECT * FROM abc;                                 -- 5
    COMMIT;                                            -- 6
  }
................................................................................
#--------------------------------------------------------------------------
# The following test cases - crash-6.* - test that a DROP TABLE operation
# is correctly rolled back in the event of a crash while the database file
# is being written. This is mainly to test that all pages are written to the
# journal file before truncation in an auto-vacuum database.
#
do_test crash-6.1 {
  crashsql -delay 1 -file test.db {
    DROP TABLE abc;
  }
} {1 {child process exited abnormally}}
do_test crash-6.2 {
  signature
} $sig

#--------------------------------------------------------------------------
# These test cases test the case where the master journal file name is 
# corrupted slightly so that the corruption has to be detected by the
# checksum.
do_test crash-7.1 {
  crashsql -delay 1 -file test.db {
    ATTACH 'test2.db' AS aux;
    BEGIN;
    INSERT INTO abc VALUES(randstr(1500,1500), 0, 0);
    INSERT INTO abc2 VALUES(randstr(1500,1500), 0, 0);
    COMMIT;
  }

Changes to test/ioerr.test.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# 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.30 2007/03/15 12:17:43 drh Exp $

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


# 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.
................................................................................
  if {![catch {sqlite3 -has_codec} r] && !$r} {
    do_ioerr_test ioerr-6 -tclprep {
      execsql {
        ATTACH 'test2.db' as aux;
        CREATE TABLE tx(a, b);
        CREATE TABLE aux.ty(a, b);
      }
      set rc [crashsql 2 test2.db-journal {
        ATTACH 'test2.db' as aux;
        PRAGMA cache_size = 10;
        BEGIN;
        CREATE TABLE aux.t2(a, b, c);
        CREATE TABLE t1(a, b, c);
        COMMIT;
      }]







|







 







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# 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.31 2007/03/17 10:26:59 danielk1977 Exp $

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


# 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.
................................................................................
  if {![catch {sqlite3 -has_codec} r] && !$r} {
    do_ioerr_test ioerr-6 -tclprep {
      execsql {
        ATTACH 'test2.db' as aux;
        CREATE TABLE tx(a, b);
        CREATE TABLE aux.ty(a, b);
      }
      set rc [crashsql -delay 2 -file test2.db-journal {
        ATTACH 'test2.db' as aux;
        PRAGMA cache_size = 10;
        BEGIN;
        CREATE TABLE aux.t2(a, b, c);
        CREATE TABLE t1(a, b, c);
        COMMIT;
      }]

Changes to test/malloc.test.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
#***********************************************************************
# 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.36 2006/10/18 23:26:39 drh 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]==""} {
................................................................................
  sqlite3_finalize $::STMT
} 

# Test malloc errors when replaying two hot journals from a 2-file 
# transaction.
ifcapable crashtest {
  do_malloc_test 13 -tclprep {
    set rc [crashsql 1 test2.db {
      ATTACH 'test2.db' as aux;
      PRAGMA cache_size = 10;
      BEGIN;
      CREATE TABLE aux.t2(a, b, c);
      CREATE TABLE t1(a, b, c);
      COMMIT;
    }]







|







 







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
#***********************************************************************
# 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.37 2007/03/17 10:26:59 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]==""} {
................................................................................
  sqlite3_finalize $::STMT
} 

# Test malloc errors when replaying two hot journals from a 2-file 
# transaction.
ifcapable crashtest {
  do_malloc_test 13 -tclprep {
    set rc [crashsql -delay 1 -file test2.db {
      ATTACH 'test2.db' as aux;
      PRAGMA cache_size = 10;
      BEGIN;
      CREATE TABLE aux.t2(a, b, c);
      CREATE TABLE t1(a, b, c);
      COMMIT;
    }]

Changes to test/quick.test.

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
39
40
41
42
43
44
45

46
47
48
49
50
51
52
#    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: quick.test,v 1.47 2006/11/23 21:09:11 drh Exp $

proc lshift {lvar} {
  upvar $lvar l
  set ret [lindex $l 0]
  set l [lrange $l 1 end]
  return $ret
}
................................................................................
  btree2.test
  btree3.test
  btree4.test
  btree5.test
  btree6.test
  corrupt.test
  crash.test

  loadext.test
  malloc.test
  malloc2.test
  malloc3.test
  memleak.test
  misuse.test
  quick.test







|







 







>







2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#    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: quick.test,v 1.48 2007/03/17 10:26:59 danielk1977 Exp $

proc lshift {lvar} {
  upvar $lvar l
  set ret [lindex $l 0]
  set l [lrange $l 1 end]
  return $ret
}
................................................................................
  btree2.test
  btree3.test
  btree4.test
  btree5.test
  btree6.test
  corrupt.test
  crash.test
  crash2.test
  loadext.test
  malloc.test
  malloc2.test
  malloc3.test
  memleak.test
  misuse.test
  quick.test

Changes to test/tester.tcl.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
305
306
307
308
309
310
311


312
313
314
315





















316
317
318
319
320
321
322
323
324
325
326
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
# $Id: tester.tcl,v 1.74 2007/03/17 07:22:43 danielk1977 Exp $

# Make sure tclsqlite3 was compiled correctly.  Abort now with an
# error message if not.
#
if {[sqlite3 -tcl-uses-utf]} {
  if {"\u1234"=="u1234"} {
    puts stderr "***** BUILD PROBLEM *****"
................................................................................
#
# The return value is a list of two elements. The first element is a
# boolean, indicating whether or not the process actually crashed or
# reported some other error. The second element in the returned list is the
# error message. This is "child process exited abnormally" if the crash
# occured.
#


proc crashsql {crashdelay crashfile sql} {
  if {$::tcl_platform(platform)!="unix"} {
    error "crashsql should only be used on unix"
  }





















  set cfile [file join [pwd] $crashfile]

  set f [open crash.tcl w]
  puts $f "sqlite3_crashparams $crashdelay $cfile"
  puts $f "set sqlite_pending_byte $::sqlite_pending_byte"
  puts $f "sqlite3 db test.db"

  # This block sets the cache size of the main database to 10
  # pages. This is done in case the build is configured to omit
  # "PRAGMA cache_size".
  puts $f {db eval {SELECT * FROM sqlite_master;}}







|







 







>
>
|



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



|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
305
306
307
308
309
310
311
312
313
314
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
341
342
343
344
345
346
347
348
349
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
# $Id: tester.tcl,v 1.75 2007/03/17 10:26:59 danielk1977 Exp $

# Make sure tclsqlite3 was compiled correctly.  Abort now with an
# error message if not.
#
if {[sqlite3 -tcl-uses-utf]} {
  if {"\u1234"=="u1234"} {
    puts stderr "***** BUILD PROBLEM *****"
................................................................................
#
# The return value is a list of two elements. The first element is a
# boolean, indicating whether or not the process actually crashed or
# reported some other error. The second element in the returned list is the
# error message. This is "child process exited abnormally" if the crash
# occured.
#
#   crashsql -delay CRASHDELAY -file CRASHFILE ?-blocksize BLOCKSIZE $sql
#
proc crashsql {args} {
  if {$::tcl_platform(platform)!="unix"} {
    error "crashsql should only be used on unix"
  }

  set blocksize ""
  set crashdelay 1
  set crashfile ""
  set sql [lindex $args end]
  
  for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} {
    set z [lindex $args $ii]
    set n [string length $z]
    set z2 [lindex $args [expr $ii+1]]

    if     {$n>1 && [string first $z -delay]==0}     {set crashdelay $z2} \
    elseif {$n>1 && [string first $z -file]==0}      {set crashfile $z2}  \
    elseif {$n>1 && [string first $z -blocksize]==0} {set blocksize $z2}  \
    else   { error "Unrecognized option: $z" }
  }

  if {$crashfile eq ""} {
    error "Compulsory option -file missing"
  }

  set cfile [file join [pwd] $crashfile]

  set f [open crash.tcl w]
  puts $f "sqlite3_crashparams $crashdelay $cfile $blocksize"
  puts $f "set sqlite_pending_byte $::sqlite_pending_byte"
  puts $f "sqlite3 db test.db"

  # This block sets the cache size of the main database to 10
  # pages. This is done in case the build is configured to omit
  # "PRAGMA cache_size".
  puts $f {db eval {SELECT * FROM sqlite_master;}}

Changes to www/capi3ref.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
....
1718
1719
1720
1721
1722
1723
1724

1725
1726
1727
1728
1729
1730
1731
....
1736
1737
1738
1739
1740
1741
1742

1743
1744
1745
1746
1747
1748
1749
....
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
....
1769
1770
1771
1772
1773
1774
1775

1776

set rcsid {$Id: capi3ref.tcl,v 1.52 2007/02/20 15:21:05 drh Exp $}
source common.tcl
header {C/C++ Interface For SQLite Version 3}
puts {
<h2>C/C++ Interface For SQLite Version 3</h2>
}

proc api {name prototype desc {notused x}} {
  global apilist specialname
  if {$name==""} {
    regsub -all {sqlite3_[a-z0-9_]+\(} $prototype \
      {[lappend name [string trimright & (]]} x1
................................................................................
  incr i
}
#parray n_to_name
#parray n_to_idx
#parray name_to_idx
#parray sname
incr n -1

puts {<table width="100%" cellpadding="5"><tr>}
set nrow [expr {($n+2)/3}]
set i 0
for {set j 0} {$j<3} {incr j} {
  if {$j>0} {puts {<td width="10"></td>}}
  puts {<td valign="top">}
  set limit [expr {$i+$nrow}]
................................................................................
    puts "<li><a href=\"#$name\">$display</a></li>"
    incr i
  }
  puts {</ul></td>}
}
puts "</table>"
puts "<!-- $n entries.  $nrow rows in 3 columns -->"


proc resolve_name {ignore_list name} {
  global name_to_idx
  if {![info exists name_to_idx($name)] || [lsearch $ignore_list $name]>=0} {
    return $name
  } else {
    return "<a href=\"#$name\">$name</a>"
................................................................................

foreach name [lsort [array names name_to_idx]] {
  set i $name_to_idx($name)
  if {[info exists done($i)]} continue
  set done($i) 1
  foreach {namelist prototype desc} [lindex $apilist $i] break
  foreach name $namelist {
    puts "<a name=\"$name\">"
  }
  puts "<p><hr></p>"
  puts "<blockquote><pre>"
  regsub "^( *\n)+" $prototype {} p2
  regsub "(\n *)+\$" $p2 {} p3
  puts $p3
  puts "</pre></blockquote>"
................................................................................
  foreach x $specialname {
    regsub -all $x $d2 "\[resolve_name $name &\]" d2
  }
  regsub -all "\n( *\n)+" [subst $d2] "</p>\n\n<p>" d3
  puts "<p>$d3</p>"
}


footer $rcsid

|



|







 







>







 







>







 







|







 







>

>
1
2
3
4
5
6
7
8
9
10
11
12
....
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
....
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
....
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
....
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
set rcsid {$Id: capi3ref.tcl,v 1.53 2007/03/17 10:26:59 danielk1977 Exp $}
source common.tcl
header {C/C++ Interface For SQLite Version 3}
puts {
<h2 class=pdf_section>C/C++ Interface For SQLite Version 3</h2>
}

proc api {name prototype desc {notused x}} {
  global apilist specialname
  if {$name==""} {
    regsub -all {sqlite3_[a-z0-9_]+\(} $prototype \
      {[lappend name [string trimright & (]]} x1
................................................................................
  incr i
}
#parray n_to_name
#parray n_to_idx
#parray name_to_idx
#parray sname
incr n -1
puts "<DIV class=pdf_ignore>"
puts {<table width="100%" cellpadding="5"><tr>}
set nrow [expr {($n+2)/3}]
set i 0
for {set j 0} {$j<3} {incr j} {
  if {$j>0} {puts {<td width="10"></td>}}
  puts {<td valign="top">}
  set limit [expr {$i+$nrow}]
................................................................................
    puts "<li><a href=\"#$name\">$display</a></li>"
    incr i
  }
  puts {</ul></td>}
}
puts "</table>"
puts "<!-- $n entries.  $nrow rows in 3 columns -->"
puts "</DIV>"

proc resolve_name {ignore_list name} {
  global name_to_idx
  if {![info exists name_to_idx($name)] || [lsearch $ignore_list $name]>=0} {
    return $name
  } else {
    return "<a href=\"#$name\">$name</a>"
................................................................................

foreach name [lsort [array names name_to_idx]] {
  set i $name_to_idx($name)
  if {[info exists done($i)]} continue
  set done($i) 1
  foreach {namelist prototype desc} [lindex $apilist $i] break
  foreach name $namelist {
    puts "<a name=\"$name\"></a>"
  }
  puts "<p><hr></p>"
  puts "<blockquote><pre>"
  regsub "^( *\n)+" $prototype {} p2
  regsub "(\n *)+\$" $p2 {} p3
  puts $p3
  puts "</pre></blockquote>"
................................................................................
  foreach x $specialname {
    regsub -all $x $d2 "\[resolve_name $name &\]" d2
  }
  regsub -all "\n( *\n)+" [subst $d2] "</p>\n\n<p>" d3
  puts "<p>$d3</p>"
}

puts "<DIV class=pdf_ignore>"
footer $rcsid
puts "</DIV>"