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