1*aef0bf64Sdanielk1977# 2005 December 30 2*aef0bf64Sdanielk1977# 3*aef0bf64Sdanielk1977# The author disclaims copyright to this source code. In place of 4*aef0bf64Sdanielk1977# a legal notice, here is a blessing: 5*aef0bf64Sdanielk1977# 6*aef0bf64Sdanielk1977# May you do good and not evil. 7*aef0bf64Sdanielk1977# May you find forgiveness for yourself and forgive others. 8*aef0bf64Sdanielk1977# May you share freely, never taking more than you give. 9*aef0bf64Sdanielk1977# 10*aef0bf64Sdanielk1977#*********************************************************************** 11*aef0bf64Sdanielk1977# This file implements regression tests for SQLite library. The 12*aef0bf64Sdanielk1977# focus of this file is testing the SELECT statement. 13*aef0bf64Sdanielk1977# 14*aef0bf64Sdanielk1977# $Id: shared.test,v 1.1 2005/12/30 16:28:02 danielk1977 Exp $ 15*aef0bf64Sdanielk1977 16*aef0bf64Sdanielk1977set ::enable_shared_cache [sqlite3_enable_shared_cache 1] 17*aef0bf64Sdanielk1977 18*aef0bf64Sdanielk1977set testdir [file dirname $argv0] 19*aef0bf64Sdanielk1977source $testdir/tester.tcl 20*aef0bf64Sdanielk1977db close 21*aef0bf64Sdanielk1977 22*aef0bf64Sdanielk1977ifcapable !shared_cache { 23*aef0bf64Sdanielk1977 finish_test 24*aef0bf64Sdanielk1977 return 25*aef0bf64Sdanielk1977} 26*aef0bf64Sdanielk1977 27*aef0bf64Sdanielk1977# Test organization: 28*aef0bf64Sdanielk1977# 29*aef0bf64Sdanielk1977# shared-1.*: Simple test to verify basic sanity of table level locking when 30*aef0bf64Sdanielk1977# two connections share a pager cache. 31*aef0bf64Sdanielk1977# shared-2.*: Test that a read transaction can co-exist with a 32*aef0bf64Sdanielk1977# write-transaction, including a simple test to ensure the 33*aef0bf64Sdanielk1977# external locking protocol is still working. 34*aef0bf64Sdanielk1977# 35*aef0bf64Sdanielk1977 36*aef0bf64Sdanielk1977do_test shared-1.1 { 37*aef0bf64Sdanielk1977 # Open a second database on the file test.db. It should use the same pager 38*aef0bf64Sdanielk1977 # cache and schema as the original connection. Verify that only 1 file is 39*aef0bf64Sdanielk1977 # opened. 40*aef0bf64Sdanielk1977 sqlite3 db2 test.db 41*aef0bf64Sdanielk1977 sqlite3 db test.db 42*aef0bf64Sdanielk1977 set ::sqlite_open_file_count 43*aef0bf64Sdanielk1977} {1} 44*aef0bf64Sdanielk1977do_test shared-1.2 { 45*aef0bf64Sdanielk1977 # Add a table and a single row of data via the first connection. 46*aef0bf64Sdanielk1977 # Ensure that the second connection can see them. 47*aef0bf64Sdanielk1977 execsql { 48*aef0bf64Sdanielk1977 CREATE TABLE abc(a, b, c); 49*aef0bf64Sdanielk1977 INSERT INTO abc VALUES(1, 2, 3); 50*aef0bf64Sdanielk1977 } db 51*aef0bf64Sdanielk1977 execsql { 52*aef0bf64Sdanielk1977 SELECT * FROM abc; 53*aef0bf64Sdanielk1977 } db2 54*aef0bf64Sdanielk1977} {1 2 3} 55*aef0bf64Sdanielk1977do_test shared-1.3 { 56*aef0bf64Sdanielk1977 # Have the first connection begin a transaction and obtain a read-lock 57*aef0bf64Sdanielk1977 # on table abc. This should not prevent the second connection from 58*aef0bf64Sdanielk1977 # querying abc. 59*aef0bf64Sdanielk1977 execsql { 60*aef0bf64Sdanielk1977 BEGIN; 61*aef0bf64Sdanielk1977 SELECT * FROM abc; 62*aef0bf64Sdanielk1977 } 63*aef0bf64Sdanielk1977 execsql { 64*aef0bf64Sdanielk1977 SELECT * FROM abc; 65*aef0bf64Sdanielk1977 } db2 66*aef0bf64Sdanielk1977} {1 2 3} 67*aef0bf64Sdanielk1977do_test shared-1.4 { 68*aef0bf64Sdanielk1977 # Try to insert a row into abc via connection 2. This should fail because 69*aef0bf64Sdanielk1977 # of the read-lock connection 1 is holding on table abc (obtained in the 70*aef0bf64Sdanielk1977 # previous test case). 71*aef0bf64Sdanielk1977 catchsql { 72*aef0bf64Sdanielk1977 INSERT INTO abc VALUES(4, 5, 6); 73*aef0bf64Sdanielk1977 } db2 74*aef0bf64Sdanielk1977} {1 {database is locked}} 75*aef0bf64Sdanielk1977do_test shared-1.5 { 76*aef0bf64Sdanielk1977 # Using connection 2 (the one without the open transaction), create a 77*aef0bf64Sdanielk1977 # new table and add a row to it. This is permitted as the transaction 78*aef0bf64Sdanielk1977 # started by connection 1 is currently a read transaction. 79*aef0bf64Sdanielk1977 execsql { 80*aef0bf64Sdanielk1977 CREATE TABLE def(d, e, f); 81*aef0bf64Sdanielk1977 INSERT INTO def VALUES('I', 'II', 'III'); 82*aef0bf64Sdanielk1977 } db2 83*aef0bf64Sdanielk1977} {} 84*aef0bf64Sdanielk1977do_test shared-1.6 { 85*aef0bf64Sdanielk1977 # Upgrade connection 1's transaction to a write transaction. Insert 86*aef0bf64Sdanielk1977 # a row into table def - the table just created by connection 2. 87*aef0bf64Sdanielk1977 # 88*aef0bf64Sdanielk1977 # Connection 1 is able to see table def, even though it was created 89*aef0bf64Sdanielk1977 # "after" the connection 1 transaction was started. This is because no 90*aef0bf64Sdanielk1977 # lock was established on the sqlite_master table. 91*aef0bf64Sdanielk1977 92*aef0bf64Sdanielk1977# Todo: Remove this. Because the implementation does not include 93*aef0bf64Sdanielk1977# shared-schemas yet, we need to run some query (that will fail at 94*aef0bf64Sdanielk1977# OP_VerifyCookie) so that connection 1 picks up the schema change 95*aef0bf64Sdanielk1977# made via connection 2. Otherwise the sqlite3_prepare("INSERT INTO def...") 96*aef0bf64Sdanielk1977# below will fail. 97*aef0bf64Sdanielk1977execsql { 98*aef0bf64Sdanielk1977 SELECT * FROM sqlite_master; 99*aef0bf64Sdanielk1977} 100*aef0bf64Sdanielk1977 101*aef0bf64Sdanielk1977 execsql { 102*aef0bf64Sdanielk1977 INSERT INTO def VALUES('IV', 'V', 'VI'); 103*aef0bf64Sdanielk1977 } 104*aef0bf64Sdanielk1977} {} 105*aef0bf64Sdanielk1977do_test shared-1.7 { 106*aef0bf64Sdanielk1977 # Read from the sqlite_master table with connection 1 (inside the 107*aef0bf64Sdanielk1977 # transaction). Then test that we can no longer create a table 108*aef0bf64Sdanielk1977 # with connection 2. This is because of the read-lock on sqlite_master. 109*aef0bf64Sdanielk1977 execsql { 110*aef0bf64Sdanielk1977 SELECT * FROM sqlite_master; 111*aef0bf64Sdanielk1977 } 112*aef0bf64Sdanielk1977 catchsql { 113*aef0bf64Sdanielk1977 CREATE TABLE ghi(g, h, i); 114*aef0bf64Sdanielk1977 } db2 115*aef0bf64Sdanielk1977} {1 {database is locked}} 116*aef0bf64Sdanielk1977do_test shared-1.8 { 117*aef0bf64Sdanielk1977 # Check that connection 2 can read the sqlite_master table. Then 118*aef0bf64Sdanielk1977 # create a table using connection 1 (this should write-lock the 119*aef0bf64Sdanielk1977 # sqlite_master table). Then try to read sqlite_master again using 120*aef0bf64Sdanielk1977 # connection 2 and verify that the write-lock prevents this. 121*aef0bf64Sdanielk1977 execsql { 122*aef0bf64Sdanielk1977 SELECT * FROM sqlite_master; 123*aef0bf64Sdanielk1977 } db2 124*aef0bf64Sdanielk1977 execsql { 125*aef0bf64Sdanielk1977 CREATE TABLE ghi(g, h, i); 126*aef0bf64Sdanielk1977 } 127*aef0bf64Sdanielk1977 catchsql { 128*aef0bf64Sdanielk1977 SELECT * FROM sqlite_master; 129*aef0bf64Sdanielk1977 } db2 130*aef0bf64Sdanielk1977} {1 {database is locked}} 131*aef0bf64Sdanielk1977do_test shared-1.9 { 132*aef0bf64Sdanielk1977 # Commit the connection 1 transaction. 133*aef0bf64Sdanielk1977 execsql { 134*aef0bf64Sdanielk1977 COMMIT; 135*aef0bf64Sdanielk1977 } 136*aef0bf64Sdanielk1977} {} 137*aef0bf64Sdanielk1977 138*aef0bf64Sdanielk1977do_test shared-2.1 { 139*aef0bf64Sdanielk1977 # Open connection db3 to the database. Use a different path to the same 140*aef0bf64Sdanielk1977 # file so that db3 does *not* share the same pager cache as db and db2 141*aef0bf64Sdanielk1977 # (there should be two open file handles). 142*aef0bf64Sdanielk1977 sqlite3 db3 ./test.db 143*aef0bf64Sdanielk1977 set ::sqlite_open_file_count 144*aef0bf64Sdanielk1977} {2} 145*aef0bf64Sdanielk1977do_test shared-2.2 { 146*aef0bf64Sdanielk1977 # Start read transactions on db and db2 (the shared pager cache). Ensure 147*aef0bf64Sdanielk1977 # db3 cannot write to the database. 148*aef0bf64Sdanielk1977 execsql { 149*aef0bf64Sdanielk1977 BEGIN; 150*aef0bf64Sdanielk1977 SELECT * FROM abc; 151*aef0bf64Sdanielk1977 } 152*aef0bf64Sdanielk1977 execsql { 153*aef0bf64Sdanielk1977 BEGIN; 154*aef0bf64Sdanielk1977 SELECT * FROM abc; 155*aef0bf64Sdanielk1977 } db2 156*aef0bf64Sdanielk1977 catchsql { 157*aef0bf64Sdanielk1977 INSERT INTO abc VALUES(1, 2, 3); 158*aef0bf64Sdanielk1977 } db2 159*aef0bf64Sdanielk1977} {1 {database is locked}} 160*aef0bf64Sdanielk1977do_test shared-2.3 { 161*aef0bf64Sdanielk1977 # Turn db's transaction into a write-transaction. db3 should still be 162*aef0bf64Sdanielk1977 # able to read from table def (but will not see the new row). Connection 163*aef0bf64Sdanielk1977 # db2 should not be able to read def (because of the write-lock). 164*aef0bf64Sdanielk1977 165*aef0bf64Sdanielk1977# Todo: The failed "INSERT INTO abc ..." statement in the above test 166*aef0bf64Sdanielk1977# has started a write-transaction on db2 (should this be so?). This 167*aef0bf64Sdanielk1977# would prevent connection db from starting a write-transaction. So roll the 168*aef0bf64Sdanielk1977# db2 transaction back and replace it with a new read transaction. 169*aef0bf64Sdanielk1977 execsql { 170*aef0bf64Sdanielk1977 ROLLBACK; 171*aef0bf64Sdanielk1977 BEGIN; 172*aef0bf64Sdanielk1977 SELECT * FROM abc; 173*aef0bf64Sdanielk1977 } db2 174*aef0bf64Sdanielk1977 175*aef0bf64Sdanielk1977 execsql { 176*aef0bf64Sdanielk1977 INSERT INTO def VALUES('VII', 'VIII', 'IX'); 177*aef0bf64Sdanielk1977 } 178*aef0bf64Sdanielk1977 concat [ 179*aef0bf64Sdanielk1977 catchsql { SELECT * FROM def; } db3 180*aef0bf64Sdanielk1977 ] [ 181*aef0bf64Sdanielk1977 catchsql { SELECT * FROM def; } db2 182*aef0bf64Sdanielk1977 ] 183*aef0bf64Sdanielk1977} {0 {I II III IV V VI} 1 {database is locked}} 184*aef0bf64Sdanielk1977do_test shared-2.4 { 185*aef0bf64Sdanielk1977 # Commit the open transaction on db. db2 still holds a read-transaction. 186*aef0bf64Sdanielk1977 # This should prevent db3 from writing to the database, but not from 187*aef0bf64Sdanielk1977 # reading. 188*aef0bf64Sdanielk1977 execsql { 189*aef0bf64Sdanielk1977 COMMIT; 190*aef0bf64Sdanielk1977 } 191*aef0bf64Sdanielk1977 concat [ 192*aef0bf64Sdanielk1977 catchsql { SELECT * FROM def; } db3 193*aef0bf64Sdanielk1977 ] [ 194*aef0bf64Sdanielk1977 catchsql { INSERT INTO def VALUES('X', 'XI', 'XII'); } db3 195*aef0bf64Sdanielk1977 ] 196*aef0bf64Sdanielk1977} {0 {I II III IV V VI VII VIII IX} 1 {database is locked}} 197*aef0bf64Sdanielk1977 198*aef0bf64Sdanielk1977 199*aef0bf64Sdanielk1977catch {db close} 200*aef0bf64Sdanielk1977catch {db2 close} 201*aef0bf64Sdanielk1977catch {db3 close} 202*aef0bf64Sdanielk1977 203*aef0bf64Sdanielk1977finish_test 204*aef0bf64Sdanielk1977sqlite3_enable_shared_cache $::enable_shared_cache 205*aef0bf64Sdanielk1977 206