SQLite

Check-in [9f6ea1de5a]
Login

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

Overview
Comment:Merge trunk updates with experimental branch. Also add tests to journal2.test.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: 9f6ea1de5abab0ca28688e257ddf03c66413cf6e
User & Date: dan 2010-06-17 10:52:07.000
Original Comment: Merge trunk updates with experimental branch.
Context
2010-06-17
11:36
Fix bug in journal2.test. (check-in: c1e04f1d4e user: dan tags: experimental)
10:52
Merge trunk updates with experimental branch. Also add tests to journal2.test. (check-in: 9f6ea1de5a user: dan tags: experimental)
10:42
Do not delete the journal file in "PRAGMA journal_mode" commands. This fixes [fc62af4523]. (check-in: 1ec74591a9 user: dan tags: trunk)
06:19
Merge fix [f80c3f922a] with experimental changes. (check-in: 20133e9ca9 user: dan tags: experimental)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
    */
    if( isOpen(pPager->jfd) && eMode!=PAGER_JOURNALMODE_WAL ){
      sqlite3OsClose(pPager->jfd);
    }

    /* Change the journal mode. */
    pPager->journalMode = (u8)eMode;

    /* When transistioning from TRUNCATE or PERSIST to any other journal
    ** mode (and we are not in locking_mode=EXCLUSIVE) then delete the
    ** journal file.
    */
    assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
    assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
    assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 );
    assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 );
    assert( (PAGER_JOURNALMODE_OFF & 5)!=1 );
    assert( (PAGER_JOURNALMODE_WAL & 5)!=1 );
    if( (eOld & 5)==1 && (eMode & 5)!=1 && !pPager->exclusiveMode ){
      sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
    }
  }

  /* Return the new journal mode */
  return (int)pPager->journalMode;
}

/*







<
<
<
<
<
<
<
<
<
<
<
<
<
<







5894
5895
5896
5897
5898
5899
5900














5901
5902
5903
5904
5905
5906
5907
    */
    if( isOpen(pPager->jfd) && eMode!=PAGER_JOURNALMODE_WAL ){
      sqlite3OsClose(pPager->jfd);
    }

    /* Change the journal mode. */
    pPager->journalMode = (u8)eMode;














  }

  /* Return the new journal mode */
  return (int)pPager->journalMode;
}

/*
Changes to test/journal2.test.
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
# Set up a hook so that each time a journal file is opened, closed or
# deleted, the method name ("xOpen", "xClose" or "xDelete") and the final
# segment of the journal file-name (i.e. "test.db-journal") are appended to
# global list variable $::oplog.
#
tvfs filter {xOpen xClose xDelete}
tvfs script journal_op_catcher

proc journal_op_catcher {method filename args} {

  # If global variable ::tvfs_error_on_write is defined, then return an
  # IO error to every attempt to modify the file-system. Otherwise, return
  # SQLITE_OK.
  #
  if {[info exists ::tvfs_error_on_write]} {
    if {$method == "xDelete" || $method == "xWrite" || $method == "xTruncate"} {
      return SQLITE_IOERR 
    }
    return SQLITE_OK
  }


  if {[string match *journal* $filename]==0} return


  set f [file tail $filename]





  lappend ::oplog $method $f





  if {[info exists ::open_journals($f)]==0} { set ::open_journals($f) 0 }
  switch -- $method {
    xOpen {
      incr ::open_journals($f) +1
    }
    xClose {
      incr ::open_journals($f) -1
    }
    xDelete {
      if {$::open_journals($f)>0} { return SQLITE_IOERR }
    }
  }

  return
}


do_test journal2-1.1 {
  set ::oplog [list]
  sqlite3 db test.db
  execsql { CREATE TABLE t1(a, b) }







<







|





>
|
>
|

>
>
>
>
>


>
>
>
>


<
|
<
<
|
<
<
|
|
|
<
|







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
# Set up a hook so that each time a journal file is opened, closed or
# deleted, the method name ("xOpen", "xClose" or "xDelete") and the final
# segment of the journal file-name (i.e. "test.db-journal") are appended to
# global list variable $::oplog.
#
tvfs filter {xOpen xClose xDelete}
tvfs script journal_op_catcher

proc journal_op_catcher {method filename args} {

  # If global variable ::tvfs_error_on_write is defined, then return an
  # IO error to every attempt to modify the file-system. Otherwise, return
  # SQLITE_OK.
  #
  if {[info exists ::tvfs_error_on_write]} {
    if {[lsearch {xDelete xWrite xTruncate} $method]>=0} {
      return SQLITE_IOERR 
    }
    return SQLITE_OK
  }

  # The rest of this command only deals with xOpen(), xClose() and xDelete()
  # operations on journal files. If this invocation does not represent such
  # an operation, return with no further ado.
  #
  set f [file tail $filename]
  if {[string match *journal $f]==0} return
  if {[lsearch {xOpen xDelete xClose} $method]<0} return

  # Append a record of this operation to global list variable $::oplog.
  #
  lappend ::oplog $method $f

  # If this is an attempt to delete a journal file for which there exists
  # one ore more open handles, return an error. The code in test_vfs.c
  # will not invoke the xDelete method of the "real" VFS in this case.
  #
  if {[info exists ::open_journals($f)]==0} { set ::open_journals($f) 0 }
  switch -- $method {

    xOpen   { incr ::open_journals($f) +1 }


    xClose  { incr ::open_journals($f) -1 }


    xDelete { if {$::open_journals($f)>0} { puts EEE;return SQLITE_IOERR } }
  }


  return ""
}


do_test journal2-1.1 {
  set ::oplog [list]
  sqlite3 db test.db
  execsql { CREATE TABLE t1(a, b) }
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
do_test journal2-1.7 { execsql { SELECT * FROM t1 } } {1 2 3 4}
do_test journal2-1.8 {
  execsql { PRAGMA journal_mode = truncate } db2
  execsql { INSERT INTO t1 VALUES(5, 6)  } db2
} {}
do_test journal2-1.9 { execsql { SELECT * FROM t1 } } {1 2 3 4 5 6}

# Grow the database until it is reasonably large. Then, from a 
# journal_mode=DELETE connection, attempt to commit a large transaction (one
# that involves upgrading to an exclusive lock and writing the database
# before the transaction is committed).
#
do_test journal2-1.10 {
  db2 close
  db func a_string a_string
  execsql {
    CREATE TABLE t2(a UNIQUE, b UNIQUE);
    INSERT INTO t2 VALUES(a_string(200), a_string(300));







|
<
<
<







112
113
114
115
116
117
118
119



120
121
122
123
124
125
126
do_test journal2-1.7 { execsql { SELECT * FROM t1 } } {1 2 3 4}
do_test journal2-1.8 {
  execsql { PRAGMA journal_mode = truncate } db2
  execsql { INSERT INTO t1 VALUES(5, 6)  } db2
} {}
do_test journal2-1.9 { execsql { SELECT * FROM t1 } } {1 2 3 4 5 6}

# Grow the database until it is reasonably large.



#
do_test journal2-1.10 {
  db2 close
  db func a_string a_string
  execsql {
    CREATE TABLE t2(a UNIQUE, b UNIQUE);
    INSERT INTO t2 VALUES(a_string(200), a_string(300));
133
134
135
136
137
138
139









140
141
142
143
144
145
146
  file size test.db-journal
} {0}
do_test journal2-1.11 {
  set sz [expr [file size test.db] / 1024]
  expr {$sz>120 && $sz<200}
} 1










do_test journal2-1.12 {
  sqlite3 db2 test.db
  execsql {
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t2 SELECT randomblob(200), randomblob(300) FROM t2;  -- 128
  } db2







>
>
>
>
>
>
>
>
>







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  file size test.db-journal
} {0}
do_test journal2-1.11 {
  set sz [expr [file size test.db] / 1024]
  expr {$sz>120 && $sz<200}
} 1

# Using new connection [db2] (with journal_mode=DELETE), write a lot of
# data to the database. So that many pages within the database file are
# modified before the transaction is committed.
#
# Then, enable simulated IO errors in all calls to xDelete, xWrite
# and xTruncate before committing the transaction and closing the 
# database file. From the point of view of other file-system users, it
# appears as if the process hosting [db2] unexpectedly exited.
# 
do_test journal2-1.12 {
  sqlite3 db2 test.db
  execsql {
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t2 SELECT randomblob(200), randomblob(300) FROM t2;  -- 128
  } db2
177
178
179
180
181
182
183

184




























185


186
187
188
do_test journal2-1.20 {
  sqlite3 db2 testX.db
  expr {[catchsql { PRAGMA integrity_check } db2] == "0 ok"}
} {0}
do_test journal2-1.21 {
  db2 close
} {}






























db close


tvfs delete
finish_test








>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>



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
do_test journal2-1.20 {
  sqlite3 db2 testX.db
  expr {[catchsql { PRAGMA integrity_check } db2] == "0 ok"}
} {0}
do_test journal2-1.21 {
  db2 close
} {}
db close

#-------------------------------------------------------------------------
# Test that it is possible to switch from journal_mode=truncate to
# journal_mode=WAL on a SAFE_DELETE file-system. SQLite should close and
# delete the journal file when committing the transaction that switches
# the system to WAL mode.
#
ifcapable wal {
  do_test journal2-2.1 {
    faultsim_delete_and_reopen
    set ::oplog [list]
    execsql { PRAGMA journal_mode = persist }
    set ::oplog
  } {}
  do_test journal2-2.2 {
    execsql { 
      CREATE TABLE t1(x);
      INSERT INTO t1 VALUES(3.14159);
    }
    set ::oplog
  } {xOpen test.db-journal}
  do_test journal2-2.3 {
    expr {[file size test.db-journal] > 512}
  } {1}
  do_test journal2-2.3 {
    set ::oplog [list]
    execsql { PRAGMA journal_mode = WAL }
    set ::oplog
  } {xClose test.db-journal xDelete test.db-journal}
  db close
}

tvfs delete
finish_test

Changes to test/jrnlmode.test.
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
    do_test jrnlmode-6.5 {
      execsql {
        PRAGMA journal_mode = MEMORY;
        BEGIN;
          INSERT INTO t4 VALUES(3, 4);
      }
      file exists test.db-journal
    } {0}
    do_test jrnlmode-6.7 {
      execsql {
        COMMIT;
        SELECT * FROM t4;
      }
    } {1 2 3 4}
    do_test jrnlmode-6.8 {
      file exists test.db-journal
    } {0}
    do_test jrnlmode-6.9 {
      execsql {
        PRAGMA journal_mode = DELETE;
        BEGIN IMMEDIATE; INSERT INTO t4 VALUES(1,2); COMMIT;
      }
      file exists test.db-journal
    } {0}







|








|







480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
    do_test jrnlmode-6.5 {
      execsql {
        PRAGMA journal_mode = MEMORY;
        BEGIN;
          INSERT INTO t4 VALUES(3, 4);
      }
      file exists test.db-journal
    } {1}
    do_test jrnlmode-6.7 {
      execsql {
        COMMIT;
        SELECT * FROM t4;
      }
    } {1 2 3 4}
    do_test jrnlmode-6.8 {
      file exists test.db-journal
    } {1}
    do_test jrnlmode-6.9 {
      execsql {
        PRAGMA journal_mode = DELETE;
        BEGIN IMMEDIATE; INSERT INTO t4 VALUES(1,2); COMMIT;
      }
      file exists test.db-journal
    } {0}
Added test/tkt-fc62af4523.test.










































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# 2010 June 16
#
# 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. Specifically,
# it tests that ticket [fc62af4523] has been resolved.
#

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

do_test tkt-fc62af4523.1 {
  execsql {
    PRAGMA cache_size = 10;
    PRAGMA journal_mode = persist;
    CREATE TABLE t1(a UNIQUE, b UNIQUE);
    INSERT INTO t1 SELECT randomblob(200), randomblob(300);
    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; --  2
    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; --  4
    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; --  8
    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; -- 16
    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; -- 32
    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; -- 64
  }
  execsql {
    PRAGMA integrity_check;
    SELECT count(*) FROM t1;
  }
} {ok 64}

# Launch an external process. Have it write (but not commit) a large
# transaction to the database.
#
set ::chan [launch_testfixture]
proc buddy {code} { testfixture $::chan $code }
do_test tkt-fc62af4523.2 {
  testfixture $::chan {
    sqlite3 db test.db
    db eval {
      PRAGMA cache_size = 10;
      BEGIN;
        UPDATE t1 SET b = randomblob(400);
        UPDATE t1 SET a = randomblob(200);
    }
  }
  file exists test.db-journal
} {1}

# Now do "PRAGMA journal_mode = DELETE" in this process. At one point
# this was causing SQLite to delete the journal file from the file-system,
# even though the external process is currently using it.
#
do_test tkt-fc62af4523.3 { execsql { PRAGMA journal_mode = DELETE } } {delete}
do_test tkt-fc62af4523.4 { file exists test.db-journal } {1}

# Cause the external process to crash. Since it has already written 
# uncommitted data into the database file, the next reader will have
# to do a hot-journal rollback to recover the database.
#
# Or, if this test is run in a version with the bug present, the journal
# file has already been deleted. In this case we are left with a corrupt
# database file and no hot-journal to fix it with.
#
do_test tkt-fc62af4523.5 {
  testfixture $::chan sqlite_abort
} {ERROR: Child process hung up}
after 200
do_test tkt-fc62af4523.6 {
  execsql {
    PRAGMA integrity_check;
    SELECT count(*) FROM t1;
  }
} {ok 64}

catch { close $::chan }
finish_test