Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Handle corrupt journal file headers correctly. (CVS 1674) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
46107da7eddbdda8b582e2ece2dc4122 |
User & Date: | danielk1977 2004-06-23 01:05:27.000 |
Context
2004-06-23
| ||
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) | |
00:23 | Add a comment to the output buffer allocation in sqlite3VdbeMemTranslate() (CVS 1673) (check-in: e2f7f18298 user: danielk1977 tags: trunk) | |
Changes
Changes to main.mk.
︙ | ︙ | |||
114 115 116 117 118 119 120 | # TESTSRC = \ $(TOP)/src/btree.c \ $(TOP)/src/func.c \ $(TOP)/src/os_mac.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ | < | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | # TESTSRC = \ $(TOP)/src/btree.c \ $(TOP)/src/func.c \ $(TOP)/src/os_mac.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ $(TOP)/src/pager.c \ $(TOP)/src/pragma.c \ $(TOP)/src/printf.c \ $(TOP)/src/test1.c \ $(TOP)/src/test2.c \ $(TOP)/src/test3.c \ $(TOP)/src/test4.c \ |
︙ | ︙ | |||
270 271 272 273 274 275 276 | grep '^case OP_' $(TOP)/src/vdbe.c | \ sed -e 's/://' | \ awk '{printf "#define %-30s %3d\n", $$2, ++cnt}' >>opcodes.h os_mac.o: $(TOP)/src/os_mac.c $(HDR) $(TCCX) -c $(TOP)/src/os_mac.c | < < < | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | grep '^case OP_' $(TOP)/src/vdbe.c | \ sed -e 's/://' | \ awk '{printf "#define %-30s %3d\n", $$2, ++cnt}' >>opcodes.h os_mac.o: $(TOP)/src/os_mac.c $(HDR) $(TCCX) -c $(TOP)/src/os_mac.c os_unix.o: $(TOP)/src/os_unix.c $(HDR) $(TCCX) -c $(TOP)/src/os_unix.c os_win.o: $(TOP)/src/os_win.c $(HDR) $(TCCX) -c $(TOP)/src/os_win.c parse.o: parse.c $(HDR) |
︙ | ︙ | |||
355 356 357 358 359 360 361 | $(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) testfixture$(EXE): $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC) $(TCCX) $(TCL_FLAGS) -DTCLSH=1 -DSQLITE_TEST=1 -o testfixture$(EXE) \ $(TESTSRC) $(TOP)/src/tclsqlite.c \ libsqlite3.a $(LIBTCL) $(THREADLIB) | | | | | 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | $(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) testfixture$(EXE): $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC) $(TCCX) $(TCL_FLAGS) -DTCLSH=1 -DSQLITE_TEST=1 -o testfixture$(EXE) \ $(TESTSRC) $(TOP)/src/tclsqlite.c \ libsqlite3.a $(LIBTCL) $(THREADLIB) crashtest: $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC) $(TOP)/src/os_test.c $(TCCX) $(TCL_FLAGS) -DOS_TEST=1 -DTCLSH=1 -DSQLITE_TEST=1 -o crashtest \ $(TESTSRC) $(TOP)/src/os_test.c $(TOP)/src/tclsqlite.c \ libsqlite3.a $(LIBTCL) $(THREADLIB) fulltest: testfixture$(EXE) sqlite3$(EXE) ./testfixture$(EXE) $(TOP)/test/all.test test: testfixture$(EXE) sqlite3$(EXE) ./testfixture$(EXE) $(TOP)/test/quick.test |
︙ | ︙ |
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.136 2004/06/23 01:05:27 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> |
︙ | ︙ | |||
788 789 790 791 792 793 794 | ** If the nRec value is 0xffffffff it means that nRec should be computed ** from the file size. This value is used when the user selects the ** no-sync option for the journal. A power failure could lead to corruption ** in this case. But for things like temporary table (which will be ** deleted when the power is restored) we don't care. ** ** If the file opened as the journal file is not a well-formed | | | | > | > > | 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 | ** If the nRec value is 0xffffffff it means that nRec should be computed ** from the file size. This value is used when the user selects the ** no-sync option for the journal. A power failure could lead to corruption ** in this case. But for things like temporary table (which will be ** deleted when the power is restored) we don't care. ** ** If the file opened as the journal file is not a well-formed ** journal file then all pages up to the first corrupted page are rolled ** back (or no pages if the journal header is corrupted). The journal file ** is then deleted and SQLITE_OK returned, just as if no corruption had ** been encountered. ** ** If an I/O or malloc() error occurs, the journal-file is not deleted ** and an error code is returned. */ static int pager_playback(Pager *pPager, int useJournalSize){ off_t szJ; /* Size of the journal file in bytes */ int nRec; /* Number of Records in the journal */ int i; /* Loop counter */ Pgno mxPg = 0; /* Size of the original file in pages */ unsigned char aMagic[8]; /* A buffer to hold the magic header */ |
︙ | ︙ | |||
827 828 829 830 831 832 833 | goto end_playback; } /* (1) Read the beginning of the journal and verify the magic string ** at the beginning of the journal. */ rc = sqlite3OsRead(&pPager->jfd, aMagic, sizeof(aMagic)); if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ | < | 830 831 832 833 834 835 836 837 838 839 840 841 842 843 | goto end_playback; } /* (1) Read the beginning of the journal and verify the magic string ** at the beginning of the journal. */ rc = sqlite3OsRead(&pPager->jfd, aMagic, sizeof(aMagic)); 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 ){ |
︙ | ︙ | |||
853 854 855 856 857 858 859 860 861 862 863 864 865 866 | goto end_playback; } /* (5) and (6): Check if a master journal file is specified. If one is ** specified, only proceed with the playback if it still exists. */ rc = read32bits(&pPager->jfd, &nMaster); if( rc ) goto end_playback; if( nMaster>0 ){ zMaster = sqliteMalloc(nMaster); if( !zMaster ){ rc = SQLITE_NOMEM; goto end_playback; } rc = sqlite3OsRead(&pPager->jfd, zMaster, nMaster); | > | 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 | goto end_playback; } /* (5) and (6): Check if a master journal file is specified. If one is ** specified, only proceed with the playback if it still exists. */ rc = read32bits(&pPager->jfd, &nMaster); if( rc ) goto end_playback; if( szJ < 24+nMaster ) goto end_playback; if( nMaster>0 ){ zMaster = sqliteMalloc(nMaster); if( !zMaster ){ rc = SQLITE_NOMEM; goto end_playback; } rc = sqlite3OsRead(&pPager->jfd, zMaster, nMaster); |
︙ | ︙ | |||
904 905 906 907 908 909 910 | ** occur during this process, ignore them. */ if( rc==SQLITE_OK ){ pager_delmaster(zMaster); } sqliteFree(zMaster); } | | < < < < < < < < | 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 | ** occur during this process, ignore them. */ if( rc==SQLITE_OK ){ pager_delmaster(zMaster); } sqliteFree(zMaster); } if( rc==SQLITE_OK ){ rc = pager_unwritelock(pPager); } return rc; } /* ** Playback the statement journal. |
︙ | ︙ |
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 | # 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.2 2004/06/23 01:05:27 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # This proc execs a seperate process that crashes midway through executing # the SQL script $sql on database test.db. # # Argument $crashdelay indicates the number of file closes or syncs to wait # before crashing. When a crash occurs a random subset of unsynced writes # are written into any open files. proc crashsql {crashdelay sql} { set f [open crash.tcl w] puts $f "sqlite3_crashseed $crashdelay" puts $f "sqlite3 db test.db" puts $f "db eval {" puts $f "$sql" puts $f "}" close $f exec [file join . crashtest] crash.tcl } # 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 # 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 # database-sync # crash-1.5: Ensure the database is in the same state as after crash-1.1. # 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); } } {} do_test crash-1.2 { catch { crashsql 1 { DELETE FROM abc WHERE a = 1; } } msg set msg } {child process exited abnormally} do_test crash-1.3 { catchsql { SELECT * FROM abc; } } {0 {1 2 3 4 5 6}} do_test crash-1.4 { catch { crashsql 1 { DELETE FROM abc WHERE a = 1; } } msg set msg } {child process exited abnormally} do_test crash-1.5 { catchsql { SELECT * FROM abc; } } {0 {1 2 3 4 5 6}} finish_test |
Changes to test/func.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 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. The # focus of this file is testing built-in functions. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing built-in functions. # # $Id: func.test,v 1.25 2004/06/23 01:05:27 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a table to work with. # do_test func-0.0 { |
︙ | ︙ | |||
388 389 390 391 392 393 394 395 396 397 398 399 400 401 | # a special user-defined function only available in test builds, # test_auxdata(). Function test_auxdata() takes any number of arguments. do_test func-13.1 { execsql { SELECT test_auxdata('hello world'); } } {0} do_test func-13.2 { execsql { CREATE TABLE t4(a, b); INSERT INTO t4 VALUES('abc', 'def'); INSERT INTO t4 VALUES('ghi', 'jkl'); } } {} | > | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | # a special user-defined function only available in test builds, # test_auxdata(). Function test_auxdata() takes any number of arguments. do_test func-13.1 { execsql { SELECT test_auxdata('hello world'); } } {0} do_test func-13.2 { execsql { CREATE TABLE t4(a, b); INSERT INTO t4 VALUES('abc', 'def'); INSERT INTO t4 VALUES('ghi', 'jkl'); } } {} |
︙ | ︙ | |||
429 430 431 432 433 434 435 436 | sqlite3_bind_text $STMT 1 hello -1 set res [list] while { "SQLITE_ROW"==[sqlite3_step $STMT] } { lappend res [sqlite3_column_text $STMT 0] } lappend res [sqlite3_finalize $STMT] } {{0 0} {1 0} SQLITE_OK} | < | 430 431 432 433 434 435 436 437 438 | sqlite3_bind_text $STMT 1 hello -1 set res [list] while { "SQLITE_ROW"==[sqlite3_step $STMT] } { lappend res [sqlite3_column_text $STMT 0] } lappend res [sqlite3_finalize $STMT] } {{0 0} {1 0} SQLITE_OK} finish_test |