Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Test cases to verify recovery after a crash. (CVS 1675) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
41868d79ac5b3c496c4d87ca6b4ee7c1 |
User & Date: | danielk1977 2004-06-23 10:43:10.000 |
Context
2004-06-23
| ||
12:15 | Add some tests for user functions that prefer various text encodings. (CVS 1676) (check-in: db6bab5748 user: danielk1977 tags: trunk) | |
10:43 | Test cases to verify recovery after a crash. (CVS 1675) (check-in: 41868d79ac user: danielk1977 tags: trunk) | |
01:05 | Handle corrupt journal file headers correctly. (CVS 1674) (check-in: 46107da7ed user: danielk1977 tags: trunk) | |
Changes
Changes to src/os_test.c.
︙ | ︙ | |||
56 57 58 59 60 61 62 | #undef sqlite3OsCheckReservedLock #define BLOCKSIZE 512 #define BLOCK_OFFSET(x) ((x) * BLOCKSIZE) /* | | > > > > > > > | | > | < < < < < < < < < < | > > | > | < > | | | > > > > > > > | > > > > | > | 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 | #undef sqlite3OsCheckReservedLock #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 ** a file that SQLite will call sqlite3OsSync() on. Each time this happens ** iCrashDelay is decremented. If iCrashDelay is zero after being ** decremented, a "crash" occurs during the sync() operation. ** ** In other words, a crash occurs the iCrashDelay'th time zCrashFile is ** synced. */ static int iCrashDelay = 0; char zCrashFile[256]; /* ** Set the value of the two crash parameters. */ void sqlite3SetCrashParams(int iDelay, char const *zFile){ sqlite3OsEnterMutex(); assert( strlen(zFile)<256 ); 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; int n; sqlite3OsEnterMutex(); n = strlen(zCrashFile); if( zCrashFile[n-1]=='*' ){ n--; }else if( strlen(zPath)>n ){ n = strlen(zPath); } r = ( iCrashDelay>0 && !strncmp(zPath, zCrashFile, n) && --iCrashDelay==0 )?1:0; sqlite3OsLeaveMutex(); return r; } static OsTestFile *pAllFiles = 0; /* ** Initialise the os_test.c specific fields of pFile. */ static void initFile(OsFile *id, char const *zName){ |
︙ | ︙ | |||
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 | if( rc!=SQLITE_OK ) return rc; } } return SQLITE_OK; } /* ** Write the cache of pFile to disk. If crash is non-zero, randomly ** skip blocks when writing. The cache is deleted before returning. */ static int writeCache2(OsTestFile *pFile, int crash){ int i; int nMax = pFile->nMaxWrite; off_t offset; int rc = SQLITE_OK; offset = osTell(pFile); for(i=0; i<pFile->nBlk; i++){ u8 *p = pFile->apBlk[i]; if( p ){ int skip = 0; if( crash ){ char random; sqlite3Randomness(1, &random); if( random & 0x01 ){ skip = 1; | > > < > | < < | < > < | 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 226 227 228 | if( rc!=SQLITE_OK ) return rc; } } return SQLITE_OK; } /* #define TRACE_WRITECACHE */ /* ** Write the cache of pFile to disk. If crash is non-zero, randomly ** skip blocks when writing. The cache is deleted before returning. */ static int writeCache2(OsTestFile *pFile, int crash){ int i; int nMax = pFile->nMaxWrite; off_t offset; int rc = SQLITE_OK; offset = osTell(pFile); for(i=0; i<pFile->nBlk; i++){ u8 *p = pFile->apBlk[i]; if( p ){ int skip = 0; if( crash ){ char random; sqlite3Randomness(1, &random); if( random & 0x01 ){ skip = 1; #ifdef TRACE_WRITECACHE printf("Not writing block %d of %s\n", i, pFile->zName); }else{ printf("Writing block %d of %s\n", i, pFile->zName); #endif } } if( rc==SQLITE_OK ){ rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i)); } if( rc==SQLITE_OK && !skip ){ int len = BLOCKSIZE; if( BLOCK_OFFSET(i+1)>nMax ){ len = nMax-BLOCK_OFFSET(i); |
︙ | ︙ | |||
231 232 233 234 235 236 237 | return rc; } /* ** Write the cache to disk. */ static int writeCache(OsTestFile *pFile){ | > | | < | > > > | | | | | < | | > > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | return rc; } /* ** Write the cache to disk. */ static int writeCache(OsTestFile *pFile){ if( pFile->apBlk ){ int c = crashRequired(pFile->zName); if( c ){ OsTestFile *p; #ifdef TRACE_WRITECACHE printf("Crash during sync of %s\n", pFile->zName); #endif for(p=pAllFiles; p; p=p->pNext){ writeCache2(p, 1); } exit(-1); }else{ return writeCache2(pFile, 0); } } return SQLITE_OK; } /* ** Close the file. */ int sqlite3OsClose(OsFile *id){ if( !(*id) ) return SQLITE_OK; |
︙ | ︙ |
Changes to src/os_test.h.
︙ | ︙ | |||
30 31 32 33 34 35 36 | int nBlk; /* Size of apBlock. */ int nMaxWrite; /* Largest offset written to. */ char *zName; /* File name */ OsRealFile fd; OsTestFile *pNext; }; | | | 30 31 32 33 34 35 36 37 38 39 | int nBlk; /* Size of apBlock. */ int nMaxWrite; /* Largest offset written to. */ char *zName; /* File name */ OsRealFile fd; OsTestFile *pNext; }; void sqlite3SetCrashParams(int iDelay, char const *zFile); #endif /* _SQLITE_OS_UNIX_H_ */ |
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** 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. ** | | | 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.137 2004/06/23 10:43:10 danielk1977 Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | sqliteFree( pPager->aInJournal ); pPager->aInJournal = 0; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->inJournal = 0; pPg->dirty = 0; pPg->needSync = 0; } }else{ assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); } sqlite3OsUnlock(&pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; return SQLITE_OK; } /* ** Compute and return a checksum for the page of data. ** ** This is not a real checksum. It is really just the sum of the | > > > > | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 | sqliteFree( pPager->aInJournal ); pPager->aInJournal = 0; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->inJournal = 0; pPg->dirty = 0; pPg->needSync = 0; } pPager->dirtyCache = 0; pPager->nMaster = 0; pPager->nRec = 0; }else{ assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); } sqlite3OsUnlock(&pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; pPager->origDbSize = 0; return SQLITE_OK; } /* ** Compute and return a checksum for the page of data. ** ** This is not a real checksum. It is really just the sum of the |
︙ | ︙ | |||
504 505 506 507 508 509 510 | ** ** FIX ME: Consider adding every 200th (or so) byte of the data to the ** checksum. That way if a single page spans 3 or more disk sectors and ** only the middle sector is corrupt, we will still have a reasonable ** chance of failing the checksum and thus detecting the problem. */ static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){ | | > > > > > | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | ** ** FIX ME: Consider adding every 200th (or so) byte of the data to the ** checksum. That way if a single page spans 3 or more disk sectors and ** only the middle sector is corrupt, we will still have a reasonable ** chance of failing the checksum and thus detecting the problem. */ static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){ u32 cksum = pPager->cksumInit; int i = pPager->pageSize-200; while( i>0 ){ cksum += aData[i]; i -= 200; } return cksum; } /* ** Read a single page from the journal file opened on file descriptor ** jfd. Playback this one page. ** |
︙ | ︙ | |||
836 837 838 839 840 841 842 | if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ goto end_playback; } /* (2) Read the number of pages stored in the journal. */ rc = read32bits(&pPager->jfd, (u32*)&nRec); if( rc ) goto end_playback; | | > > | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 | if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ goto end_playback; } /* (2) Read the number of pages stored in the journal. */ rc = read32bits(&pPager->jfd, (u32*)&nRec); if( rc ) goto end_playback; if( nRec==0xffffffff || useJournalSize || nRec>(szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager) ){ nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager); } /* (3) Read the initial value for the sanity checksum */ rc = read32bits(&pPager->jfd, &pPager->cksumInit); if( rc ) goto end_playback; |
︙ | ︙ | |||
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 | if( pPager->noSync ) pPager->needSync = 0; }else{ pPager->noSync = 1; mxPage = -mxPage; } if( mxPage>10 ){ pPager->mxPage = mxPage; } } /* ** Adjust the robustness of the database to damage due to OS crashes ** or power failures by changing the number of syncs()s when writing ** the rollback journal. There are three levels: | > > | 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 | if( pPager->noSync ) pPager->needSync = 0; }else{ pPager->noSync = 1; mxPage = -mxPage; } if( mxPage>10 ){ pPager->mxPage = mxPage; }else{ pPager->mxPage = 10; } } /* ** Adjust the robustness of the database to damage due to OS crashes ** or power failures by changing the number of syncs()s when writing ** the rollback journal. There are three levels: |
︙ | ︙ | |||
2405 2406 2407 2408 2409 2410 2411 | ** if there have been no changes to the database file. */ assert( pPager->needSync==0 ); rc = pager_unwritelock(pPager); pPager->dbSize = -1; return rc; } assert( pPager->journalOpen ); | < < < < < < < < < < < < < | 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 | ** if there have been no changes to the database file. */ assert( pPager->needSync==0 ); rc = pager_unwritelock(pPager); pPager->dbSize = -1; return rc; } assert( pPager->journalOpen ); rc = sqlite3pager_sync(pPager, 0); if( rc!=SQLITE_OK ){ goto commit_abort; } rc = pager_unwritelock(pPager); pPager->dbSize = -1; return rc; |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the printf() interface to SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 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. ** ************************************************************************* ** Code for testing the printf() interface to SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test1.c,v 1.84 2004/06/23 10:43:11 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include "os.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
980 981 982 983 984 985 986 | bad_args: Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0); return TCL_ERROR; } | | | | | | | | 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 | bad_args: Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0); return TCL_ERROR; } static int sqlite3_crashparams( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifdef OS_TEST int delay; if( objc!=3 ) goto bad_args; if( Tcl_GetIntFromObj(interp, objv[1], &delay) ) return TCL_ERROR; sqlite3SetCrashParams(delay, Tcl_GetString(objv[2])); #endif return TCL_OK; #ifdef OS_TEST bad_args: Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), "<delay> <filename>", 0); return TCL_ERROR; #endif } /* ** Usage: breakpoint |
︙ | ︙ | |||
2064 2065 2066 2067 2068 2069 2070 | /* Functions from os.h */ { "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 }, { "sqlite3OsClose", test_sqlite3OsClose, 0 }, { "sqlite3OsLock", test_sqlite3OsLock, 0 }, { "sqlite3OsUnlock", test_sqlite3OsUnlock, 0 }, { "add_test_collate", test_collate, 0 }, | | | 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 | /* Functions from os.h */ { "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 }, { "sqlite3OsClose", test_sqlite3OsClose, 0 }, { "sqlite3OsLock", test_sqlite3OsLock, 0 }, { "sqlite3OsUnlock", test_sqlite3OsUnlock, 0 }, { "add_test_collate", test_collate, 0 }, { "sqlite3_crashparams", sqlite3_crashparams, 0 }, }; int i; extern int sqlite3_os_trace; for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); |
︙ | ︙ |
Changes to test/crash.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 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. # #*********************************************************************** # This file implements regression tests for SQLite library. # | | > > > | | | > > > > > > > | > | > > | > > > > > > > > > > > > > > > > > | | > > > > > > > | < | | | > | > | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > | > > > > | > > > > > > > > > > > > > | > > > > > > > > | > > > | > > > | > > > > > > | | < < > > > > > > > > > > > | > > > > > | > | > > | > > > > > > > > > > > > > | > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 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 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 117 118 119 120 121 122 123 124 125 126 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 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 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 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 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | # 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. # #*********************************************************************** # This file implements regression tests for SQLite library. # # $Id: crash.test,v 1.3 2004/06/23 10:43:15 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set repeats 100 # set repeats 5 # This proc execs a seperate process that crashes midway through executing # the SQL script $sql on database test.db. # # The crash occurs during a sync() of file $crashfile. When the crash # occurs a random subset of all unsynced writes made by the process are # written into the files on disk. Argument $crashdelay indicates the # number of file syncs to wait before crashing. # # 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} { set cfile [file join [pwd] $crashfile] set f [open crash.tcl w] puts $f "sqlite3_crashparams $crashdelay $cfile" puts $f "sqlite3 db test.db" puts $f "db eval {pragma full_synchronous = 1}" puts $f "db eval {" puts $f "$sql" puts $f "}" close $f set r [catch { exec [file join . crashtest] crash.tcl } msg] lappend r $msg } # The following procedure computes a "signature" for table "abc". If # abc changes in any way, the signature should change. proc signature {} { return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc}] } proc signature2 {} { return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc2}] } # Use a small pager-cache for these tests. do_test crash-0.1 { execsql { pragma default_cache_size = 10 } } {} #-------------------------------------------------------------------------- # Simple crash test: # # crash-1.1: Create a database with a table with two rows. # crash-1.2: Run a 'DELETE FROM abc WHERE a = 1' that crashes during # the first journal-sync. # crash-1.3: Ensure the database is in the same state as after crash-1.1. # crash-1.4: Run a 'DELETE FROM abc WHERE a = 1' that crashes during # the first database-sync. # crash-1.5: Ensure the database is in the same state as after crash-1.1. # # Tests 1.6 through 1.9 are the same as 1.2 through 1.5, except the crash # is requested on the second sync of each file. This doesn't happen in # such a small test case, so these tests are just to verify that the # test infrastructure operates as expected. # do_test crash-1.1 { execsql { CREATE TABLE abc(a, b, c); 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}} # exit 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; } } {0 {}} do_test crash-1.7 { catchsql { SELECT * FROM abc; } } {0 {4 5 6}} do_test crash-1.8 { crashsql 2 test.db { DELETE FROM abc WHERE a = 4; } } {0 {}} do_test crash-1.9 { catchsql { SELECT * FROM abc; } } {0 {}} #-------------------------------------------------------------------------- # The following tests test recovery when both the database file and the the # journal file contain corrupt data. This can happen after pages are # written to the database file before a transaction is committed due to # cache-pressure. # # crash-2.1: Insert 18 pages of data into the database. # crash-2.2: Check the database file size looks ok. # crash-2.3: Delete 15 or so pages (with a 10 page page-cache), then crash. # crash-2.4: Ensure the database is in the same state as after crash-2.1. # # Test cases crash-2.5 and crash-2.6 check that the database is OK if the # crash occurs during the main database file sync. But this isn't really # different from the crash-1.* cases. # do_test crash-2.1 { execsql { BEGIN } for {set n 0} {$n < 1000} {incr n} { execsql "INSERT INTO abc VALUES($n, [expr 2*$n], [expr 3*$n])" } execsql { COMMIT } 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 } {19} 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 #-------------------------------------------------------------------------- # The crash-3.* test cases are essentially the same test as test case # crash-2.*, but with a more complicated data set. # # The test is repeated a few times with different seeds for the random # number generator in the crashing executable. Because there is no way to # seed the random number generator directly, some SQL is added to the test # case to 'use up' a different quantity random numbers before the test SQL # is executed. # # Make sure the file is much bigger than the pager-cache (10 pages). This # ensures that cache-spills happen regularly. do_test crash-3.0 { execsql { INSERT INTO abc SELECT * FROM abc; INSERT INTO abc SELECT * FROM abc; INSERT INTO abc SELECT * FROM abc; INSERT INTO abc SELECT * FROM abc; INSERT INTO abc SELECT * FROM abc; } expr [file size test.db] / 1024 } {554} 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}} do_test crash-3.$i.2 { signature } $sig } #-------------------------------------------------------------------------- # The following test cases - crash-4.* - test the correct recovery of the # database when a crash occurs during a multi-file transaction. # # crash-4.1.*: Test recovery when crash occurs during sync() of the # main database journal file. # crash-4.2.*: Test recovery when crash occurs during sync() of an # attached database journal file. # crash-4.3.*: Test recovery when crash occurs during sync() of the master # journal file. # do_test crash-4.0 { file delete -force test2.db file delete -force test2.db-journal sqlite3 db2 test2.db execsql {pragma default_cache_size = 10} db2 db2 close execsql { ATTACH 'test2.db' AS aux; CREATE TABLE aux.abc2 AS SELECT 2*a as a, 2*b as b, 2*c as c FROM abc; } expr [file size test2.db] / 1024 } {559} for {set i 1} {$i < $repeats} {incr i} { set sig [signature] set sig2 [signature2] do_test crash-4.1.$i.1 { crashsql [expr $i%5 + 1] 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; COMMIT; " } {1 {child process exited abnormally}} do_test crash-4.1.$i.2 { signature } $sig do_test crash-4.1.$i.3 { signature2 } $sig2 } for {set i 1} {$i < $repeats} {incr i} { set sig [signature] set sig2 [signature2] do_test crash-4.2.$i.1 { crashsql [expr $i%5 + 1] 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; COMMIT; " } {1 {child process exited abnormally}} do_test crash-4.2.$i.2 { signature } $sig do_test crash-4.2.$i.3 { 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; COMMIT; " } {1 {child process exited abnormally}} do_test crash-4.3.$i.2 { signature } $sig do_test crash-4.3.$i.3 { signature2 } $sig2 } finish_test |