OLD | NEW |
| (Empty) |
1 # 2005 December 30 | |
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 # | |
12 # $Id: shared.test,v 1.36 2009/03/16 13:19:36 danielk1977 Exp $ | |
13 | |
14 set testdir [file dirname $argv0] | |
15 source $testdir/tester.tcl | |
16 db close | |
17 | |
18 # These tests cannot be run without the ATTACH command. | |
19 # | |
20 ifcapable !shared_cache||!attach { | |
21 finish_test | |
22 return | |
23 } | |
24 | |
25 set ::enable_shared_cache [sqlite3_enable_shared_cache 1] | |
26 | |
27 foreach av [list 0 1] { | |
28 | |
29 # Open the database connection and execute the auto-vacuum pragma | |
30 forcedelete test.db | |
31 sqlite3 db test.db | |
32 | |
33 ifcapable autovacuum { | |
34 do_test shared-[expr $av+1].1.0 { | |
35 execsql "pragma auto_vacuum=$::av" | |
36 execsql {pragma auto_vacuum} | |
37 } "$av" | |
38 } else { | |
39 if {$av} { | |
40 db close | |
41 break | |
42 } | |
43 } | |
44 | |
45 # if we're using proxy locks, we use 2 filedescriptors for a db | |
46 # that is open but NOT yet locked, after a lock is taken we'll have 3, | |
47 # normally sqlite uses 1 (proxy locking adds the conch and the local lock) | |
48 set using_proxy 0 | |
49 foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] { | |
50 set using_proxy $value | |
51 } | |
52 set extrafds_prelock 0 | |
53 set extrafds_postlock 0 | |
54 if {$using_proxy>0} { | |
55 set extrafds_prelock 1 | |
56 set extrafds_postlock 2 | |
57 } | |
58 | |
59 # $av is currently 0 if this loop iteration is to test with auto-vacuum turned | |
60 # off, and 1 if it is turned on. Increment it so that (1 -> no auto-vacuum) | |
61 # and (2 -> auto-vacuum). The sole reason for this is so that it looks nicer | |
62 # when we use this variable as part of test-case names. | |
63 # | |
64 incr av | |
65 | |
66 # Test organization: | |
67 # | |
68 # shared-1.*: Simple test to verify basic sanity of table level locking when | |
69 # two connections share a pager cache. | |
70 # shared-2.*: Test that a read transaction can co-exist with a | |
71 # write-transaction, including a simple test to ensure the | |
72 # external locking protocol is still working. | |
73 # shared-3.*: Simple test of read-uncommitted mode. | |
74 # shared-4.*: Check that the schema is locked and unlocked correctly. | |
75 # shared-5.*: Test that creating/dropping schema items works when databases | |
76 # are attached in different orders to different handles. | |
77 # shared-6.*: Locking, UNION ALL queries and sub-queries. | |
78 # shared-7.*: Autovacuum and shared-cache. | |
79 # shared-8.*: Tests related to the text encoding of shared-cache databases. | |
80 # shared-9.*: TEMP triggers and shared-cache databases. | |
81 # shared-10.*: Tests of sqlite3_close(). | |
82 # shared-11.*: Test transaction locking. | |
83 # | |
84 | |
85 do_test shared-$av.1.1 { | |
86 # Open a second database on the file test.db. It should use the same pager | |
87 # cache and schema as the original connection. Verify that only 1 file is | |
88 # opened. | |
89 sqlite3 db2 test.db | |
90 set ::sqlite_open_file_count | |
91 expr $sqlite_open_file_count-$extrafds_postlock | |
92 } {1} | |
93 do_test shared-$av.1.2 { | |
94 # Add a table and a single row of data via the first connection. | |
95 # Ensure that the second connection can see them. | |
96 execsql { | |
97 CREATE TABLE abc(a, b, c); | |
98 INSERT INTO abc VALUES(1, 2, 3); | |
99 } db | |
100 execsql { | |
101 SELECT * FROM abc; | |
102 } db2 | |
103 } {1 2 3} | |
104 do_test shared-$av.1.3 { | |
105 # Have the first connection begin a transaction and obtain a read-lock | |
106 # on table abc. This should not prevent the second connection from | |
107 # querying abc. | |
108 execsql { | |
109 BEGIN; | |
110 SELECT * FROM abc; | |
111 } | |
112 execsql { | |
113 SELECT * FROM abc; | |
114 } db2 | |
115 } {1 2 3} | |
116 do_test shared-$av.1.4 { | |
117 # Try to insert a row into abc via connection 2. This should fail because | |
118 # of the read-lock connection 1 is holding on table abc (obtained in the | |
119 # previous test case). | |
120 catchsql { | |
121 INSERT INTO abc VALUES(4, 5, 6); | |
122 } db2 | |
123 } {1 {database table is locked: abc}} | |
124 do_test shared-$av.1.5 { | |
125 # Using connection 2 (the one without the open transaction), try to create | |
126 # a new table. This should fail because of the open read transaction | |
127 # held by connection 1. | |
128 catchsql { | |
129 CREATE TABLE def(d, e, f); | |
130 } db2 | |
131 } {1 {database table is locked: sqlite_master}} | |
132 do_test shared-$av.1.6 { | |
133 # Upgrade connection 1's transaction to a write transaction. Create | |
134 # a new table - def - and insert a row into it. Because the connection 1 | |
135 # transaction modifies the schema, it should not be possible for | |
136 # connection 2 to access the database at all until the connection 1 | |
137 # has finished the transaction. | |
138 execsql { | |
139 CREATE TABLE def(d, e, f); | |
140 INSERT INTO def VALUES('IV', 'V', 'VI'); | |
141 } | |
142 } {} | |
143 do_test shared-$av.1.7 { | |
144 # Read from the sqlite_master table with connection 1 (inside the | |
145 # transaction). Then test that we can not do this with connection 2. This | |
146 # is because of the schema-modified lock established by connection 1 | |
147 # in the previous test case. | |
148 execsql { | |
149 SELECT * FROM sqlite_master; | |
150 } | |
151 catchsql { | |
152 SELECT * FROM sqlite_master; | |
153 } db2 | |
154 } {1 {database schema is locked: main}} | |
155 do_test shared-$av.1.8 { | |
156 # Commit the connection 1 transaction. | |
157 execsql { | |
158 COMMIT; | |
159 } | |
160 } {} | |
161 | |
162 do_test shared-$av.2.1 { | |
163 # Open connection db3 to the database. Use a different path to the same | |
164 # file so that db3 does *not* share the same pager cache as db and db2 | |
165 # (there should be two open file handles). | |
166 if {$::tcl_platform(platform)=="unix"} { | |
167 sqlite3 db3 ./test.db | |
168 } else { | |
169 sqlite3 db3 TEST.DB | |
170 } | |
171 set ::sqlite_open_file_count | |
172 expr $sqlite_open_file_count-($extrafds_prelock+$extrafds_postlock) | |
173 } {2} | |
174 do_test shared-$av.2.2 { | |
175 # Start read transactions on db and db2 (the shared pager cache). Ensure | |
176 # db3 cannot write to the database. | |
177 execsql { | |
178 BEGIN; | |
179 SELECT * FROM abc; | |
180 } | |
181 execsql { | |
182 BEGIN; | |
183 SELECT * FROM abc; | |
184 } db2 | |
185 catchsql { | |
186 INSERT INTO abc VALUES(1, 2, 3); | |
187 } db2 | |
188 } {1 {database table is locked: abc}} | |
189 do_test shared-$av.2.3 { | |
190 # Turn db's transaction into a write-transaction. db3 should still be | |
191 # able to read from table def (but will not see the new row). Connection | |
192 # db2 should not be able to read def (because of the write-lock). | |
193 | |
194 # Todo: The failed "INSERT INTO abc ..." statement in the above test | |
195 # has started a write-transaction on db2 (should this be so?). This | |
196 # would prevent connection db from starting a write-transaction. So roll the | |
197 # db2 transaction back and replace it with a new read transaction. | |
198 execsql { | |
199 ROLLBACK; | |
200 BEGIN; | |
201 SELECT * FROM abc; | |
202 } db2 | |
203 | |
204 execsql { | |
205 INSERT INTO def VALUES('VII', 'VIII', 'IX'); | |
206 } | |
207 concat [ | |
208 catchsql { SELECT * FROM def; } db3 | |
209 ] [ | |
210 catchsql { SELECT * FROM def; } db2 | |
211 ] | |
212 } {0 {IV V VI} 1 {database table is locked: def}} | |
213 do_test shared-$av.2.4 { | |
214 # Commit the open transaction on db. db2 still holds a read-transaction. | |
215 # This should prevent db3 from writing to the database, but not from | |
216 # reading. | |
217 execsql { | |
218 COMMIT; | |
219 } | |
220 concat [ | |
221 catchsql { SELECT * FROM def; } db3 | |
222 ] [ | |
223 catchsql { INSERT INTO def VALUES('X', 'XI', 'XII'); } db3 | |
224 ] | |
225 } {0 {IV V VI VII VIII IX} 1 {database is locked}} | |
226 | |
227 catchsql COMMIT db2 | |
228 | |
229 do_test shared-$av.3.1.1 { | |
230 # This test case starts a linear scan of table 'seq' using a | |
231 # read-uncommitted connection. In the middle of the scan, rows are added | |
232 # to the end of the seq table (ahead of the current cursor position). | |
233 # The uncommitted rows should be included in the results of the scan. | |
234 execsql " | |
235 CREATE TABLE seq(i PRIMARY KEY, x); | |
236 INSERT INTO seq VALUES(1, '[string repeat X 500]'); | |
237 INSERT INTO seq VALUES(2, '[string repeat X 500]'); | |
238 " | |
239 execsql {SELECT * FROM sqlite_master} db2 | |
240 execsql {PRAGMA read_uncommitted = 1} db2 | |
241 | |
242 set ret [list] | |
243 db2 eval {SELECT i FROM seq ORDER BY i} { | |
244 if {$i < 4} { | |
245 set max [execsql {SELECT max(i) FROM seq}] | |
246 db eval { | |
247 INSERT INTO seq SELECT i + :max, x FROM seq; | |
248 } | |
249 } | |
250 lappend ret $i | |
251 } | |
252 set ret | |
253 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16} | |
254 do_test shared-$av.3.1.2 { | |
255 # Another linear scan through table seq using a read-uncommitted connection. | |
256 # This time, delete each row as it is read. Should not affect the results of | |
257 # the scan, but the table should be empty after the scan is concluded | |
258 # (test 3.1.3 verifies this). | |
259 set ret [list] | |
260 db2 eval {SELECT i FROM seq} { | |
261 db eval {DELETE FROM seq WHERE i = :i} | |
262 lappend ret $i | |
263 } | |
264 set ret | |
265 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16} | |
266 do_test shared-$av.3.1.3 { | |
267 execsql { | |
268 SELECT * FROM seq; | |
269 } | |
270 } {} | |
271 | |
272 catch {db close} | |
273 catch {db2 close} | |
274 catch {db3 close} | |
275 | |
276 #-------------------------------------------------------------------------- | |
277 # Tests shared-4.* test that the schema locking rules are applied | |
278 # correctly. i.e.: | |
279 # | |
280 # 1. All transactions require a read-lock on the schemas of databases they | |
281 # access. | |
282 # 2. Transactions that modify a database schema require a write-lock on that | |
283 # schema. | |
284 # 3. It is not possible to compile a statement while another handle has a | |
285 # write-lock on the schema. | |
286 # | |
287 | |
288 # Open two database handles db and db2. Each has a single attach database | |
289 # (as well as main): | |
290 # | |
291 # db.main -> ./test.db | |
292 # db.test2 -> ./test2.db | |
293 # db2.main -> ./test2.db | |
294 # db2.test -> ./test.db | |
295 # | |
296 forcedelete test.db | |
297 forcedelete test2.db | |
298 forcedelete test2.db-journal | |
299 sqlite3 db test.db | |
300 sqlite3 db2 test2.db | |
301 do_test shared-$av.4.1.1 { | |
302 set sqlite_open_file_count | |
303 expr $sqlite_open_file_count-($extrafds_prelock*2) | |
304 } {2} | |
305 do_test shared-$av.4.1.2 { | |
306 execsql {ATTACH 'test2.db' AS test2} | |
307 set sqlite_open_file_count | |
308 expr $sqlite_open_file_count-($extrafds_postlock*2) | |
309 } {2} | |
310 do_test shared-$av.4.1.3 { | |
311 execsql {ATTACH 'test.db' AS test} db2 | |
312 set sqlite_open_file_count | |
313 expr $sqlite_open_file_count-($extrafds_postlock*2) | |
314 } {2} | |
315 | |
316 # Sanity check: Create a table in ./test.db via handle db, and test that handle | |
317 # db2 can "see" the new table immediately. A handle using a seperate pager | |
318 # cache would have to reload the database schema before this were possible. | |
319 # | |
320 do_test shared-$av.4.2.1 { | |
321 execsql { | |
322 CREATE TABLE abc(a, b, c); | |
323 CREATE TABLE def(d, e, f); | |
324 INSERT INTO abc VALUES('i', 'ii', 'iii'); | |
325 INSERT INTO def VALUES('I', 'II', 'III'); | |
326 } | |
327 } {} | |
328 do_test shared-$av.4.2.2 { | |
329 execsql { | |
330 SELECT * FROM test.abc; | |
331 } db2 | |
332 } {i ii iii} | |
333 | |
334 # Open a read-transaction and read from table abc via handle 2. Check that | |
335 # handle 1 can read table abc. Check that handle 1 cannot modify table abc | |
336 # or the database schema. Then check that handle 1 can modify table def. | |
337 # | |
338 do_test shared-$av.4.3.1 { | |
339 execsql { | |
340 BEGIN; | |
341 SELECT * FROM test.abc; | |
342 } db2 | |
343 } {i ii iii} | |
344 do_test shared-$av.4.3.2 { | |
345 catchsql { | |
346 INSERT INTO abc VALUES('iv', 'v', 'vi'); | |
347 } | |
348 } {1 {database table is locked: abc}} | |
349 do_test shared-$av.4.3.3 { | |
350 catchsql { | |
351 CREATE TABLE ghi(g, h, i); | |
352 } | |
353 } {1 {database table is locked: sqlite_master}} | |
354 do_test shared-$av.4.3.3 { | |
355 catchsql { | |
356 INSERT INTO def VALUES('IV', 'V', 'VI'); | |
357 } | |
358 } {0 {}} | |
359 do_test shared-$av.4.3.4 { | |
360 # Cleanup: commit the transaction opened by db2. | |
361 execsql { | |
362 COMMIT | |
363 } db2 | |
364 } {} | |
365 | |
366 # Open a write-transaction using handle 1 and modify the database schema. | |
367 # Then try to execute a compiled statement to read from the same | |
368 # database via handle 2 (fails to get the lock on sqlite_master). Also | |
369 # try to compile a read of the same database using handle 2 (also fails). | |
370 # Finally, compile a read of the other database using handle 2. This | |
371 # should also fail. | |
372 # | |
373 ifcapable compound { | |
374 do_test shared-$av.4.4.1.2 { | |
375 # Sanity check 1: Check that the schema is what we think it is when viewed | |
376 # via handle 1. | |
377 execsql { | |
378 CREATE TABLE test2.ghi(g, h, i); | |
379 SELECT 'test.db:'||name FROM sqlite_master | |
380 UNION ALL | |
381 SELECT 'test2.db:'||name FROM test2.sqlite_master; | |
382 } | |
383 } {test.db:abc test.db:def test2.db:ghi} | |
384 do_test shared-$av.4.4.1.2 { | |
385 # Sanity check 2: Check that the schema is what we think it is when viewed | |
386 # via handle 2. | |
387 execsql { | |
388 SELECT 'test2.db:'||name FROM sqlite_master | |
389 UNION ALL | |
390 SELECT 'test.db:'||name FROM test.sqlite_master; | |
391 } db2 | |
392 } {test2.db:ghi test.db:abc test.db:def} | |
393 } | |
394 | |
395 do_test shared-$av.4.4.2 { | |
396 set ::DB2 [sqlite3_connection_pointer db2] | |
397 set sql {SELECT * FROM abc} | |
398 set ::STMT1 [sqlite3_prepare $::DB2 $sql -1 DUMMY] | |
399 execsql { | |
400 BEGIN; | |
401 CREATE TABLE jkl(j, k, l); | |
402 } | |
403 sqlite3_step $::STMT1 | |
404 } {SQLITE_ERROR} | |
405 do_test shared-$av.4.4.3 { | |
406 sqlite3_finalize $::STMT1 | |
407 } {SQLITE_LOCKED} | |
408 do_test shared-$av.4.4.4 { | |
409 set rc [catch { | |
410 set ::STMT1 [sqlite3_prepare $::DB2 $sql -1 DUMMY] | |
411 } msg] | |
412 list $rc $msg | |
413 } {1 {(6) database schema is locked: test}} | |
414 do_test shared-$av.4.4.5 { | |
415 set rc [catch { | |
416 set ::STMT1 [sqlite3_prepare $::DB2 "SELECT * FROM ghi" -1 DUMMY] | |
417 } msg] | |
418 list $rc $msg | |
419 } {1 {(6) database schema is locked: test}} | |
420 | |
421 | |
422 catch {db2 close} | |
423 catch {db close} | |
424 | |
425 #-------------------------------------------------------------------------- | |
426 # Tests shared-5.* | |
427 # | |
428 foreach db [list test.db test1.db test2.db test3.db] { | |
429 forcedelete $db ${db}-journal | |
430 } | |
431 do_test shared-$av.5.1.1 { | |
432 sqlite3 db1 test.db | |
433 sqlite3 db2 test.db | |
434 execsql { | |
435 ATTACH 'test1.db' AS test1; | |
436 ATTACH 'test2.db' AS test2; | |
437 ATTACH 'test3.db' AS test3; | |
438 } db1 | |
439 execsql { | |
440 ATTACH 'test3.db' AS test3; | |
441 ATTACH 'test2.db' AS test2; | |
442 ATTACH 'test1.db' AS test1; | |
443 } db2 | |
444 } {} | |
445 do_test shared-$av.5.1.2 { | |
446 execsql { | |
447 CREATE TABLE test1.t1(a, b); | |
448 CREATE INDEX test1.i1 ON t1(a, b); | |
449 } db1 | |
450 } {} | |
451 ifcapable view { | |
452 do_test shared-$av.5.1.3 { | |
453 execsql { | |
454 CREATE VIEW test1.v1 AS SELECT * FROM t1; | |
455 } db1 | |
456 } {} | |
457 } | |
458 ifcapable trigger { | |
459 do_test shared-$av.5.1.4 { | |
460 execsql { | |
461 CREATE TRIGGER test1.trig1 AFTER INSERT ON t1 BEGIN | |
462 INSERT INTO t1 VALUES(new.a, new.b); | |
463 END; | |
464 } db1 | |
465 } {} | |
466 } | |
467 do_test shared-$av.5.1.5 { | |
468 execsql { | |
469 DROP INDEX i1; | |
470 } db2 | |
471 } {} | |
472 ifcapable view { | |
473 do_test shared-$av.5.1.6 { | |
474 execsql { | |
475 DROP VIEW v1; | |
476 } db2 | |
477 } {} | |
478 } | |
479 ifcapable trigger { | |
480 do_test shared-$av.5.1.7 { | |
481 execsql { | |
482 DROP TRIGGER trig1; | |
483 } db2 | |
484 } {} | |
485 } | |
486 do_test shared-$av.5.1.8 { | |
487 execsql { | |
488 DROP TABLE t1; | |
489 } db2 | |
490 } {} | |
491 ifcapable compound { | |
492 do_test shared-$av.5.1.9 { | |
493 execsql { | |
494 SELECT * FROM sqlite_master UNION ALL SELECT * FROM test1.sqlite_master | |
495 } db1 | |
496 } {} | |
497 } | |
498 | |
499 #-------------------------------------------------------------------------- | |
500 # Tests shared-6.* test that a query obtains all the read-locks it needs | |
501 # before starting execution of the query. This means that there is no chance | |
502 # some rows of data will be returned before a lock fails and SQLITE_LOCK | |
503 # is returned. | |
504 # | |
505 do_test shared-$av.6.1.1 { | |
506 execsql { | |
507 CREATE TABLE t1(a, b); | |
508 CREATE TABLE t2(a, b); | |
509 INSERT INTO t1 VALUES(1, 2); | |
510 INSERT INTO t2 VALUES(3, 4); | |
511 } db1 | |
512 } {} | |
513 ifcapable compound { | |
514 do_test shared-$av.6.1.2 { | |
515 execsql { | |
516 SELECT * FROM t1 UNION ALL SELECT * FROM t2; | |
517 } db2 | |
518 } {1 2 3 4} | |
519 } | |
520 do_test shared-$av.6.1.3 { | |
521 # Establish a write lock on table t2 via connection db2. Then make a | |
522 # UNION all query using connection db1 that first accesses t1, followed | |
523 # by t2. If the locks are grabbed at the start of the statement (as | |
524 # they should be), no rows are returned. If (as was previously the case) | |
525 # they are grabbed as the tables are accessed, the t1 rows will be | |
526 # returned before the query fails. | |
527 # | |
528 execsql { | |
529 BEGIN; | |
530 INSERT INTO t2 VALUES(5, 6); | |
531 } db2 | |
532 set ret [list] | |
533 catch { | |
534 db1 eval {SELECT * FROM t1 UNION ALL SELECT * FROM t2} { | |
535 lappend ret $a $b | |
536 } | |
537 } | |
538 set ret | |
539 } {} | |
540 do_test shared-$av.6.1.4 { | |
541 execsql { | |
542 COMMIT; | |
543 BEGIN; | |
544 INSERT INTO t1 VALUES(7, 8); | |
545 } db2 | |
546 set ret [list] | |
547 catch { | |
548 db1 eval { | |
549 SELECT (CASE WHEN a>4 THEN (SELECT a FROM t1) ELSE 0 END) AS d FROM t2; | |
550 } { | |
551 lappend ret $d | |
552 } | |
553 } | |
554 set ret | |
555 } {} | |
556 | |
557 catch {db1 close} | |
558 catch {db2 close} | |
559 foreach f [list test.db test2.db] { | |
560 forcedelete $f ${f}-journal | |
561 } | |
562 | |
563 #-------------------------------------------------------------------------- | |
564 # Tests shared-7.* test auto-vacuum does not invalidate cursors from | |
565 # other shared-cache users when it reorganizes the database on | |
566 # COMMIT. | |
567 # | |
568 do_test shared-$av.7.1 { | |
569 # This test case sets up a test database in auto-vacuum mode consisting | |
570 # of two tables, t1 and t2. Both have a single index. Table t1 is | |
571 # populated first (so consists of pages toward the start of the db file), | |
572 # t2 second (pages toward the end of the file). | |
573 sqlite3 db test.db | |
574 sqlite3 db2 test.db | |
575 execsql { | |
576 BEGIN; | |
577 CREATE TABLE t1(a PRIMARY KEY, b); | |
578 CREATE TABLE t2(a PRIMARY KEY, b); | |
579 } | |
580 set ::contents {} | |
581 for {set i 0} {$i < 100} {incr i} { | |
582 set a [string repeat "$i " 20] | |
583 set b [string repeat "$i " 20] | |
584 db eval { | |
585 INSERT INTO t1 VALUES(:a, :b); | |
586 } | |
587 lappend ::contents [list [expr $i+1] $a $b] | |
588 } | |
589 execsql { | |
590 INSERT INTO t2 SELECT * FROM t1; | |
591 COMMIT; | |
592 } | |
593 } {} | |
594 do_test shared-$av.7.2 { | |
595 # This test case deletes the contents of table t1 (the one at the start of | |
596 # the file) while many cursors are open on table t2 and its index. All of | |
597 # the non-root pages will be moved from the end to the start of the file | |
598 # when the DELETE is committed - this test verifies that moving the pages | |
599 # does not disturb the open cursors. | |
600 # | |
601 | |
602 proc lockrow {db tbl oids body} { | |
603 set ret [list] | |
604 db eval "SELECT oid AS i, a, b FROM $tbl ORDER BY a" { | |
605 if {$i==[lindex $oids 0]} { | |
606 set noids [lrange $oids 1 end] | |
607 if {[llength $noids]==0} { | |
608 set subret [eval $body] | |
609 } else { | |
610 set subret [lockrow $db $tbl $noids $body] | |
611 } | |
612 } | |
613 lappend ret [list $i $a $b] | |
614 } | |
615 return [linsert $subret 0 $ret] | |
616 } | |
617 proc locktblrows {db tbl body} { | |
618 set oids [db eval "SELECT oid FROM $tbl"] | |
619 lockrow $db $tbl $oids $body | |
620 } | |
621 | |
622 set scans [locktblrows db t2 { | |
623 execsql { | |
624 DELETE FROM t1; | |
625 } db2 | |
626 }] | |
627 set error 0 | |
628 | |
629 # Test that each SELECT query returned the expected contents of t2. | |
630 foreach s $scans { | |
631 if {[lsort -integer -index 0 $s]!=$::contents} { | |
632 set error 1 | |
633 } | |
634 } | |
635 set error | |
636 } {0} | |
637 | |
638 catch {db close} | |
639 catch {db2 close} | |
640 unset -nocomplain contents | |
641 | |
642 #-------------------------------------------------------------------------- | |
643 # The following tests try to trick the shared-cache code into assuming | |
644 # the wrong encoding for a database. | |
645 # | |
646 forcedelete test.db test.db-journal | |
647 ifcapable utf16 { | |
648 do_test shared-$av.8.1.1 { | |
649 sqlite3 db test.db | |
650 execsql { | |
651 PRAGMA encoding = 'UTF-16'; | |
652 SELECT * FROM sqlite_master; | |
653 } | |
654 } {} | |
655 do_test shared-$av.8.1.2 { | |
656 string range [execsql {PRAGMA encoding;}] 0 end-2 | |
657 } {UTF-16} | |
658 | |
659 do_test shared-$av.8.1.3 { | |
660 sqlite3 db2 test.db | |
661 execsql { | |
662 PRAGMA encoding = 'UTF-8'; | |
663 CREATE TABLE abc(a, b, c); | |
664 } db2 | |
665 } {} | |
666 do_test shared-$av.8.1.4 { | |
667 execsql { | |
668 SELECT * FROM sqlite_master; | |
669 } | |
670 } "table abc abc [expr $AUTOVACUUM?3:2] {CREATE TABLE abc(a, b, c)}" | |
671 do_test shared-$av.8.1.5 { | |
672 db2 close | |
673 execsql { | |
674 PRAGMA encoding; | |
675 } | |
676 } {UTF-8} | |
677 | |
678 forcedelete test2.db test2.db-journal | |
679 do_test shared-$av.8.2.1 { | |
680 execsql { | |
681 ATTACH 'test2.db' AS aux; | |
682 SELECT * FROM aux.sqlite_master; | |
683 } | |
684 } {} | |
685 do_test shared-$av.8.2.2 { | |
686 sqlite3 db2 test2.db | |
687 execsql { | |
688 PRAGMA encoding = 'UTF-16'; | |
689 CREATE TABLE def(d, e, f); | |
690 } db2 | |
691 string range [execsql {PRAGMA encoding;} db2] 0 end-2 | |
692 } {UTF-16} | |
693 | |
694 catch {db close} | |
695 catch {db2 close} | |
696 forcedelete test.db test2.db | |
697 | |
698 do_test shared-$av.8.3.2 { | |
699 sqlite3 db test.db | |
700 execsql { CREATE TABLE def(d, e, f) } | |
701 execsql { PRAGMA encoding } | |
702 } {UTF-8} | |
703 do_test shared-$av.8.3.3 { | |
704 set zDb16 "[encoding convertto unicode test.db]\x00\x00" | |
705 set db16 [sqlite3_open16 $zDb16 {}] | |
706 | |
707 set stmt [sqlite3_prepare $db16 "SELECT sql FROM sqlite_master" -1 DUMMY] | |
708 sqlite3_step $stmt | |
709 set sql [sqlite3_column_text $stmt 0] | |
710 sqlite3_finalize $stmt | |
711 set sql | |
712 } {CREATE TABLE def(d, e, f)} | |
713 do_test shared-$av.8.3.4 { | |
714 set stmt [sqlite3_prepare $db16 "PRAGMA encoding" -1 DUMMY] | |
715 sqlite3_step $stmt | |
716 set enc [sqlite3_column_text $stmt 0] | |
717 sqlite3_finalize $stmt | |
718 set enc | |
719 } {UTF-8} | |
720 | |
721 sqlite3_close $db16 | |
722 | |
723 # Bug #2547 is causing this to fail. | |
724 if 0 { | |
725 do_test shared-$av.8.2.3 { | |
726 catchsql { | |
727 SELECT * FROM aux.sqlite_master; | |
728 } | |
729 } {1 {attached databases must use the same text encoding as main database}} | |
730 } | |
731 } | |
732 | |
733 catch {db close} | |
734 catch {db2 close} | |
735 forcedelete test.db test2.db | |
736 | |
737 #--------------------------------------------------------------------------- | |
738 # The following tests - shared-9.* - test interactions between TEMP triggers | |
739 # and shared-schemas. | |
740 # | |
741 ifcapable trigger&&tempdb { | |
742 | |
743 do_test shared-$av.9.1 { | |
744 sqlite3 db test.db | |
745 sqlite3 db2 test.db | |
746 execsql { | |
747 CREATE TABLE abc(a, b, c); | |
748 CREATE TABLE abc_mirror(a, b, c); | |
749 CREATE TEMP TRIGGER BEFORE INSERT ON abc BEGIN | |
750 INSERT INTO abc_mirror(a, b, c) VALUES(new.a, new.b, new.c); | |
751 END; | |
752 INSERT INTO abc VALUES(1, 2, 3); | |
753 SELECT * FROM abc_mirror; | |
754 } | |
755 } {1 2 3} | |
756 do_test shared-$av.9.2 { | |
757 execsql { | |
758 INSERT INTO abc VALUES(4, 5, 6); | |
759 SELECT * FROM abc_mirror; | |
760 } db2 | |
761 } {1 2 3} | |
762 do_test shared-$av.9.3 { | |
763 db close | |
764 db2 close | |
765 } {} | |
766 | |
767 } ; # End shared-9.* | |
768 | |
769 #--------------------------------------------------------------------------- | |
770 # The following tests - shared-10.* - test that the library behaves | |
771 # correctly when a connection to a shared-cache is closed. | |
772 # | |
773 do_test shared-$av.10.1 { | |
774 # Create a small sample database with two connections to it (db and db2). | |
775 forcedelete test.db | |
776 sqlite3 db test.db | |
777 sqlite3 db2 test.db | |
778 execsql { | |
779 CREATE TABLE ab(a PRIMARY KEY, b); | |
780 CREATE TABLE de(d PRIMARY KEY, e); | |
781 INSERT INTO ab VALUES('Chiang Mai', 100000); | |
782 INSERT INTO ab VALUES('Bangkok', 8000000); | |
783 INSERT INTO de VALUES('Ubon', 120000); | |
784 INSERT INTO de VALUES('Khon Kaen', 200000); | |
785 } | |
786 } {} | |
787 do_test shared-$av.10.2 { | |
788 # Open a read-transaction with the first connection, a write-transaction | |
789 # with the second. | |
790 execsql { | |
791 BEGIN; | |
792 SELECT * FROM ab; | |
793 } | |
794 execsql { | |
795 BEGIN; | |
796 INSERT INTO de VALUES('Pataya', 30000); | |
797 } db2 | |
798 } {} | |
799 do_test shared-$av.10.3 { | |
800 # An external connection should be able to read the database, but not | |
801 # prepare a write operation. | |
802 if {$::tcl_platform(platform)=="unix"} { | |
803 sqlite3 db3 ./test.db | |
804 } else { | |
805 sqlite3 db3 TEST.DB | |
806 } | |
807 execsql { | |
808 SELECT * FROM ab; | |
809 } db3 | |
810 catchsql { | |
811 BEGIN; | |
812 INSERT INTO de VALUES('Pataya', 30000); | |
813 } db3 | |
814 } {1 {database is locked}} | |
815 do_test shared-$av.10.4 { | |
816 # Close the connection with the write-transaction open | |
817 db2 close | |
818 } {} | |
819 do_test shared-$av.10.5 { | |
820 # Test that the db2 transaction has been automatically rolled back. | |
821 # If it has not the ('Pataya', 30000) entry will still be in the table. | |
822 execsql { | |
823 SELECT * FROM de; | |
824 } | |
825 } {Ubon 120000 {Khon Kaen} 200000} | |
826 do_test shared-$av.10.5 { | |
827 # Closing db2 should have dropped the shared-cache back to a read-lock. | |
828 # So db3 should be able to prepare a write... | |
829 catchsql {INSERT INTO de VALUES('Pataya', 30000);} db3 | |
830 } {0 {}} | |
831 do_test shared-$av.10.6 { | |
832 # ... but not commit it. | |
833 catchsql {COMMIT} db3 | |
834 } {1 {database is locked}} | |
835 do_test shared-$av.10.7 { | |
836 # Commit the (read-only) db transaction. Check via db3 to make sure the | |
837 # contents of table "de" are still as they should be. | |
838 execsql { | |
839 COMMIT; | |
840 } | |
841 execsql { | |
842 SELECT * FROM de; | |
843 } db3 | |
844 } {Ubon 120000 {Khon Kaen} 200000 Pataya 30000} | |
845 do_test shared-$av.10.9 { | |
846 # Commit the external transaction. | |
847 catchsql {COMMIT} db3 | |
848 } {0 {}} | |
849 integrity_check shared-$av.10.10 | |
850 do_test shared-$av.10.11 { | |
851 db close | |
852 db3 close | |
853 } {} | |
854 | |
855 do_test shared-$av.11.1 { | |
856 forcedelete test.db | |
857 sqlite3 db test.db | |
858 sqlite3 db2 test.db | |
859 execsql { | |
860 CREATE TABLE abc(a, b, c); | |
861 CREATE TABLE abc2(a, b, c); | |
862 BEGIN; | |
863 INSERT INTO abc VALUES(1, 2, 3); | |
864 } | |
865 } {} | |
866 do_test shared-$av.11.2 { | |
867 catchsql {BEGIN;} db2 | |
868 catchsql {SELECT * FROM abc;} db2 | |
869 } {1 {database table is locked: abc}} | |
870 do_test shared-$av.11.3 { | |
871 catchsql {BEGIN} db2 | |
872 } {1 {cannot start a transaction within a transaction}} | |
873 do_test shared-$av.11.4 { | |
874 catchsql {SELECT * FROM abc2;} db2 | |
875 } {0 {}} | |
876 do_test shared-$av.11.5 { | |
877 catchsql {INSERT INTO abc2 VALUES(1, 2, 3);} db2 | |
878 } {1 {database table is locked}} | |
879 do_test shared-$av.11.6 { | |
880 catchsql {SELECT * FROM abc2} | |
881 } {0 {}} | |
882 do_test shared-$av.11.6 { | |
883 execsql { | |
884 ROLLBACK; | |
885 PRAGMA read_uncommitted = 1; | |
886 } db2 | |
887 } {} | |
888 do_test shared-$av.11.7 { | |
889 execsql { | |
890 INSERT INTO abc2 VALUES(4, 5, 6); | |
891 INSERT INTO abc2 VALUES(7, 8, 9); | |
892 } | |
893 } {} | |
894 do_test shared-$av.11.8 { | |
895 set res [list] | |
896 db2 eval { | |
897 SELECT abc.a as I, abc2.a as II FROM abc, abc2; | |
898 } { | |
899 execsql { | |
900 DELETE FROM abc WHERE 1; | |
901 } | |
902 lappend res $I $II | |
903 } | |
904 set res | |
905 } {1 4 {} 7} | |
906 if {[llength [info command sqlite3_shared_cache_report]]==1} { | |
907 ifcapable curdir { | |
908 do_test shared-$av.11.9 { | |
909 string tolower [sqlite3_shared_cache_report] | |
910 } [string tolower [list [file nativename [file normalize test.db]] 2]] | |
911 } | |
912 } | |
913 | |
914 do_test shared-$av.11.11 { | |
915 db close | |
916 db2 close | |
917 } {} | |
918 | |
919 # This tests that if it is impossible to free any pages, SQLite will | |
920 # exceed the limit set by PRAGMA cache_size. | |
921 forcedelete test.db test.db-journal | |
922 sqlite3 db test.db | |
923 ifcapable pager_pragmas { | |
924 do_test shared-$av.12.1 { | |
925 execsql { | |
926 PRAGMA cache_size = 10; | |
927 PRAGMA cache_size; | |
928 } | |
929 } {10} | |
930 } | |
931 do_test shared-$av.12.2 { | |
932 set ::db_handles [list] | |
933 for {set i 1} {$i < 15} {incr i} { | |
934 lappend ::db_handles db$i | |
935 sqlite3 db$i test.db | |
936 execsql "CREATE TABLE db${i}(a, b, c)" db$i | |
937 execsql "INSERT INTO db${i} VALUES(1, 2, 3)" | |
938 } | |
939 } {} | |
940 proc nested_select {handles} { | |
941 [lindex $handles 0] eval "SELECT * FROM [lindex $handles 0]" { | |
942 lappend ::res $a $b $c | |
943 if {[llength $handles]>1} { | |
944 nested_select [lrange $handles 1 end] | |
945 } | |
946 } | |
947 } | |
948 do_test shared-$av.12.3 { | |
949 set ::res [list] | |
950 nested_select $::db_handles | |
951 set ::res | |
952 } [string range [string repeat "1 2 3 " [llength $::db_handles]] 0 end-1] | |
953 | |
954 do_test shared-$av.12.X { | |
955 db close | |
956 foreach h $::db_handles { | |
957 $h close | |
958 } | |
959 } {} | |
960 | |
961 # Internally, locks are acquired on shared B-Tree structures in the order | |
962 # that the structures appear in the virtual memory address space. This | |
963 # test case attempts to cause the order of the structures in memory | |
964 # to be different from the order in which they are attached to a given | |
965 # database handle. This covers an extra line or two. | |
966 # | |
967 do_test shared-$av.13.1 { | |
968 forcedelete test2.db test3.db test4.db test5.db | |
969 sqlite3 db :memory: | |
970 execsql { | |
971 ATTACH 'test2.db' AS aux2; | |
972 ATTACH 'test3.db' AS aux3; | |
973 ATTACH 'test4.db' AS aux4; | |
974 ATTACH 'test5.db' AS aux5; | |
975 DETACH aux2; | |
976 DETACH aux3; | |
977 DETACH aux4; | |
978 ATTACH 'test2.db' AS aux2; | |
979 ATTACH 'test3.db' AS aux3; | |
980 ATTACH 'test4.db' AS aux4; | |
981 } | |
982 } {} | |
983 do_test shared-$av.13.2 { | |
984 execsql { | |
985 CREATE TABLE t1(a, b, c); | |
986 CREATE TABLE aux2.t2(a, b, c); | |
987 CREATE TABLE aux3.t3(a, b, c); | |
988 CREATE TABLE aux4.t4(a, b, c); | |
989 CREATE TABLE aux5.t5(a, b, c); | |
990 SELECT count(*) FROM | |
991 aux2.sqlite_master, | |
992 aux3.sqlite_master, | |
993 aux4.sqlite_master, | |
994 aux5.sqlite_master | |
995 } | |
996 } {1} | |
997 do_test shared-$av.13.3 { | |
998 db close | |
999 } {} | |
1000 | |
1001 # Test that nothing horrible happens if a connection to a shared B-Tree | |
1002 # structure is closed while some other connection has an open cursor. | |
1003 # | |
1004 do_test shared-$av.14.1 { | |
1005 sqlite3 db test.db | |
1006 sqlite3 db2 test.db | |
1007 execsql {SELECT name FROM sqlite_master} | |
1008 } {db1 db2 db3 db4 db5 db6 db7 db8 db9 db10 db11 db12 db13 db14} | |
1009 do_test shared-$av.14.2 { | |
1010 set res [list] | |
1011 db eval {SELECT name FROM sqlite_master} { | |
1012 if {$name eq "db7"} { | |
1013 db2 close | |
1014 } | |
1015 lappend res $name | |
1016 } | |
1017 set res | |
1018 } {db1 db2 db3 db4 db5 db6 db7 db8 db9 db10 db11 db12 db13 db14} | |
1019 do_test shared-$av.14.3 { | |
1020 db close | |
1021 } {} | |
1022 | |
1023 # Populate a database schema using connection [db]. Then drop it using | |
1024 # [db2]. This is to try to find any points where shared-schema elements | |
1025 # are allocated using the lookaside buffer of [db]. | |
1026 # | |
1027 # Mutexes are enabled for this test as that activates a couple of useful | |
1028 # assert() statements in the C code. | |
1029 # | |
1030 do_test shared-$av-15.1 { | |
1031 forcedelete test.db | |
1032 sqlite3 db test.db -fullmutex 1 | |
1033 sqlite3 db2 test.db -fullmutex 1 | |
1034 execsql { | |
1035 CREATE TABLE t1(a, b, c); | |
1036 CREATE INDEX i1 ON t1(a, b); | |
1037 CREATE VIEW v1 AS SELECT * FROM t1; | |
1038 CREATE VIEW v2 AS SELECT * FROM t1, v1 | |
1039 WHERE t1.c=v1.c GROUP BY t1.a ORDER BY v1.b; | |
1040 CREATE TRIGGER tr1 AFTER INSERT ON t1 | |
1041 WHEN new.a!=1 | |
1042 BEGIN | |
1043 DELETE FROM t1 WHERE a=5; | |
1044 INSERT INTO t1 VALUES(1, 2, 3); | |
1045 UPDATE t1 SET c=c+1; | |
1046 END; | |
1047 | |
1048 INSERT INTO t1 VALUES(5, 6, 7); | |
1049 INSERT INTO t1 VALUES(8, 9, 10); | |
1050 INSERT INTO t1 VALUES(11, 12, 13); | |
1051 ANALYZE; | |
1052 SELECT * FROM t1; | |
1053 } | |
1054 } {1 2 6 8 9 12 1 2 5 11 12 14 1 2 4} | |
1055 do_test shared-$av-15.2 { | |
1056 execsql { DROP TABLE t1 } db2 | |
1057 } {} | |
1058 db close | |
1059 db2 close | |
1060 | |
1061 # Shared cache on a :memory: database. This only works for URI filenames. | |
1062 # | |
1063 do_test shared-$av-16.1 { | |
1064 sqlite3 db1 file::memory: -uri 1 | |
1065 sqlite3 db2 file::memory: -uri 1 | |
1066 db1 eval { | |
1067 CREATE TABLE t1(x); INSERT INTO t1 VALUES(1),(2),(3); | |
1068 } | |
1069 db2 eval { | |
1070 SELECT x FROM t1 ORDER BY x; | |
1071 } | |
1072 } {1 2 3} | |
1073 do_test shared-$av-16.2 { | |
1074 db2 eval { | |
1075 INSERT INTO t1 VALUES(99); | |
1076 DELETE FROM t1 WHERE x=2; | |
1077 } | |
1078 db1 eval { | |
1079 SELECT x FROM t1 ORDER BY x; | |
1080 } | |
1081 } {1 3 99} | |
1082 | |
1083 # Verify that there is no cache sharing ordinary (non-URI) filenames are | |
1084 # used. | |
1085 # | |
1086 do_test shared-$av-16.3 { | |
1087 db1 close | |
1088 db2 close | |
1089 sqlite3 db1 :memory: | |
1090 sqlite3 db2 :memory: | |
1091 db1 eval { | |
1092 CREATE TABLE t1(x); INSERT INTO t1 VALUES(4),(5),(6); | |
1093 } | |
1094 catchsql { | |
1095 SELECT * FROM t1; | |
1096 } db2 | |
1097 } {1 {no such table: t1}} | |
1098 | |
1099 # Shared cache on named memory databases. | |
1100 # | |
1101 do_test shared-$av-16.4 { | |
1102 db1 close | |
1103 db2 close | |
1104 forcedelete test.db test.db-wal test.db-journal | |
1105 sqlite3 db1 file:test.db?mode=memory -uri 1 | |
1106 sqlite3 db2 file:test.db?mode=memory -uri 1 | |
1107 db1 eval { | |
1108 CREATE TABLE t1(x); INSERT INTO t1 VALUES(1),(2),(3); | |
1109 } | |
1110 db2 eval { | |
1111 SELECT x FROM t1 ORDER BY x; | |
1112 } | |
1113 } {1 2 3} | |
1114 do_test shared-$av-16.5 { | |
1115 db2 eval { | |
1116 INSERT INTO t1 VALUES(99); | |
1117 DELETE FROM t1 WHERE x=2; | |
1118 } | |
1119 db1 eval { | |
1120 SELECT x FROM t1 ORDER BY x; | |
1121 } | |
1122 } {1 3 99} | |
1123 do_test shared-$av-16.6 { | |
1124 file exists test.db | |
1125 } {0} ;# Verify that the database is in-memory | |
1126 | |
1127 # Shared cache on named memory databases with different names. | |
1128 # | |
1129 do_test shared-$av-16.7 { | |
1130 db1 close | |
1131 db2 close | |
1132 forcedelete test1.db test2.db | |
1133 sqlite3 db1 file:test1.db?mode=memory -uri 1 | |
1134 sqlite3 db2 file:test2.db?mode=memory -uri 1 | |
1135 db1 eval { | |
1136 CREATE TABLE t1(x); INSERT INTO t1 VALUES(1),(2),(3); | |
1137 } | |
1138 catchsql { | |
1139 SELECT x FROM t1 ORDER BY x; | |
1140 } db2 | |
1141 } {1 {no such table: t1}} | |
1142 do_test shared-$av-16.8 { | |
1143 file exists test1.db | |
1144 } {0} ;# Verify that the database is in-memory | |
1145 | |
1146 # Shared cache on named memory databases attached to readonly connections. | |
1147 # | |
1148 do_test shared-$av-16.8.1 { | |
1149 db1 close | |
1150 db2 close | |
1151 | |
1152 sqlite3 db test1.db | |
1153 db eval { | |
1154 CREATE TABLE yy(a, b); | |
1155 INSERT INTO yy VALUES(77, 88); | |
1156 } | |
1157 db close | |
1158 | |
1159 sqlite3 db1 test1.db -uri 1 -readonly 1 | |
1160 sqlite3 db2 test2.db -uri 1 | |
1161 | |
1162 db1 eval { | |
1163 ATTACH 'file:mem?mode=memory&cache=shared' AS shared; | |
1164 CREATE TABLE shared.xx(a, b); | |
1165 INSERT INTO xx VALUES(55, 66); | |
1166 } | |
1167 db2 eval { | |
1168 ATTACH 'file:mem?mode=memory&cache=shared' AS shared; | |
1169 SELECT * FROM xx; | |
1170 } | |
1171 } {55 66} | |
1172 | |
1173 do_test shared-$av-16.8.2 { db1 eval { SELECT * FROM yy } } {77 88} | |
1174 do_test shared-$av-16.8.3 { | |
1175 list [catch {db1 eval { INSERT INTO yy VALUES(1, 2) }} msg] $msg | |
1176 } {1 {attempt to write a readonly database}} | |
1177 | |
1178 db1 close | |
1179 db2 close | |
1180 | |
1181 } ;# end of autovacuum on/off loop | |
1182 | |
1183 sqlite3_enable_shared_cache $::enable_shared_cache | |
1184 finish_test | |
OLD | NEW |