|
1 # 2007 June 13 |
|
2 # |
|
3 # The author disclaims copyright to this source code. In place of |
|
4 # a legal notice, here is a blessing: |
|
5 # |
|
6 # May you do good and not evil. |
|
7 # May you find forgiveness for yourself and forgive others. |
|
8 # May you share freely, never taking more than you give. |
|
9 # |
|
10 #*********************************************************************** |
|
11 # This file implements regression tests for SQLite library. |
|
12 # |
|
13 # This file implements tests to verify that ticket #2409 has been |
|
14 # fixed. More specifically, they verify that if SQLite cannot |
|
15 # obtain an EXCLUSIVE lock while trying to spill the cache during |
|
16 # any statement other than a COMMIT, an I/O error is returned instead |
|
17 # of SQLITE_BUSY. |
|
18 # |
|
19 # $Id: tkt2409.test,v 1.6 2008/08/28 17:46:19 drh Exp $ |
|
20 |
|
21 # Test Outline: |
|
22 # |
|
23 # tkt-2409-1.*: Cause a cache-spill during an INSERT that is within |
|
24 # a db transaction but does not start a statement transaction. |
|
25 # Verify that the transaction is automatically rolled back |
|
26 # and SQLITE_IOERR_BLOCKED is returned |
|
27 # |
|
28 # UPDATE: As of the pcache modifications, failing to upgrade to |
|
29 # an exclusive lock when attempting a cache-spill is no longer an |
|
30 # error. The pcache module allocates more space and keeps working |
|
31 # in memory if this occurs. |
|
32 # |
|
33 # tkt-2409-2.*: Cause a cache-spill while updating the change-counter |
|
34 # during a database COMMIT. Verify that the transaction is not |
|
35 # rolled back and SQLITE_BUSY is returned. |
|
36 # |
|
37 # tkt-2409-3.*: Similar to 2409-1.*, but using many INSERT statements |
|
38 # within a transaction instead of just one. |
|
39 # |
|
40 # UPDATE: Again, pcache now just keeps working in main memory. |
|
41 # |
|
42 # tkt-2409-4.*: Similar to 2409-1.*, but rig it so that the |
|
43 # INSERT statement starts a statement transaction. Verify that |
|
44 # SQLITE_BUSY is returned and the transaction is not rolled back. |
|
45 # |
|
46 # UPDATE: This time, SQLITE_BUSY is not returned. pcache just uses |
|
47 # more malloc()'d memory. |
|
48 # |
|
49 |
|
50 set testdir [file dirname $argv0] |
|
51 source $testdir/tester.tcl |
|
52 |
|
53 ifcapable !pager_pragmas { |
|
54 finish_test |
|
55 return |
|
56 } |
|
57 |
|
58 sqlite3_extended_result_codes $::DB 1 |
|
59 |
|
60 # Aquire a read-lock on the database using handle [db2]. |
|
61 # |
|
62 proc read_lock_db {} { |
|
63 if {$::STMT eq ""} { |
|
64 set ::STMT [sqlite3_prepare db2 {SELECT rowid FROM sqlite_master} -1 TAIL] |
|
65 set rc [sqlite3_step $::STMT] |
|
66 if {$rc eq "SQLITE_ERROR"} { |
|
67 unread_lock_db |
|
68 read_lock_db |
|
69 } |
|
70 } |
|
71 } |
|
72 |
|
73 # Release any read-lock obtained using [read_lock_db] |
|
74 # |
|
75 proc unread_lock_db {} { |
|
76 if {$::STMT ne ""} { |
|
77 sqlite3_finalize $::STMT |
|
78 set ::STMT "" |
|
79 } |
|
80 } |
|
81 |
|
82 # Open the db handle used by [read_lock_db]. |
|
83 # |
|
84 sqlite3 db2 test.db |
|
85 set ::STMT "" |
|
86 |
|
87 do_test tkt2409-1.1 { |
|
88 execsql { |
|
89 PRAGMA cache_size=10; |
|
90 CREATE TABLE t1(x TEXT UNIQUE NOT NULL, y BLOB); |
|
91 } |
|
92 read_lock_db |
|
93 set ::zShort [string repeat 0123456789 1] |
|
94 set ::zLong [string repeat 0123456789 1500] |
|
95 catchsql { |
|
96 BEGIN; |
|
97 INSERT INTO t1 VALUES($::zShort, $::zLong); |
|
98 } |
|
99 } {0 {}} |
|
100 |
|
101 do_test tkt2409-1.2 { |
|
102 sqlite3_errcode $::DB |
|
103 } {SQLITE_OK} |
|
104 |
|
105 # Check the integrity of the cache. |
|
106 # |
|
107 integrity_check tkt2409-1.3 |
|
108 |
|
109 # Check that the transaction was rolled back. Because the INSERT |
|
110 # statement in which the "I/O error" occured did not open a statement |
|
111 # transaction, SQLite had no choice but to roll back the transaction. |
|
112 # |
|
113 do_test tkt2409-1.4 { |
|
114 unread_lock_db |
|
115 catchsql { ROLLBACK } |
|
116 } {0 {}} |
|
117 |
|
118 set ::zShort [string repeat 0123456789 1] |
|
119 set ::zLong [string repeat 0123456789 1500] |
|
120 set ::rc 1 |
|
121 for {set iCache 10} {$::rc} {incr iCache} { |
|
122 execsql "PRAGMA cache_size = $iCache" |
|
123 do_test tkt2409-2.1.$iCache { |
|
124 read_lock_db |
|
125 set ::rc [catch { |
|
126 execsql { |
|
127 BEGIN; |
|
128 INSERT INTO t1 VALUES($::zShort, $::zLong); |
|
129 } |
|
130 } msg] |
|
131 expr {($::rc == 1 && $msg eq "disk I/O error") || $::rc == 0} |
|
132 } {1} |
|
133 } |
|
134 |
|
135 do_test tkt2409-2.2 { |
|
136 catchsql { |
|
137 ROLLBACK; |
|
138 BEGIN; |
|
139 INSERT INTO t1 VALUES($::zShort, $::zLong); |
|
140 COMMIT; |
|
141 } |
|
142 } {1 {database is locked}} |
|
143 |
|
144 do_test tkt2409-2.3 { |
|
145 unread_lock_db |
|
146 catchsql { |
|
147 COMMIT; |
|
148 } |
|
149 } {0 {}} |
|
150 |
|
151 |
|
152 do_test tkt2409-3.1 { |
|
153 db close |
|
154 set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db] |
|
155 sqlite3_extended_result_codes $::DB 1 |
|
156 execsql { |
|
157 PRAGMA cache_size=10; |
|
158 DELETE FROM t1; |
|
159 } |
|
160 read_lock_db |
|
161 set ::zShort [string repeat 0123456789 1] |
|
162 set ::zLong [string repeat 0123456789 1500] |
|
163 catchsql { |
|
164 BEGIN; |
|
165 INSERT INTO t1 SELECT $::zShort, $::zLong; |
|
166 } |
|
167 } {0 {}} |
|
168 |
|
169 do_test tkt2409-3.2 { |
|
170 sqlite3_errcode $::DB |
|
171 } {SQLITE_OK} |
|
172 |
|
173 # Check the integrity of the cache. |
|
174 # |
|
175 integrity_check tkt2409-3.3 |
|
176 |
|
177 # Check that the transaction was rolled back. Because the INSERT |
|
178 # statement in which the "I/O error" occured did not open a statement |
|
179 # transaction, SQLite had no choice but to roll back the transaction. |
|
180 # |
|
181 do_test tkt2409-3.4 { |
|
182 unread_lock_db |
|
183 catchsql { ROLLBACK } |
|
184 } {0 {}} |
|
185 integrity_check tkt2409-3.5 |
|
186 |
|
187 expr {srand(1)} |
|
188 do_test tkt2409-4.1 { |
|
189 execsql { |
|
190 PRAGMA cache_size=20; |
|
191 DROP TABLE t1; |
|
192 CREATE TABLE t1 (x TEXT UNIQUE NOT NULL); |
|
193 } |
|
194 |
|
195 unset -nocomplain t1 |
|
196 array unset t1 |
|
197 set t1(0) 1 |
|
198 set sql "" |
|
199 for {set i 0} {$i<5000} {incr i} { |
|
200 set r 0 |
|
201 while {[info exists t1($r)]} { |
|
202 set r [expr {int(rand()*1000000000)}] |
|
203 } |
|
204 set t1($r) 1 |
|
205 append sql "INSERT INTO t1 VALUES('some-text-$r');" |
|
206 } |
|
207 |
|
208 read_lock_db |
|
209 execsql BEGIN |
|
210 catchsql $sql |
|
211 } {0 {}} |
|
212 |
|
213 do_test tkt2409-4.2 { |
|
214 sqlite3_errcode $::DB |
|
215 } {SQLITE_OK} |
|
216 |
|
217 # Check the integrity of the cache. |
|
218 # |
|
219 integrity_check tkt2409-4.3 |
|
220 |
|
221 do_test tkt2409-4.4 { |
|
222 catchsql { ROLLBACK } |
|
223 } {0 {}} |
|
224 integrity_check tkt2409-4.5 |
|
225 |
|
226 unread_lock_db |
|
227 db2 close |
|
228 unset -nocomplain t1 |
|
229 finish_test |