summaryrefslogtreecommitdiff
path: root/test/tkt2854.test
blob: 914ddd1b697c95c31bf199bb3f8e8b361f244e5f (plain)
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# 2007 December 20
#
# 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.
#
#***********************************************************************
#
# $Id: tkt2854.test,v 1.4 2009/03/16 13:19:36 danielk1977 Exp $

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

ifcapable !shared_cache {
  finish_test
  return
}

set ::enable_shared_cache [sqlite3_enable_shared_cache 1]

# Open 3 database connections. Connection "db" and "db2" share a cache.
# Connection "db3" has its own cache.
#
do_test tkt2854-1.1 {
  sqlite3 db test.db
  sqlite3 db2 test.db

  # This is taken from shared.test.  The Windows VFS expands 
  # ./test.db (and test.db) to be the same thing so the path
  # matches and they share a cache.  By changing the case 
  # for Windows platform, we get around this and get a separate
  # connection.
  if {$::tcl_platform(platform)=="unix"} {
    sqlite3 db3 ./test.db
  } else {
    sqlite3 db3 TEST.DB
  }

  db eval {
    CREATE TABLE abc(a, b, c);
  }
} {}

# Check that an exclusive lock cannot be obtained if some other 
# shared-cache connection has a read-lock on a table.
#
do_test tkt2854-1.2 {
  execsql { 
    BEGIN;
    SELECT * FROM abc;
  } db2
} {}
do_test tkt2854-1.3 {
  catchsql { BEGIN EXCLUSIVE } db
} {1 {database table is locked}}
do_test tkt2854-1.4 {
  execsql { SELECT * FROM abc } db3
} {}
do_test tkt2854-1.5 {
  catchsql { INSERT INTO abc VALUES(1, 2, 3) } db3
} {1 {database is locked}}
do_test tkt2854-1.6 {
  execsql { COMMIT } db2
} {}

# Check that an exclusive lock prevents other shared-cache users from
# starting a transaction.
#
do_test tkt2854-1.7 {
  set ::DB2 [sqlite3_connection_pointer db2]
  set ::STMT1 [sqlite3_prepare $DB2 "SELECT * FROM abc" -1 TAIL]
  set ::STMT2 [sqlite3_prepare $DB2 "BEGIN EXCLUSIVE" -1 TAIL]
  set ::STMT3 [sqlite3_prepare $DB2 "BEGIN IMMEDIATE" -1 TAIL]
  set ::STMT4 [sqlite3_prepare $DB2 "BEGIN" -1 TAIL]
  set ::STMT5 [sqlite3_prepare $DB2 "COMMIT" -1 TAIL]
  execsql { BEGIN EXCLUSIVE } db
} {}
do_test tkt2854-1.8 {
  catchsql { BEGIN EXCLUSIVE } db2
} {1 {database schema is locked: main}}
do_test tkt2854-1.9 {
  catchsql { BEGIN IMMEDIATE } db2
} {1 {database schema is locked: main}}
do_test tkt2854-1.10 {
  # This fails because the schema of main cannot be verified.
  catchsql { BEGIN } db2
} {1 {database schema is locked: main}}

# Check that an exclusive lock prevents other shared-cache users from
# reading the database. Use stored statements so that the error occurs
# at the b-tree level, not the schema level.
#
do_test tkt2854-1.11 {
  list [sqlite3_step $::STMT1] [sqlite3_finalize $::STMT1]
} {SQLITE_ERROR SQLITE_LOCKED}
do_test tkt2854-1.12 {
  list [sqlite3_step $::STMT2] [sqlite3_finalize $::STMT2]
} {SQLITE_ERROR SQLITE_LOCKED}
do_test tkt2854-1.13 {
  list [sqlite3_step $::STMT3] [sqlite3_finalize $::STMT3]
} {SQLITE_ERROR SQLITE_LOCKED}
do_test tkt2854-1.14 {
  # A regular "BEGIN" doesn't touch any databases. So it succeeds.
  list [sqlite3_step $::STMT4] [sqlite3_finalize $::STMT4]
} {SQLITE_DONE SQLITE_OK}
do_test tkt2854-1.15 {
  # As does a COMMIT.
  list [sqlite3_step $::STMT5] [sqlite3_finalize $::STMT5]
} {SQLITE_DONE SQLITE_OK}

# Try to read the database using connection "db3" (which does not share
# a cache with "db"). The database should be locked.
do_test tkt2854-1.16 {
  catchsql { SELECT * FROM abc } db3
} {1 {database is locked}}
do_test tkt2854-1.17 {
  execsql { COMMIT } db
} {}
do_test tkt2854-1.18 {
  execsql { SELECT * FROM abc } db2
} {}

# Check that if an attempt to obtain an exclusive lock fails because an
# attached db cannot be locked, the internal exclusive flag used by
# shared-cache users is correctly cleared.
do_test tkt2854-1.19 {
  forcedelete test2.db test2.db-journal
  sqlite3 db4 test2.db
  execsql { CREATE TABLE def(d, e, f) } db4
  execsql { ATTACH 'test2.db' AS aux } db
} {}
do_test tkt2854-1.20 {
  execsql {BEGIN IMMEDIATE} db4
  catchsql {BEGIN EXCLUSIVE} db
} {1 {database table is locked}}
do_test tkt2854-1.21 {
  execsql {SELECT * FROM abc} db2
} {}

db close
db2 close
db3 close
db4 close
sqlite3_enable_shared_cache $::enable_shared_cache
finish_test