SQLite

Check-in [b9170f2903]
Login

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

Overview
Comment:Modify the code for reading hot-journal files so that it can handle journals generated by versions 3.5.7 and earlier.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: b9170f2903c480bca2bdc986e98aaeadfdb9ad2b
User & Date: dan 2010-08-19 15:11:34.000
Context
2010-08-19
15:12
Merge two leaves. (check-in: b03091fc35 user: dan tags: trunk)
15:11
Modify the code for reading hot-journal files so that it can handle journals generated by versions 3.5.7 and earlier. (check-in: b9170f2903 user: dan tags: trunk)
11:05
Add new test script backcompat.test, for testing database/journal/wal file compatibility against previous versions. (check-in: 8804f4989d user: dan tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
1504
1505
1506
1507
1508
1509
1510








1511
1512
1513
1514
1515
1516
1517

    /* Read the page-size and sector-size journal header fields. */
    if( SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+20, &iSectorSize))
     || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+24, &iPageSize))
    ){
      return rc;
    }









    /* Check that the values read from the page-size and sector-size fields
    ** are within range. To be 'in range', both values need to be a power
    ** of two greater than or equal to 512 or 32, and not greater than their 
    ** respective compile time maximum limits.
    */
    if( iPageSize<512                  || iSectorSize<32







>
>
>
>
>
>
>
>







1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525

    /* Read the page-size and sector-size journal header fields. */
    if( SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+20, &iSectorSize))
     || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+24, &iPageSize))
    ){
      return rc;
    }

    /* Versions of SQLite prior to 3.5.8 set the page-size field of the
    ** journal header to zero. In this case, assume that the Pager.pageSize
    ** variable is already set to the correct page size.
    */
    if( iPageSize==0 ){
      iPageSize = pPager->pageSize;
    }

    /* Check that the values read from the page-size and sector-size fields
    ** are within range. To be 'in range', both values need to be a power
    ** of two greater than or equal to 512 or 32, and not greater than their 
    ** respective compile time maximum limits.
    */
    if( iPageSize<512                  || iSectorSize<32
Changes to test/backcompat.test.
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
# for documentation of the available commands.
#

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


# Search for binaries to test against. Any executable files that match
# our naming convention are assumed to be testfixture binaries to test
# against.
#
set binaries [list]
set pattern "[file tail [info nameofexec]]?*"
foreach file [glob $pattern] {
  if {[file executable $file]} {lappend binaries $file}
}
if {[llength $binaries]==0} {
  puts "WARNING: No binaries to test against. No tests have been run."
  finish_test
  return
}
proc get_version {binary} {
  set chan [launch_testfixture $binary]
  set v [testfixture $chan { sqlite3 -version }]
  close $chan
  set v
}
foreach bin $binaries {
  puts "Testing against $bin - version [get_version $bin]"
}


#set binaries testfixture



proc do_backcompat_test {rv binary script} {

  if { $rv } {
    proc code1 {tcl} { testfixture $::bc_chan $tcl }
    proc code2 {tcl} { uplevel #0 $tcl }


  } else {
    proc code1 {tcl} { uplevel #0 $tcl }

    proc code2 {tcl} { testfixture $::bc_chan $tcl }
  }

  proc sql1 sql { code1 [list db eval $sql] }
  proc sql2 sql { code2 [list db eval $sql] }

  file delete -force test.db

  set ::bc_chan [launch_testfixture $binary]
  code1 { sqlite3 db test.db }
  code2 { sqlite3 db test.db }

  uplevel $script

  catch { code1 { db close } }
  catch { code2 { db close } }
  catch { close $::bc_chan }

}

array set ::incompatible [list]
proc do_allbackcompat_test {script} {

  foreach bin $::binaries {
    set nErr [set_test_counter errors]
    foreach dir {0 1} {

      set ::bcname ".$dir.[string map {testfixture {}} $bin]."

      rename do_test _do_test
      proc do_test {nm sql res} {
        set nm [regsub {\.} $nm $::bcname]
        uplevel [list _do_test $nm $sql $res]
      }

      do_backcompat_test $dir $bin $script

      rename do_test {}
      rename _do_test do_test
    }
    if { $nErr < [set_test_counter errors] } {
      set ::incompatible([get_version $bin]) 1
    }







>






|


















>
|
>

>
|


<

>
>


>
|





<
<
<







|
>









|







|







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
# for documentation of the available commands.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
db close

# Search for binaries to test against. Any executable files that match
# our naming convention are assumed to be testfixture binaries to test
# against.
#
set binaries [list]
set pattern "[file tail [info nameofexec]]*"
foreach file [glob $pattern] {
  if {[file executable $file]} {lappend binaries $file}
}
if {[llength $binaries]==0} {
  puts "WARNING: No binaries to test against. No tests have been run."
  finish_test
  return
}
proc get_version {binary} {
  set chan [launch_testfixture $binary]
  set v [testfixture $chan { sqlite3 -version }]
  close $chan
  set v
}
foreach bin $binaries {
  puts "Testing against $bin - version [get_version $bin]"
}

proc do_backcompat_test {rv bin1 bin2 script} {

  file delete -force test.db

  if {$bin1 != ""} { set ::bc_chan1 [launch_testfixture $bin1] }
  set ::bc_chan2 [launch_testfixture $bin2]

  if { $rv } {

    proc code2 {tcl} { uplevel #0 $tcl }
    if {$bin1 != ""} { proc code2 {tcl} { testfixture $::bc_chan1 $tcl } }
    proc code1 {tcl} { testfixture $::bc_chan2 $tcl }
  } else {
    proc code1 {tcl} { uplevel #0 $tcl }
    if {$bin1 != ""} { proc code1 {tcl} { testfixture $::bc_chan1 $tcl } }
    proc code2 {tcl} { testfixture $::bc_chan2 $tcl }
  }

  proc sql1 sql { code1 [list db eval $sql] }
  proc sql2 sql { code2 [list db eval $sql] }




  code1 { sqlite3 db test.db }
  code2 { sqlite3 db test.db }

  uplevel $script

  catch { code1 { db close } }
  catch { code2 { db close } }
  catch { close $::bc_chan2 }
  catch { close $::bc_chan1 }
}

array set ::incompatible [list]
proc do_allbackcompat_test {script} {

  foreach bin $::binaries {
    set nErr [set_test_counter errors]
    foreach dir {0 1} {

      set ::bcname ".[string map {testfixture {}} $bin].$dir."

      rename do_test _do_test
      proc do_test {nm sql res} {
        set nm [regsub {\.} $nm $::bcname]
        uplevel [list _do_test $nm $sql $res]
      }

      do_backcompat_test $dir {} $bin $script

      rename do_test {}
      rename _do_test do_test
    }
    if { $nErr < [set_test_counter errors] } {
      set ::incompatible([get_version $bin]) 1
    }
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
  do_test backcompat-1.1.4 { sql1 { SELECT * FROM t1; } } {abc def ghi jkl}
  do_test backcompat-1.1.5 { sql1 { PRAGMA integrity_check } } {ok}
  do_test backcompat-1.1.6 { sql2 { PRAGMA integrity_check } } {ok}

  # Test that one version can roll back a hot-journal file left in the
  # file-system by the other version.
  #





  do_test backcompat-1.2.1 { sql1 {
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t1 VALUES(randomblob(400), randomblob(400));
      INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
      INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
      INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
      INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
    COMMIT;
  } } {}
  set cksum1 [sql1 {SELECT md5sum(a), md5sum(b) FROM t1}]
  set cksum2 [sql2 {SELECT md5sum(a), md5sum(b) FROM t1}]
  do_test backcompat-1.2.2 [list string compare $cksum1 $cksum2] 0

  do_test backcompat-1.2.3 { sql1 {
    BEGIN;
      UPDATE t1 SET a = randomblob(500);
  } } {}
  set data [read_file_system]




  do_test backcompat-1.2.4 { sql1 { COMMIT } } {}

  set same [expr {[sql2 {SELECT md5sum(a), md5sum(b) FROM t1}] == $cksum2}]
  do_test backcompat-1.2.5 [list set {} $same] 0



  write_file_system $data



  set same [expr {[sql2 {SELECT md5sum(a), md5sum(b) FROM t1}] == $cksum2}]
  do_test backcompat-1.2.6 [list set {} $same] 1

  do_test backcompat-1.2.7 { sql2 { PRAGMA integrity_check } } {ok}
  do_test backcompat-1.2.8 { sql2 { PRAGMA integrity_check } } {ok}
}

foreach k [lsort [array names ::incompatible]] {
  puts "ERROR: Detected incompatibility with version $k"
}

finish_test







>
>
>
>
>



















>
>
>
>





>
>

>
>
>



|








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
  do_test backcompat-1.1.4 { sql1 { SELECT * FROM t1; } } {abc def ghi jkl}
  do_test backcompat-1.1.5 { sql1 { PRAGMA integrity_check } } {ok}
  do_test backcompat-1.1.6 { sql2 { PRAGMA integrity_check } } {ok}

  # Test that one version can roll back a hot-journal file left in the
  # file-system by the other version.
  #
  # Each test case is named "backcompat-1.X...", where X is either 0 or
  # 1. If it is 0, then the current version creates a journal file that
  # the old versions try to read. Otherwise, if X is 1, then the old version
  # creates the journal file and we try to read it with the current version.
  #
  do_test backcompat-1.2.1 { sql1 {
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t1 VALUES(randomblob(400), randomblob(400));
      INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
      INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
      INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
      INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
    COMMIT;
  } } {}
  set cksum1 [sql1 {SELECT md5sum(a), md5sum(b) FROM t1}]
  set cksum2 [sql2 {SELECT md5sum(a), md5sum(b) FROM t1}]
  do_test backcompat-1.2.2 [list string compare $cksum1 $cksum2] 0

  do_test backcompat-1.2.3 { sql1 {
    BEGIN;
      UPDATE t1 SET a = randomblob(500);
  } } {}
  set data [read_file_system]

  set f "test.db-journal[incr x]"
  file copy -force test.db-journal $f

  do_test backcompat-1.2.4 { sql1 { COMMIT } } {}

  set same [expr {[sql2 {SELECT md5sum(a), md5sum(b) FROM t1}] == $cksum2}]
  do_test backcompat-1.2.5 [list set {} $same] 0

  code1 { db close }
  code2 { db close }
  write_file_system $data
  code1 { sqlite3 db test.db }
  code2 { sqlite3 db test.db }

  set same [expr {[sql2 {SELECT md5sum(a), md5sum(b) FROM t1}] == $cksum2}]
  do_test backcompat-1.2.6 [list set {} $same] 1

  do_test backcompat-1.2.7 { sql1 { PRAGMA integrity_check } } {ok}
  do_test backcompat-1.2.8 { sql2 { PRAGMA integrity_check } } {ok}
}

foreach k [lsort [array names ::incompatible]] {
  puts "ERROR: Detected incompatibility with version $k"
}

finish_test