xref: /sqlite-3.40.0/test/pager1.test (revision e91a54e1)
1*e91a54e1Sdan# 2010 June 15
2*e91a54e1Sdan#
3*e91a54e1Sdan# The author disclaims copyright to this source code.  In place of
4*e91a54e1Sdan# a legal notice, here is a blessing:
5*e91a54e1Sdan#
6*e91a54e1Sdan#    May you do good and not evil.
7*e91a54e1Sdan#    May you find forgiveness for yourself and forgive others.
8*e91a54e1Sdan#    May you share freely, never taking more than you give.
9*e91a54e1Sdan#
10*e91a54e1Sdan#***********************************************************************
11*e91a54e1Sdan#
12*e91a54e1Sdan
13*e91a54e1Sdanset testdir [file dirname $argv0]
14*e91a54e1Sdansource $testdir/tester.tcl
15*e91a54e1Sdansource $testdir/lock_common.tcl
16*e91a54e1Sdansource $testdir/malloc_common.tcl
17*e91a54e1Sdan
18*e91a54e1Sdanforeach code [list {
19*e91a54e1Sdan  set ::code2_chan [launch_testfixture]
20*e91a54e1Sdan  set ::code3_chan [launch_testfixture]
21*e91a54e1Sdan  proc code2 {tcl} { testfixture $::code2_chan $tcl }
22*e91a54e1Sdan  proc code3 {tcl} { testfixture $::code3_chan $tcl }
23*e91a54e1Sdan  set tn 1
24*e91a54e1Sdan} {
25*e91a54e1Sdan  proc code2 {tcl} { uplevel #0 $tcl }
26*e91a54e1Sdan  proc code3 {tcl} { uplevel #0 $tcl }
27*e91a54e1Sdan  set tn 2
28*e91a54e1Sdan}] {
29*e91a54e1Sdan
30*e91a54e1Sdan  faultsim_delete_and_reopen
31*e91a54e1Sdan
32*e91a54e1Sdan  # Open connections [db2] and [db3]. Depending on which iteration this
33*e91a54e1Sdan  # is, the connections may be created in this interpreter, or in
34*e91a54e1Sdan  # interpreters running in other OS processes. As such, the [db2] and [db3]
35*e91a54e1Sdan  # commands should only be accessed within [code2] and [code3] blocks,
36*e91a54e1Sdan  # respectively.
37*e91a54e1Sdan  #
38*e91a54e1Sdan  eval $code
39*e91a54e1Sdan  code2 { sqlite3 db2 test.db }
40*e91a54e1Sdan  code3 { sqlite3 db3 test.db }
41*e91a54e1Sdan
42*e91a54e1Sdan  # Shorthand commands. Execute SQL using database connection [db2] or
43*e91a54e1Sdan  # [db3]. Return the results.
44*e91a54e1Sdan  #
45*e91a54e1Sdan  proc sql1 {sql} { db eval $sql }
46*e91a54e1Sdan  proc sql2 {sql} { code2 [list db2 eval $sql] }
47*e91a54e1Sdan  proc sql3 {sql} { code3 [list db3 eval $sql] }
48*e91a54e1Sdan
49*e91a54e1Sdan  proc csql1 {sql} { list [catch { sql1 $sql } msg] $msg }
50*e91a54e1Sdan  proc csql2 {sql} { list [catch { sql2 $sql } msg] $msg }
51*e91a54e1Sdan  proc csql3 {sql} { list [catch { sql3 $sql } msg] $msg }
52*e91a54e1Sdan
53*e91a54e1Sdan  # Create and populate a database table using connection [db]. Check
54*e91a54e1Sdan  # that connections [db2] and [db3] can see the schema and content.
55*e91a54e1Sdan  #
56*e91a54e1Sdan  do_test pager1-$tn.1 {
57*e91a54e1Sdan    sql1 {
58*e91a54e1Sdan      CREATE TABLE t1(a PRIMARY KEY, b);
59*e91a54e1Sdan      CREATE INDEX i1 ON t1(b);
60*e91a54e1Sdan      INSERT INTO t1 VALUES(1, 'one');
61*e91a54e1Sdan      INSERT INTO t1 VALUES(2, 'two');
62*e91a54e1Sdan    }
63*e91a54e1Sdan  } {}
64*e91a54e1Sdan  do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
65*e91a54e1Sdan  do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
66*e91a54e1Sdan
67*e91a54e1Sdan  # Open a transaction and add a row using [db]. This puts [db] in
68*e91a54e1Sdan  # RESERVED state. Check that connections [db2] and [db3] can still
69*e91a54e1Sdan  # read the database content as it was before the transaction was
70*e91a54e1Sdan  # opened. [db] should see the inserted row.
71*e91a54e1Sdan  #
72*e91a54e1Sdan  do_test pager1-$tn.4 {
73*e91a54e1Sdan    sql1 {
74*e91a54e1Sdan      BEGIN;
75*e91a54e1Sdan        INSERT INTO t1 VALUES(3, 'three');
76*e91a54e1Sdan    }
77*e91a54e1Sdan  } {}
78*e91a54e1Sdan  do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
79*e91a54e1Sdan  do_test pager1-$tn.6 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
80*e91a54e1Sdan  do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
81*e91a54e1Sdan
82*e91a54e1Sdan  # [db] still has an open write transaction. Check that this prevents
83*e91a54e1Sdan  # other connections (specifically [db2]) from writing to the database.
84*e91a54e1Sdan  #
85*e91a54e1Sdan  # Even if [db2] opens a transaction first, it may not write to the
86*e91a54e1Sdan  # database. After the attempt to write the db within a transaction,
87*e91a54e1Sdan  # [db2] is left with an open transaction, but not a read-lock on
88*e91a54e1Sdan  # the main database. So it does not prevent [db] from committing.
89*e91a54e1Sdan  #
90*e91a54e1Sdan  do_test pager1-$tn.8 {
91*e91a54e1Sdan    csql2 { UPDATE t1 SET a = a + 10 }
92*e91a54e1Sdan  } {1 {database is locked}}
93*e91a54e1Sdan  do_test pager1-$tn.9 {
94*e91a54e1Sdan    csql2 {
95*e91a54e1Sdan      BEGIN;
96*e91a54e1Sdan      UPDATE t1 SET a = a + 10;
97*e91a54e1Sdan    }
98*e91a54e1Sdan  } {1 {database is locked}}
99*e91a54e1Sdan
100*e91a54e1Sdan  # Have [db] commit its transactions. Check the other connections can
101*e91a54e1Sdan  # now see the new database content.
102*e91a54e1Sdan  #
103*e91a54e1Sdan  do_test pager1-$tn.10 { sql1 { COMMIT } } {}
104*e91a54e1Sdan  do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
105*e91a54e1Sdan  do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
106*e91a54e1Sdan  do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
107*e91a54e1Sdan
108*e91a54e1Sdan  # Check that, as noted above, [db2] really did keep an open transaction
109*e91a54e1Sdan  # after the attempt to write the database failed.
110*e91a54e1Sdan  #
111*e91a54e1Sdan  do_test pager1-$tn.14 {
112*e91a54e1Sdan    csql2 { BEGIN }
113*e91a54e1Sdan  } {1 {cannot start a transaction within a transaction}}
114*e91a54e1Sdan  do_test pager1-$tn.15 { sql2 { ROLLBACK } } {}
115*e91a54e1Sdan
116*e91a54e1Sdan  # Have [db2] open a transaction and take a read-lock on the database.
117*e91a54e1Sdan  # Check that this prevents [db] from writing to the database (outside
118*e91a54e1Sdan  # of any transaction). After this fails, check that [db3] can read
119*e91a54e1Sdan  # the db (showing that [db] did not take a PENDING lock etc.)
120*e91a54e1Sdan  #
121*e91a54e1Sdan  do_test pager1-$tn.15 {
122*e91a54e1Sdan    sql2 { BEGIN; SELECT * FROM t1; }
123*e91a54e1Sdan  } {1 one 2 two 3 three}
124*e91a54e1Sdan  do_test pager1-$tn.16 {
125*e91a54e1Sdan    csql1 { UPDATE t1 SET a = a + 10 }
126*e91a54e1Sdan  } {1 {database is locked}}
127*e91a54e1Sdan  do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
128*e91a54e1Sdan
129*e91a54e1Sdan  # This time, have [db] open a transaction before writing the database.
130*e91a54e1Sdan  # This works - [db] gets a RESERVED lock which does not conflict with
131*e91a54e1Sdan  # the SHARED lock [db2] is holding.
132*e91a54e1Sdan  #
133*e91a54e1Sdan  do_test pager1-$tn.18 {
134*e91a54e1Sdan    sql1 {
135*e91a54e1Sdan      BEGIN;
136*e91a54e1Sdan      UPDATE t1 SET a = a + 10;
137*e91a54e1Sdan    }
138*e91a54e1Sdan  } {}
139*e91a54e1Sdan  do_test pager1-$tn-19 {
140*e91a54e1Sdan    sql1 { PRAGMA lock_status }
141*e91a54e1Sdan  } {main reserved temp closed}
142*e91a54e1Sdan  do_test pager1-$tn-20 {
143*e91a54e1Sdan    sql2 { PRAGMA lock_status }
144*e91a54e1Sdan  } {main shared temp closed}
145*e91a54e1Sdan
146*e91a54e1Sdan  # Check that all connections can still read the database. Only [db] sees
147*e91a54e1Sdan  # the updated content (as the transaction has not been committed yet).
148*e91a54e1Sdan  #
149*e91a54e1Sdan  do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three}
150*e91a54e1Sdan  do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
151*e91a54e1Sdan  do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
152*e91a54e1Sdan
153*e91a54e1Sdan  # Because [db2] still has the SHARED lock, [db] is unable to commit the
154*e91a54e1Sdan  # transaction. If it tries, an error is returned and the connection
155*e91a54e1Sdan  # upgrades to a PENDING lock.
156*e91a54e1Sdan  #
157*e91a54e1Sdan  # Once this happens, [db] can read the database and see the new content,
158*e91a54e1Sdan  # [db2] (still holding SHARED) can still read the old content, but [db3]
159*e91a54e1Sdan  # (not holding any lock) is prevented by [db]'s PENDING from reading
160*e91a54e1Sdan  # the database.
161*e91a54e1Sdan  #
162*e91a54e1Sdan  do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}}
163*e91a54e1Sdan  do_test pager1-$tn-25 {
164*e91a54e1Sdan    sql1 { PRAGMA lock_status }
165*e91a54e1Sdan  } {main pending temp closed}
166*e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { SELECT * FROM t1  } } {11 one 12 two 13 three}
167*e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1  } } {1 one 2 two 3 three}
168*e91a54e1Sdan  do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
169*e91a54e1Sdan
170*e91a54e1Sdan  # Have [db2] commit its read transaction, releasing the SHARED lock it
171*e91a54e1Sdan  # is holding. Now, neither [db2] nor [db3] may read the database (as [db]
172*e91a54e1Sdan  # is still holding a PENDING).
173*e91a54e1Sdan  #
174*e91a54e1Sdan  do_test pager1-$tn.29 { sql2 { COMMIT } } {}
175*e91a54e1Sdan  do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
176*e91a54e1Sdan  do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
177*e91a54e1Sdan
178*e91a54e1Sdan  # [db] is now able to commit the transaction. Once the transaction is
179*e91a54e1Sdan  # committed, all three connections can read the new content.
180*e91a54e1Sdan  #
181*e91a54e1Sdan  do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {}
182*e91a54e1Sdan  do_test pager1-$tn.26 { sql1 { COMMIT } } {}
183*e91a54e1Sdan  do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three}
184*e91a54e1Sdan  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three}
185*e91a54e1Sdan  do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three}
186*e91a54e1Sdan
187*e91a54e1Sdan  code2 { db2 close }
188*e91a54e1Sdan  code3 { db3 close }
189*e91a54e1Sdan  catch { close $::code2_chan }
190*e91a54e1Sdan  catch { close $::code3_chan }
191*e91a54e1Sdan}
192*e91a54e1Sdan
193*e91a54e1Sdanfinish_test
194*e91a54e1Sdan
195