OLD | NEW |
| (Empty) |
1 # 2008 December 15 | |
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: savepoint.test,v 1.13 2009/07/18 08:30:45 danielk1977 Exp $ | |
13 | |
14 set testdir [file dirname $argv0] | |
15 source $testdir/tester.tcl | |
16 source $testdir/lock_common.tcl | |
17 source $testdir/malloc_common.tcl | |
18 | |
19 #---------------------------------------------------------------------- | |
20 # The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE | |
21 # and ROLLBACK TO comands are correctly parsed, and that the auto-commit | |
22 # flag is correctly set and unset as a result. | |
23 # | |
24 do_test savepoint-1.1 { | |
25 wal_set_journal_mode | |
26 execsql { | |
27 SAVEPOINT sp1; | |
28 RELEASE sp1; | |
29 } | |
30 } {} | |
31 do_test savepoint-1.2 { | |
32 execsql { | |
33 SAVEPOINT sp1; | |
34 ROLLBACK TO sp1; | |
35 } | |
36 } {} | |
37 do_test savepoint-1.3 { | |
38 execsql { SAVEPOINT sp1 } | |
39 db close | |
40 } {} | |
41 sqlite3 db test.db | |
42 do_test savepoint-1.4.1 { | |
43 execsql { | |
44 SAVEPOINT sp1; | |
45 SAVEPOINT sp2; | |
46 RELEASE sp1; | |
47 } | |
48 sqlite3_get_autocommit db | |
49 } {1} | |
50 do_test savepoint-1.4.2 { | |
51 execsql { | |
52 SAVEPOINT sp1; | |
53 SAVEPOINT sp2; | |
54 RELEASE sp2; | |
55 } | |
56 sqlite3_get_autocommit db | |
57 } {0} | |
58 do_test savepoint-1.4.3 { | |
59 execsql { RELEASE sp1 } | |
60 sqlite3_get_autocommit db | |
61 } {1} | |
62 do_test savepoint-1.4.4 { | |
63 execsql { | |
64 SAVEPOINT sp1; | |
65 SAVEPOINT sp2; | |
66 ROLLBACK TO sp1; | |
67 } | |
68 sqlite3_get_autocommit db | |
69 } {0} | |
70 do_test savepoint-1.4.5 { | |
71 execsql { RELEASE SAVEPOINT sp1 } | |
72 sqlite3_get_autocommit db | |
73 } {1} | |
74 do_test savepoint-1.4.6 { | |
75 execsql { | |
76 SAVEPOINT sp1; | |
77 SAVEPOINT sp2; | |
78 SAVEPOINT sp3; | |
79 ROLLBACK TO SAVEPOINT sp3; | |
80 ROLLBACK TRANSACTION TO sp2; | |
81 ROLLBACK TRANSACTION TO SAVEPOINT sp1; | |
82 } | |
83 sqlite3_get_autocommit db | |
84 } {0} | |
85 do_test savepoint-1.4.7 { | |
86 execsql { RELEASE SAVEPOINT SP1 } | |
87 sqlite3_get_autocommit db | |
88 } {1} | |
89 do_test savepoint-1.5 { | |
90 execsql { | |
91 SAVEPOINT sp1; | |
92 ROLLBACK TO sp1; | |
93 } | |
94 } {} | |
95 do_test savepoint-1.6 { | |
96 execsql COMMIT | |
97 } {} | |
98 wal_check_journal_mode savepoint-1.7 | |
99 | |
100 #------------------------------------------------------------------------ | |
101 # These tests - savepoint-2.* - test rollbacks and releases of savepoints | |
102 # with a very simple data set. | |
103 # | |
104 | |
105 do_test savepoint-2.1 { | |
106 execsql { | |
107 CREATE TABLE t1(a, b, c); | |
108 BEGIN; | |
109 INSERT INTO t1 VALUES(1, 2, 3); | |
110 SAVEPOINT one; | |
111 UPDATE t1 SET a = 2, b = 3, c = 4; | |
112 } | |
113 execsql { SELECT * FROM t1 } | |
114 } {2 3 4} | |
115 do_test savepoint-2.2 { | |
116 execsql { | |
117 ROLLBACK TO one; | |
118 } | |
119 execsql { SELECT * FROM t1 } | |
120 } {1 2 3} | |
121 do_test savepoint-2.3 { | |
122 execsql { | |
123 INSERT INTO t1 VALUES(4, 5, 6); | |
124 } | |
125 execsql { SELECT * FROM t1 } | |
126 } {1 2 3 4 5 6} | |
127 do_test savepoint-2.4 { | |
128 execsql { | |
129 ROLLBACK TO one; | |
130 } | |
131 execsql { SELECT * FROM t1 } | |
132 } {1 2 3} | |
133 | |
134 | |
135 do_test savepoint-2.5 { | |
136 execsql { | |
137 INSERT INTO t1 VALUES(7, 8, 9); | |
138 SAVEPOINT two; | |
139 INSERT INTO t1 VALUES(10, 11, 12); | |
140 } | |
141 execsql { SELECT * FROM t1 } | |
142 } {1 2 3 7 8 9 10 11 12} | |
143 do_test savepoint-2.6 { | |
144 execsql { | |
145 ROLLBACK TO two; | |
146 } | |
147 execsql { SELECT * FROM t1 } | |
148 } {1 2 3 7 8 9} | |
149 do_test savepoint-2.7 { | |
150 execsql { | |
151 INSERT INTO t1 VALUES(10, 11, 12); | |
152 } | |
153 execsql { SELECT * FROM t1 } | |
154 } {1 2 3 7 8 9 10 11 12} | |
155 do_test savepoint-2.8 { | |
156 execsql { | |
157 ROLLBACK TO one; | |
158 } | |
159 execsql { SELECT * FROM t1 } | |
160 } {1 2 3} | |
161 do_test savepoint-2.9 { | |
162 execsql { | |
163 INSERT INTO t1 VALUES('a', 'b', 'c'); | |
164 SAVEPOINT two; | |
165 INSERT INTO t1 VALUES('d', 'e', 'f'); | |
166 } | |
167 execsql { SELECT * FROM t1 } | |
168 } {1 2 3 a b c d e f} | |
169 do_test savepoint-2.10 { | |
170 execsql { | |
171 RELEASE two; | |
172 } | |
173 execsql { SELECT * FROM t1 } | |
174 } {1 2 3 a b c d e f} | |
175 do_test savepoint-2.11 { | |
176 execsql { | |
177 ROLLBACK; | |
178 } | |
179 execsql { SELECT * FROM t1 } | |
180 } {} | |
181 wal_check_journal_mode savepoint-2.12 | |
182 | |
183 #------------------------------------------------------------------------ | |
184 # This block of tests - savepoint-3.* - test that when a transaction | |
185 # savepoint is rolled back, locks are not released from database files. | |
186 # And that when a transaction savepoint is released, they are released. | |
187 # | |
188 # These tests do not work in WAL mode. WAL mode does not take RESERVED | |
189 # locks on the database file. | |
190 # | |
191 if {[wal_is_wal_mode]==0} { | |
192 do_test savepoint-3.1 { | |
193 execsql { SAVEPOINT "transaction" } | |
194 execsql { PRAGMA lock_status } | |
195 } {main unlocked temp closed} | |
196 | |
197 do_test savepoint-3.2 { | |
198 execsql { INSERT INTO t1 VALUES(1, 2, 3) } | |
199 execsql { PRAGMA lock_status } | |
200 } {main reserved temp closed} | |
201 | |
202 do_test savepoint-3.3 { | |
203 execsql { ROLLBACK TO "transaction" } | |
204 execsql { PRAGMA lock_status } | |
205 } {main reserved temp closed} | |
206 | |
207 do_test savepoint-3.4 { | |
208 execsql { INSERT INTO t1 VALUES(1, 2, 3) } | |
209 execsql { PRAGMA lock_status } | |
210 } {main reserved temp closed} | |
211 | |
212 do_test savepoint-3.5 { | |
213 execsql { RELEASE "transaction" } | |
214 execsql { PRAGMA lock_status } | |
215 } {main unlocked temp closed} | |
216 } | |
217 | |
218 #------------------------------------------------------------------------ | |
219 # Test that savepoints that include schema modifications are handled | |
220 # correctly. Test cases savepoint-4.*. | |
221 # | |
222 do_test savepoint-4.1 { | |
223 execsql { | |
224 CREATE TABLE t2(d, e, f); | |
225 SELECT sql FROM sqlite_master; | |
226 } | |
227 } {{CREATE TABLE t1(a, b, c)} {CREATE TABLE t2(d, e, f)}} | |
228 do_test savepoint-4.2 { | |
229 execsql { | |
230 BEGIN; | |
231 CREATE TABLE t3(g,h); | |
232 INSERT INTO t3 VALUES('I', 'II'); | |
233 SAVEPOINT one; | |
234 DROP TABLE t3; | |
235 } | |
236 } {} | |
237 do_test savepoint-4.3 { | |
238 execsql { | |
239 CREATE TABLE t3(g, h, i); | |
240 INSERT INTO t3 VALUES('III', 'IV', 'V'); | |
241 } | |
242 execsql {SELECT * FROM t3} | |
243 } {III IV V} | |
244 do_test savepoint-4.4 { | |
245 execsql { ROLLBACK TO one; } | |
246 execsql {SELECT * FROM t3} | |
247 } {I II} | |
248 do_test savepoint-4.5 { | |
249 execsql { | |
250 ROLLBACK; | |
251 SELECT sql FROM sqlite_master; | |
252 } | |
253 } {{CREATE TABLE t1(a, b, c)} {CREATE TABLE t2(d, e, f)}} | |
254 | |
255 do_test savepoint-4.6 { | |
256 execsql { | |
257 BEGIN; | |
258 INSERT INTO t1 VALUES('o', 't', 't'); | |
259 SAVEPOINT sp1; | |
260 CREATE TABLE t3(a, b, c); | |
261 INSERT INTO t3 VALUES('z', 'y', 'x'); | |
262 } | |
263 execsql {SELECT * FROM t3} | |
264 } {z y x} | |
265 do_test savepoint-4.7 { | |
266 execsql { | |
267 ROLLBACK TO sp1; | |
268 CREATE TABLE t3(a); | |
269 INSERT INTO t3 VALUES('value'); | |
270 } | |
271 execsql {SELECT * FROM t3} | |
272 } {value} | |
273 do_test savepoint-4.8 { | |
274 execsql COMMIT | |
275 } {} | |
276 wal_check_journal_mode savepoint-4.9 | |
277 | |
278 #------------------------------------------------------------------------ | |
279 # Test some logic errors to do with the savepoint feature. | |
280 # | |
281 | |
282 ifcapable incrblob { | |
283 do_test savepoint-5.1.1 { | |
284 execsql { | |
285 CREATE TABLE blobs(x); | |
286 INSERT INTO blobs VALUES('a twentyeight character blob'); | |
287 } | |
288 set fd [db incrblob blobs x 1] | |
289 puts -nonewline $fd "hello" | |
290 catchsql {SAVEPOINT abc} | |
291 } {1 {cannot open savepoint - SQL statements in progress}} | |
292 do_test savepoint-5.1.2 { | |
293 close $fd | |
294 catchsql {SAVEPOINT abc} | |
295 } {0 {}} | |
296 | |
297 do_test savepoint-5.2 { | |
298 execsql {RELEASE abc} | |
299 catchsql {RELEASE abc} | |
300 } {1 {no such savepoint: abc}} | |
301 | |
302 do_test savepoint-5.3.1 { | |
303 execsql {SAVEPOINT abc} | |
304 catchsql {ROLLBACK TO def} | |
305 } {1 {no such savepoint: def}} | |
306 do_test savepoint-5.3.2.1 { | |
307 execsql {SAVEPOINT def} | |
308 set fd [db incrblob -readonly blobs x 1] | |
309 set rc [catch {seek $fd 0;read $fd} res] | |
310 lappend rc $res | |
311 } {0 {hellontyeight character blob}} | |
312 do_test savepoint-5.3.2.2 { | |
313 catchsql {ROLLBACK TO def} | |
314 } {0 {}} | |
315 do_test savepoint-5.3.2.3 { | |
316 set rc [catch {seek $fd 0; read $fd} res] | |
317 set rc | |
318 } {0} | |
319 do_test savepoint-5.3.3 { | |
320 catchsql {RELEASE def} | |
321 } {0 {}} | |
322 do_test savepoint-5.3.4 { | |
323 close $fd | |
324 execsql {savepoint def} | |
325 set fd [db incrblob blobs x 1] | |
326 catchsql {release def} | |
327 } {1 {cannot release savepoint - SQL statements in progress}} | |
328 do_test savepoint-5.3.5 { | |
329 close $fd | |
330 execsql {release abc} | |
331 } {} | |
332 | |
333 # Rollback mode: | |
334 # | |
335 # Open a savepoint transaction and insert a row into the database. Then, | |
336 # using a second database handle, open a read-only transaction on the | |
337 # database file. Check that the savepoint transaction cannot be committed | |
338 # until after the read-only transaction has been closed. | |
339 # | |
340 # WAL mode: | |
341 # | |
342 # As above, except that the savepoint transaction can be successfully | |
343 # committed before the read-only transaction has been closed. | |
344 # | |
345 do_test savepoint-5.4.1 { | |
346 execsql { | |
347 SAVEPOINT main; | |
348 INSERT INTO blobs VALUES('another blob'); | |
349 } | |
350 } {} | |
351 do_test savepoint-5.4.2 { | |
352 sqlite3 db2 test.db | |
353 execsql { BEGIN ; SELECT count(*) FROM blobs } db2 | |
354 } {1} | |
355 if {[wal_is_wal_mode]} { | |
356 do_test savepoint-5.4.3 { catchsql "RELEASE main" } {0 {}} | |
357 do_test savepoint-5.4.4 { db2 close } {} | |
358 } else { | |
359 do_test savepoint-5.4.3 { | |
360 catchsql { RELEASE main } | |
361 } {1 {database is locked}} | |
362 do_test savepoint-5.4.4 { | |
363 db2 close | |
364 catchsql { RELEASE main } | |
365 } {0 {}} | |
366 } | |
367 do_test savepoint-5.4.5 { | |
368 execsql { SELECT x FROM blobs WHERE rowid = 2 } | |
369 } {{another blob}} | |
370 do_test savepoint-5.4.6 { | |
371 execsql { SELECT count(*) FROM blobs } | |
372 } {2} | |
373 } | |
374 wal_check_journal_mode savepoint-5.5 | |
375 | |
376 #------------------------------------------------------------------------- | |
377 # The following tests, savepoint-6.*, test an incr-vacuum inside of a | |
378 # couple of nested savepoints. | |
379 # | |
380 ifcapable {autovacuum && pragma} { | |
381 db close | |
382 forcedelete test.db | |
383 sqlite3 db test.db | |
384 | |
385 do_test savepoint-6.1 { | |
386 execsql { PRAGMA auto_vacuum = incremental } | |
387 wal_set_journal_mode | |
388 execsql { | |
389 CREATE TABLE t1(a, b, c); | |
390 CREATE INDEX i1 ON t1(a, b); | |
391 BEGIN; | |
392 INSERT INTO t1 VALUES(randstr(10,400),randstr(10,400),randstr(10,400)); | |
393 } | |
394 set r "randstr(10,400)" | |
395 for {set ii 0} {$ii < 10} {incr ii} { | |
396 execsql "INSERT INTO t1 SELECT $r, $r, $r FROM t1" | |
397 } | |
398 execsql { COMMIT } | |
399 } {} | |
400 | |
401 integrity_check savepoint-6.2 | |
402 | |
403 do_test savepoint-6.3 { | |
404 execsql { | |
405 PRAGMA cache_size = 10; | |
406 BEGIN; | |
407 UPDATE t1 SET a = randstr(10,10) WHERE (rowid%4)==0; | |
408 SAVEPOINT one; | |
409 DELETE FROM t1 WHERE rowid%2; | |
410 PRAGMA incr_vacuum; | |
411 SAVEPOINT two; | |
412 INSERT INTO t1 SELECT randstr(10,400), randstr(10,400), c FROM t1; | |
413 DELETE FROM t1 WHERE rowid%2; | |
414 PRAGMA incr_vacuum; | |
415 ROLLBACK TO one; | |
416 COMMIT; | |
417 } | |
418 } {} | |
419 | |
420 integrity_check savepoint-6.4 | |
421 | |
422 wal_check_journal_mode savepoint-6.5 | |
423 } | |
424 | |
425 #------------------------------------------------------------------------- | |
426 # The following tests, savepoint-7.*, attempt to break the logic | |
427 # surrounding savepoints by growing and shrinking the database file. | |
428 # | |
429 db close | |
430 forcedelete test.db | |
431 sqlite3 db test.db | |
432 | |
433 do_test savepoint-7.1 { | |
434 execsql { PRAGMA auto_vacuum = incremental } | |
435 wal_set_journal_mode | |
436 execsql { | |
437 PRAGMA cache_size = 10; | |
438 BEGIN; | |
439 CREATE TABLE t1(a PRIMARY KEY, b); | |
440 INSERT INTO t1(a) VALUES('alligator'); | |
441 INSERT INTO t1(a) VALUES('angelfish'); | |
442 INSERT INTO t1(a) VALUES('ant'); | |
443 INSERT INTO t1(a) VALUES('antelope'); | |
444 INSERT INTO t1(a) VALUES('ape'); | |
445 INSERT INTO t1(a) VALUES('baboon'); | |
446 INSERT INTO t1(a) VALUES('badger'); | |
447 INSERT INTO t1(a) VALUES('bear'); | |
448 INSERT INTO t1(a) VALUES('beetle'); | |
449 INSERT INTO t1(a) VALUES('bird'); | |
450 INSERT INTO t1(a) VALUES('bison'); | |
451 UPDATE t1 SET b = randstr(1000,1000); | |
452 UPDATE t1 SET b = b||randstr(1000,1000); | |
453 UPDATE t1 SET b = b||randstr(1000,1000); | |
454 UPDATE t1 SET b = b||randstr(10,1000); | |
455 COMMIT; | |
456 } | |
457 expr ([execsql { PRAGMA page_count }] > 20) | |
458 } {1} | |
459 do_test savepoint-7.2.1 { | |
460 execsql { | |
461 BEGIN; | |
462 SAVEPOINT one; | |
463 CREATE TABLE t2(a, b); | |
464 INSERT INTO t2 SELECT a, b FROM t1; | |
465 ROLLBACK TO one; | |
466 } | |
467 execsql { | |
468 PRAGMA integrity_check; | |
469 } | |
470 } {ok} | |
471 do_test savepoint-7.2.2 { | |
472 execsql { | |
473 COMMIT; | |
474 PRAGMA integrity_check; | |
475 } | |
476 } {ok} | |
477 | |
478 do_test savepoint-7.3.1 { | |
479 execsql { | |
480 CREATE TABLE t2(a, b); | |
481 INSERT INTO t2 SELECT a, b FROM t1; | |
482 } | |
483 } {} | |
484 do_test savepoint-7.3.2 { | |
485 execsql { | |
486 BEGIN; | |
487 SAVEPOINT one; | |
488 DELETE FROM t2; | |
489 PRAGMA incremental_vacuum; | |
490 SAVEPOINT two; | |
491 INSERT INTO t2 SELECT a, b FROM t1; | |
492 ROLLBACK TO two; | |
493 COMMIT; | |
494 } | |
495 execsql { PRAGMA integrity_check } | |
496 } {ok} | |
497 wal_check_journal_mode savepoint-7.3.3 | |
498 | |
499 do_test savepoint-7.4.1 { | |
500 db close | |
501 forcedelete test.db | |
502 sqlite3 db test.db | |
503 execsql { PRAGMA auto_vacuum = incremental } | |
504 wal_set_journal_mode | |
505 execsql { | |
506 CREATE TABLE t1(a, b, PRIMARY KEY(a, b)); | |
507 INSERT INTO t1 VALUES(randstr(1000,1000), randstr(1000,1000)); | |
508 BEGIN; | |
509 DELETE FROM t1; | |
510 SAVEPOINT one; | |
511 PRAGMA incremental_vacuum; | |
512 ROLLBACK TO one; | |
513 COMMIT; | |
514 } | |
515 | |
516 execsql { PRAGMA integrity_check } | |
517 } {ok} | |
518 | |
519 do_test savepoint-7.5.1 { | |
520 execsql { | |
521 PRAGMA incremental_vacuum; | |
522 CREATE TABLE t5(x, y); | |
523 INSERT INTO t5 VALUES(1, randstr(1000,1000)); | |
524 INSERT INTO t5 VALUES(2, randstr(1000,1000)); | |
525 INSERT INTO t5 VALUES(3, randstr(1000,1000)); | |
526 | |
527 BEGIN; | |
528 INSERT INTO t5 VALUES(4, randstr(1000,1000)); | |
529 INSERT INTO t5 VALUES(5, randstr(1000,1000)); | |
530 DELETE FROM t5 WHERE x=1 OR x=2; | |
531 SAVEPOINT one; | |
532 PRAGMA incremental_vacuum; | |
533 SAVEPOINT two; | |
534 INSERT INTO t5 VALUES(1, randstr(1000,1000)); | |
535 INSERT INTO t5 VALUES(2, randstr(1000,1000)); | |
536 ROLLBACK TO two; | |
537 ROLLBACK TO one; | |
538 COMMIT; | |
539 PRAGMA integrity_check; | |
540 } | |
541 } {ok} | |
542 do_test savepoint-7.5.2 { | |
543 execsql { | |
544 DROP TABLE t5; | |
545 } | |
546 } {} | |
547 wal_check_journal_mode savepoint-7.5.3 | |
548 | |
549 # Test oddly named and quoted savepoints. | |
550 # | |
551 do_test savepoint-8-1 { | |
552 execsql { SAVEPOINT "save1" } | |
553 execsql { RELEASE save1 } | |
554 } {} | |
555 do_test savepoint-8-2 { | |
556 execsql { SAVEPOINT "Including whitespace " } | |
557 execsql { RELEASE "including Whitespace " } | |
558 } {} | |
559 | |
560 # Test that the authorization callback works. | |
561 # | |
562 ifcapable auth { | |
563 proc auth {args} { | |
564 eval lappend ::authdata [lrange $args 0 4] | |
565 return SQLITE_OK | |
566 } | |
567 db auth auth | |
568 | |
569 do_test savepoint-9.1 { | |
570 set ::authdata [list] | |
571 execsql { SAVEPOINT sp1 } | |
572 set ::authdata | |
573 } {SQLITE_SAVEPOINT BEGIN sp1 {} {}} | |
574 do_test savepoint-9.2 { | |
575 set ::authdata [list] | |
576 execsql { ROLLBACK TO sp1 } | |
577 set ::authdata | |
578 } {SQLITE_SAVEPOINT ROLLBACK sp1 {} {}} | |
579 do_test savepoint-9.3 { | |
580 set ::authdata [list] | |
581 execsql { RELEASE sp1 } | |
582 set ::authdata | |
583 } {SQLITE_SAVEPOINT RELEASE sp1 {} {}} | |
584 | |
585 proc auth {args} { | |
586 eval lappend ::authdata [lrange $args 0 4] | |
587 return SQLITE_DENY | |
588 } | |
589 db auth auth | |
590 | |
591 do_test savepoint-9.4 { | |
592 set ::authdata [list] | |
593 set res [catchsql { SAVEPOINT sp1 }] | |
594 concat $::authdata $res | |
595 } {SQLITE_SAVEPOINT BEGIN sp1 {} {} 1 {not authorized}} | |
596 do_test savepoint-9.5 { | |
597 set ::authdata [list] | |
598 set res [catchsql { ROLLBACK TO sp1 }] | |
599 concat $::authdata $res | |
600 } {SQLITE_SAVEPOINT ROLLBACK sp1 {} {} 1 {not authorized}} | |
601 do_test savepoint-9.6 { | |
602 set ::authdata [list] | |
603 set res [catchsql { RELEASE sp1 }] | |
604 concat $::authdata $res | |
605 } {SQLITE_SAVEPOINT RELEASE sp1 {} {} 1 {not authorized}} | |
606 | |
607 catch { db eval ROLLBACK } | |
608 db auth "" | |
609 } | |
610 | |
611 #------------------------------------------------------------------------- | |
612 # The following tests - savepoint-10.* - test the interaction of | |
613 # savepoints and ATTACH statements. | |
614 # | |
615 | |
616 # First make sure it is not possible to attach or detach a database while | |
617 # a savepoint is open (it is not possible if any transaction is open). | |
618 # | |
619 do_test savepoint-10.1.1 { | |
620 catchsql { | |
621 SAVEPOINT one; | |
622 ATTACH 'test2.db' AS aux; | |
623 } | |
624 } {1 {cannot ATTACH database within transaction}} | |
625 do_test savepoint-10.1.2 { | |
626 execsql { | |
627 RELEASE one; | |
628 ATTACH 'test2.db' AS aux; | |
629 } | |
630 catchsql { | |
631 SAVEPOINT one; | |
632 DETACH aux; | |
633 } | |
634 } {1 {cannot DETACH database within transaction}} | |
635 do_test savepoint-10.1.3 { | |
636 execsql { | |
637 RELEASE one; | |
638 DETACH aux; | |
639 } | |
640 } {} | |
641 | |
642 # The lock state of the TEMP database can vary if SQLITE_TEMP_STORE=3 | |
643 # And the following set of tests is only really interested in the status | |
644 # of the aux1 and aux2 locks. So record the current lock status of | |
645 # TEMP for use in the answers. | |
646 set templockstate [lindex [db eval {PRAGMA lock_status}] 3] | |
647 | |
648 | |
649 if {[wal_is_wal_mode]==0} { | |
650 do_test savepoint-10.2.1 { | |
651 forcedelete test3.db | |
652 forcedelete test2.db | |
653 execsql { | |
654 ATTACH 'test2.db' AS aux1; | |
655 ATTACH 'test3.db' AS aux2; | |
656 DROP TABLE t1; | |
657 CREATE TABLE main.t1(x, y); | |
658 CREATE TABLE aux1.t2(x, y); | |
659 CREATE TABLE aux2.t3(x, y); | |
660 SELECT name FROM sqlite_master; | |
661 SELECT name FROM aux1.sqlite_master; | |
662 SELECT name FROM aux2.sqlite_master; | |
663 } | |
664 } {t1 t2 t3} | |
665 do_test savepoint-10.2.2 { | |
666 execsql { PRAGMA lock_status } | |
667 } [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked] | |
668 | |
669 do_test savepoint-10.2.3 { | |
670 execsql { | |
671 SAVEPOINT one; | |
672 INSERT INTO t1 VALUES(1, 2); | |
673 PRAGMA lock_status; | |
674 } | |
675 } [list main reserved temp $templockstate aux1 unlocked aux2 unlocked] | |
676 do_test savepoint-10.2.4 { | |
677 execsql { | |
678 INSERT INTO t3 VALUES(3, 4); | |
679 PRAGMA lock_status; | |
680 } | |
681 } [list main reserved temp $templockstate aux1 unlocked aux2 reserved] | |
682 do_test savepoint-10.2.5 { | |
683 execsql { | |
684 SAVEPOINT two; | |
685 INSERT INTO t2 VALUES(5, 6); | |
686 PRAGMA lock_status; | |
687 } | |
688 } [list main reserved temp $templockstate aux1 reserved aux2 reserved] | |
689 do_test savepoint-10.2.6 { | |
690 execsql { SELECT * FROM t2 } | |
691 } {5 6} | |
692 do_test savepoint-10.2.7 { | |
693 execsql { ROLLBACK TO two } | |
694 execsql { SELECT * FROM t2 } | |
695 } {} | |
696 do_test savepoint-10.2.8 { | |
697 execsql { PRAGMA lock_status } | |
698 } [list main reserved temp $templockstate aux1 reserved aux2 reserved] | |
699 do_test savepoint-10.2.9 { | |
700 execsql { SELECT 'a', * FROM t1 ; SELECT 'b', * FROM t3 } | |
701 } {a 1 2 b 3 4} | |
702 do_test savepoint-10.2.9 { | |
703 execsql { | |
704 INSERT INTO t2 VALUES(5, 6); | |
705 RELEASE one; | |
706 } | |
707 execsql { | |
708 SELECT * FROM t1; | |
709 SELECT * FROM t2; | |
710 SELECT * FROM t3; | |
711 } | |
712 } {1 2 5 6 3 4} | |
713 do_test savepoint-10.2.9 { | |
714 execsql { PRAGMA lock_status } | |
715 } [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked] | |
716 | |
717 do_test savepoint-10.2.10 { | |
718 execsql { | |
719 SAVEPOINT one; | |
720 INSERT INTO t1 VALUES('a', 'b'); | |
721 SAVEPOINT two; | |
722 INSERT INTO t2 VALUES('c', 'd'); | |
723 SAVEPOINT three; | |
724 INSERT INTO t3 VALUES('e', 'f'); | |
725 } | |
726 execsql { | |
727 SELECT * FROM t1; | |
728 SELECT * FROM t2; | |
729 SELECT * FROM t3; | |
730 } | |
731 } {1 2 a b 5 6 c d 3 4 e f} | |
732 do_test savepoint-10.2.11 { | |
733 execsql { ROLLBACK TO two } | |
734 execsql { | |
735 SELECT * FROM t1; | |
736 SELECT * FROM t2; | |
737 SELECT * FROM t3; | |
738 } | |
739 } {1 2 a b 5 6 3 4} | |
740 do_test savepoint-10.2.12 { | |
741 execsql { | |
742 INSERT INTO t3 VALUES('g', 'h'); | |
743 ROLLBACK TO two; | |
744 } | |
745 execsql { | |
746 SELECT * FROM t1; | |
747 SELECT * FROM t2; | |
748 SELECT * FROM t3; | |
749 } | |
750 } {1 2 a b 5 6 3 4} | |
751 do_test savepoint-10.2.13 { | |
752 execsql { ROLLBACK } | |
753 execsql { | |
754 SELECT * FROM t1; | |
755 SELECT * FROM t2; | |
756 SELECT * FROM t3; | |
757 } | |
758 } {1 2 5 6 3 4} | |
759 do_test savepoint-10.2.14 { | |
760 execsql { PRAGMA lock_status } | |
761 } [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked] | |
762 } | |
763 | |
764 #------------------------------------------------------------------------- | |
765 # The following tests - savepoint-11.* - test the interaction of | |
766 # savepoints and creating or dropping tables and indexes in | |
767 # auto-vacuum mode. | |
768 # | |
769 do_test savepoint-11.1 { | |
770 db close | |
771 forcedelete test.db | |
772 sqlite3 db test.db | |
773 execsql { PRAGMA auto_vacuum = full; } | |
774 wal_set_journal_mode | |
775 execsql { | |
776 CREATE TABLE t1(a, b, UNIQUE(a, b)); | |
777 INSERT INTO t1 VALUES(1, randstr(1000,1000)); | |
778 INSERT INTO t1 VALUES(2, randstr(1000,1000)); | |
779 } | |
780 } {} | |
781 do_test savepoint-11.2 { | |
782 execsql { | |
783 SAVEPOINT one; | |
784 CREATE TABLE t2(a, b, UNIQUE(a, b)); | |
785 SAVEPOINT two; | |
786 CREATE TABLE t3(a, b, UNIQUE(a, b)); | |
787 } | |
788 } {} | |
789 integrity_check savepoint-11.3 | |
790 do_test savepoint-11.4 { | |
791 execsql { ROLLBACK TO two } | |
792 } {} | |
793 integrity_check savepoint-11.5 | |
794 do_test savepoint-11.6 { | |
795 execsql { | |
796 CREATE TABLE t3(a, b, UNIQUE(a, b)); | |
797 ROLLBACK TO one; | |
798 } | |
799 } {} | |
800 integrity_check savepoint-11.7 | |
801 do_test savepoint-11.8 { | |
802 execsql { ROLLBACK } | |
803 execsql { PRAGMA wal_checkpoint } | |
804 file size test.db | |
805 } {8192} | |
806 | |
807 do_test savepoint-11.9 { | |
808 execsql { | |
809 DROP TABLE IF EXISTS t1; | |
810 DROP TABLE IF EXISTS t2; | |
811 DROP TABLE IF EXISTS t3; | |
812 } | |
813 } {} | |
814 do_test savepoint-11.10 { | |
815 execsql { | |
816 BEGIN; | |
817 CREATE TABLE t1(a, b); | |
818 CREATE TABLE t2(x, y); | |
819 INSERT INTO t2 VALUES(1, 2); | |
820 SAVEPOINT one; | |
821 INSERT INTO t2 VALUES(3, 4); | |
822 SAVEPOINT two; | |
823 DROP TABLE t1; | |
824 ROLLBACK TO two; | |
825 } | |
826 execsql {SELECT * FROM t2} | |
827 } {1 2 3 4} | |
828 do_test savepoint-11.11 { | |
829 execsql COMMIT | |
830 } {} | |
831 do_test savepoint-11.12 { | |
832 execsql {SELECT * FROM t2} | |
833 } {1 2 3 4} | |
834 wal_check_journal_mode savepoint-11.13 | |
835 | |
836 #------------------------------------------------------------------------- | |
837 # The following tests - savepoint-12.* - test the interaction of | |
838 # savepoints and "ON CONFLICT ROLLBACK" clauses. | |
839 # | |
840 do_test savepoint-12.1 { | |
841 execsql { | |
842 CREATE TABLE t4(a PRIMARY KEY, b); | |
843 INSERT INTO t4 VALUES(1, 'one'); | |
844 } | |
845 } {} | |
846 do_test savepoint-12.2 { | |
847 # The final statement of the following SQL hits a constraint when the | |
848 # conflict handling mode is "OR ROLLBACK" and there are a couple of | |
849 # open savepoints. At one point this would fail to clear the internal | |
850 # record of the open savepoints, resulting in an assert() failure | |
851 # later on. | |
852 # | |
853 catchsql { | |
854 BEGIN; | |
855 INSERT INTO t4 VALUES(2, 'two'); | |
856 SAVEPOINT sp1; | |
857 INSERT INTO t4 VALUES(3, 'three'); | |
858 SAVEPOINT sp2; | |
859 INSERT OR ROLLBACK INTO t4 VALUES(1, 'one'); | |
860 } | |
861 } {1 {UNIQUE constraint failed: t4.a}} | |
862 do_test savepoint-12.3 { | |
863 sqlite3_get_autocommit db | |
864 } {1} | |
865 do_test savepoint-12.4 { | |
866 execsql { SAVEPOINT one } | |
867 } {} | |
868 wal_check_journal_mode savepoint-12.5 | |
869 | |
870 #------------------------------------------------------------------------- | |
871 # The following tests - savepoint-13.* - test the interaction of | |
872 # savepoints and "journal_mode = off". | |
873 # | |
874 if {[wal_is_wal_mode]==0} { | |
875 do_test savepoint-13.1 { | |
876 db close | |
877 catch {forcedelete test.db} | |
878 sqlite3 db test.db | |
879 execsql { | |
880 BEGIN; | |
881 CREATE TABLE t1(a PRIMARY KEY, b); | |
882 INSERT INTO t1 VALUES(1, 2); | |
883 COMMIT; | |
884 PRAGMA journal_mode = off; | |
885 } | |
886 } {off} | |
887 do_test savepoint-13.2 { | |
888 execsql { | |
889 BEGIN; | |
890 INSERT INTO t1 VALUES(3, 4); | |
891 INSERT INTO t1 SELECT a+4,b+4 FROM t1; | |
892 COMMIT; | |
893 } | |
894 } {} | |
895 do_test savepoint-13.3 { | |
896 execsql { | |
897 BEGIN; | |
898 INSERT INTO t1 VALUES(9, 10); | |
899 SAVEPOINT s1; | |
900 INSERT INTO t1 VALUES(11, 12); | |
901 COMMIT; | |
902 } | |
903 } {} | |
904 do_test savepoint-13.4 { | |
905 execsql { | |
906 BEGIN; | |
907 INSERT INTO t1 VALUES(13, 14); | |
908 SAVEPOINT s1; | |
909 INSERT INTO t1 VALUES(15, 16); | |
910 ROLLBACK TO s1; | |
911 ROLLBACK; | |
912 SELECT * FROM t1; | |
913 } | |
914 } {1 2 3 4 5 6 7 8 9 10 11 12} | |
915 } | |
916 | |
917 db close | |
918 delete_file test.db | |
919 do_multiclient_test tn { | |
920 do_test savepoint-14.$tn.1 { | |
921 sql1 { | |
922 CREATE TABLE foo(x); | |
923 INSERT INTO foo VALUES(1); | |
924 INSERT INTO foo VALUES(2); | |
925 } | |
926 sql2 { | |
927 BEGIN; | |
928 SELECT * FROM foo; | |
929 } | |
930 } {1 2} | |
931 do_test savepoint-14.$tn.2 { | |
932 sql1 { | |
933 SAVEPOINT one; | |
934 INSERT INTO foo VALUES(1); | |
935 } | |
936 csql1 { RELEASE one } | |
937 } {1 {database is locked}} | |
938 do_test savepoint-14.$tn.3 { | |
939 sql1 { ROLLBACK TO one } | |
940 sql2 { COMMIT } | |
941 sql1 { RELEASE one } | |
942 } {} | |
943 | |
944 do_test savepoint-14.$tn.4 { | |
945 sql2 { | |
946 BEGIN; | |
947 SELECT * FROM foo; | |
948 } | |
949 } {1 2} | |
950 do_test savepoint-14.$tn.5 { | |
951 sql1 { | |
952 SAVEPOINT one; | |
953 INSERT INTO foo VALUES(1); | |
954 } | |
955 csql1 { RELEASE one } | |
956 } {1 {database is locked}} | |
957 do_test savepoint-14.$tn.6 { | |
958 sql2 { COMMIT } | |
959 sql1 { | |
960 ROLLBACK TO one; | |
961 INSERT INTO foo VALUES(3); | |
962 INSERT INTO foo VALUES(4); | |
963 INSERT INTO foo VALUES(5); | |
964 RELEASE one; | |
965 } | |
966 } {} | |
967 do_test savepoint-14.$tn.7 { | |
968 sql2 { CREATE INDEX fooidx ON foo(x); } | |
969 sql3 { PRAGMA integrity_check } | |
970 } {ok} | |
971 } | |
972 | |
973 do_multiclient_test tn { | |
974 do_test savepoint-15.$tn.1 { | |
975 sql1 { | |
976 CREATE TABLE foo(x); | |
977 INSERT INTO foo VALUES(1); | |
978 INSERT INTO foo VALUES(2); | |
979 } | |
980 sql2 { BEGIN; SELECT * FROM foo; } | |
981 } {1 2} | |
982 do_test savepoint-15.$tn.2 { | |
983 sql1 { | |
984 PRAGMA locking_mode = EXCLUSIVE; | |
985 BEGIN; | |
986 INSERT INTO foo VALUES(3); | |
987 } | |
988 csql1 { COMMIT } | |
989 } {1 {database is locked}} | |
990 do_test savepoint-15.$tn.3 { | |
991 sql1 { ROLLBACK } | |
992 sql2 { COMMIT } | |
993 sql1 { | |
994 INSERT INTO foo VALUES(3); | |
995 PRAGMA locking_mode = NORMAL; | |
996 INSERT INTO foo VALUES(4); | |
997 } | |
998 sql2 { CREATE INDEX fooidx ON foo(x); } | |
999 sql3 { PRAGMA integrity_check } | |
1000 } {ok} | |
1001 } | |
1002 | |
1003 do_multiclient_test tn { | |
1004 do_test savepoint-16.$tn.1 { | |
1005 sql1 { | |
1006 CREATE TABLE foo(x); | |
1007 INSERT INTO foo VALUES(1); | |
1008 INSERT INTO foo VALUES(2); | |
1009 } | |
1010 } {} | |
1011 do_test savepoint-16.$tn.2 { | |
1012 | |
1013 db eval {SELECT * FROM foo} { | |
1014 sql1 { INSERT INTO foo VALUES(3) } | |
1015 sql2 { SELECT * FROM foo } | |
1016 sql1 { INSERT INTO foo VALUES(4) } | |
1017 break | |
1018 } | |
1019 | |
1020 sql2 { CREATE INDEX fooidx ON foo(x); } | |
1021 sql3 { PRAGMA integrity_check } | |
1022 } {ok} | |
1023 do_test savepoint-16.$tn.3 { | |
1024 sql1 { SELECT * FROM foo } | |
1025 } {1 2 3 4} | |
1026 } | |
1027 | |
1028 #------------------------------------------------------------------------- | |
1029 # This next block of tests verifies that a problem reported on the mailing | |
1030 # list has been resolved. At one point the second "CREATE TABLE t6" would | |
1031 # fail as table t6 still existed in the internal cache of the db schema | |
1032 # (even though it had been removed from the database by the ROLLBACK | |
1033 # command). | |
1034 # | |
1035 sqlite3 db test.db | |
1036 do_execsql_test savepoint-17.1 { | |
1037 BEGIN; | |
1038 CREATE TABLE t6(a, b); | |
1039 INSERT INTO t6 VALUES(1, 2); | |
1040 SAVEPOINT one; | |
1041 INSERT INTO t6 VALUES(3, 4); | |
1042 ROLLBACK TO one; | |
1043 SELECT * FROM t6; | |
1044 ROLLBACK; | |
1045 } {1 2} | |
1046 | |
1047 do_execsql_test savepoint-17.2 { | |
1048 CREATE TABLE t6(a, b); | |
1049 } {} | |
1050 | |
1051 finish_test | |
OLD | NEW |