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.1.1.1 2012/02/21 17:04:16 misho 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 {
307: execsql {SAVEPOINT def}
308: set fd [db incrblob -readonly blobs x 1]
309: catchsql {ROLLBACK TO def}
310: } {1 {cannot rollback savepoint - SQL statements in progress}}
311: do_test savepoint-5.3.3 {
312: catchsql {RELEASE def}
313: } {0 {}}
314: do_test savepoint-5.3.4 {
315: close $fd
316: execsql {savepoint def}
317: set fd [db incrblob blobs x 1]
318: catchsql {release def}
319: } {1 {cannot release savepoint - SQL statements in progress}}
320: do_test savepoint-5.3.5 {
321: close $fd
322: execsql {release abc}
323: } {}
324:
325: # Rollback mode:
326: #
327: # Open a savepoint transaction and insert a row into the database. Then,
328: # using a second database handle, open a read-only transaction on the
329: # database file. Check that the savepoint transaction cannot be committed
330: # until after the read-only transaction has been closed.
331: #
332: # WAL mode:
333: #
334: # As above, except that the savepoint transaction can be successfully
335: # committed before the read-only transaction has been closed.
336: #
337: do_test savepoint-5.4.1 {
338: execsql {
339: SAVEPOINT main;
340: INSERT INTO blobs VALUES('another blob');
341: }
342: } {}
343: do_test savepoint-5.4.2 {
344: sqlite3 db2 test.db
345: execsql { BEGIN ; SELECT count(*) FROM blobs } db2
346: } {1}
347: if {[wal_is_wal_mode]} {
348: do_test savepoint-5.4.3 { catchsql "RELEASE main" } {0 {}}
349: do_test savepoint-5.4.4 { db2 close } {}
350: } else {
351: do_test savepoint-5.4.3 {
352: catchsql { RELEASE main }
353: } {1 {database is locked}}
354: do_test savepoint-5.4.4 {
355: db2 close
356: catchsql { RELEASE main }
357: } {0 {}}
358: }
359: do_test savepoint-5.4.5 {
360: execsql { SELECT x FROM blobs WHERE rowid = 2 }
361: } {{another blob}}
362: do_test savepoint-5.4.6 {
363: execsql { SELECT count(*) FROM blobs }
364: } {2}
365: }
366: wal_check_journal_mode savepoint-5.5
367:
368: #-------------------------------------------------------------------------
369: # The following tests, savepoint-6.*, test an incr-vacuum inside of a
370: # couple of nested savepoints.
371: #
372: ifcapable {autovacuum && pragma} {
373: db close
374: forcedelete test.db
375: sqlite3 db test.db
376:
377: do_test savepoint-6.1 {
378: execsql { PRAGMA auto_vacuum = incremental }
379: wal_set_journal_mode
380: execsql {
381: CREATE TABLE t1(a, b, c);
382: CREATE INDEX i1 ON t1(a, b);
383: BEGIN;
384: INSERT INTO t1 VALUES(randstr(10,400),randstr(10,400),randstr(10,400));
385: }
386: set r "randstr(10,400)"
387: for {set ii 0} {$ii < 10} {incr ii} {
388: execsql "INSERT INTO t1 SELECT $r, $r, $r FROM t1"
389: }
390: execsql { COMMIT }
391: } {}
392:
393: integrity_check savepoint-6.2
394:
395: do_test savepoint-6.3 {
396: execsql {
397: PRAGMA cache_size = 10;
398: BEGIN;
399: UPDATE t1 SET a = randstr(10,10) WHERE (rowid%4)==0;
400: SAVEPOINT one;
401: DELETE FROM t1 WHERE rowid%2;
402: PRAGMA incr_vacuum;
403: SAVEPOINT two;
404: INSERT INTO t1 SELECT randstr(10,400), randstr(10,400), c FROM t1;
405: DELETE FROM t1 WHERE rowid%2;
406: PRAGMA incr_vacuum;
407: ROLLBACK TO one;
408: COMMIT;
409: }
410: } {}
411:
412: integrity_check savepoint-6.4
413:
414: wal_check_journal_mode savepoint-6.5
415: }
416:
417: #-------------------------------------------------------------------------
418: # The following tests, savepoint-7.*, attempt to break the logic
419: # surrounding savepoints by growing and shrinking the database file.
420: #
421: db close
422: forcedelete test.db
423: sqlite3 db test.db
424:
425: do_test savepoint-7.1 {
426: execsql { PRAGMA auto_vacuum = incremental }
427: wal_set_journal_mode
428: execsql {
429: PRAGMA cache_size = 10;
430: BEGIN;
431: CREATE TABLE t1(a PRIMARY KEY, b);
432: INSERT INTO t1(a) VALUES('alligator');
433: INSERT INTO t1(a) VALUES('angelfish');
434: INSERT INTO t1(a) VALUES('ant');
435: INSERT INTO t1(a) VALUES('antelope');
436: INSERT INTO t1(a) VALUES('ape');
437: INSERT INTO t1(a) VALUES('baboon');
438: INSERT INTO t1(a) VALUES('badger');
439: INSERT INTO t1(a) VALUES('bear');
440: INSERT INTO t1(a) VALUES('beetle');
441: INSERT INTO t1(a) VALUES('bird');
442: INSERT INTO t1(a) VALUES('bison');
443: UPDATE t1 SET b = randstr(1000,1000);
444: UPDATE t1 SET b = b||randstr(1000,1000);
445: UPDATE t1 SET b = b||randstr(1000,1000);
446: UPDATE t1 SET b = b||randstr(10,1000);
447: COMMIT;
448: }
449: expr ([execsql { PRAGMA page_count }] > 20)
450: } {1}
451: do_test savepoint-7.2.1 {
452: execsql {
453: BEGIN;
454: SAVEPOINT one;
455: CREATE TABLE t2(a, b);
456: INSERT INTO t2 SELECT a, b FROM t1;
457: ROLLBACK TO one;
458: }
459: execsql {
460: PRAGMA integrity_check;
461: }
462: } {ok}
463: do_test savepoint-7.2.2 {
464: execsql {
465: COMMIT;
466: PRAGMA integrity_check;
467: }
468: } {ok}
469:
470: do_test savepoint-7.3.1 {
471: execsql {
472: CREATE TABLE t2(a, b);
473: INSERT INTO t2 SELECT a, b FROM t1;
474: }
475: } {}
476: do_test savepoint-7.3.2 {
477: execsql {
478: BEGIN;
479: SAVEPOINT one;
480: DELETE FROM t2;
481: PRAGMA incremental_vacuum;
482: SAVEPOINT two;
483: INSERT INTO t2 SELECT a, b FROM t1;
484: ROLLBACK TO two;
485: COMMIT;
486: }
487: execsql { PRAGMA integrity_check }
488: } {ok}
489: wal_check_journal_mode savepoint-7.3.3
490:
491: do_test savepoint-7.4.1 {
492: db close
493: forcedelete test.db
494: sqlite3 db test.db
495: execsql { PRAGMA auto_vacuum = incremental }
496: wal_set_journal_mode
497: execsql {
498: CREATE TABLE t1(a, b, PRIMARY KEY(a, b));
499: INSERT INTO t1 VALUES(randstr(1000,1000), randstr(1000,1000));
500: BEGIN;
501: DELETE FROM t1;
502: SAVEPOINT one;
503: PRAGMA incremental_vacuum;
504: ROLLBACK TO one;
505: COMMIT;
506: }
507:
508: execsql { PRAGMA integrity_check }
509: } {ok}
510:
511: do_test savepoint-7.5.1 {
512: execsql {
513: PRAGMA incremental_vacuum;
514: CREATE TABLE t5(x, y);
515: INSERT INTO t5 VALUES(1, randstr(1000,1000));
516: INSERT INTO t5 VALUES(2, randstr(1000,1000));
517: INSERT INTO t5 VALUES(3, randstr(1000,1000));
518:
519: BEGIN;
520: INSERT INTO t5 VALUES(4, randstr(1000,1000));
521: INSERT INTO t5 VALUES(5, randstr(1000,1000));
522: DELETE FROM t5 WHERE x=1 OR x=2;
523: SAVEPOINT one;
524: PRAGMA incremental_vacuum;
525: SAVEPOINT two;
526: INSERT INTO t5 VALUES(1, randstr(1000,1000));
527: INSERT INTO t5 VALUES(2, randstr(1000,1000));
528: ROLLBACK TO two;
529: ROLLBACK TO one;
530: COMMIT;
531: PRAGMA integrity_check;
532: }
533: } {ok}
534: do_test savepoint-7.5.2 {
535: execsql {
536: DROP TABLE t5;
537: }
538: } {}
539: wal_check_journal_mode savepoint-7.5.3
540:
541: # Test oddly named and quoted savepoints.
542: #
543: do_test savepoint-8-1 {
544: execsql { SAVEPOINT "save1" }
545: execsql { RELEASE save1 }
546: } {}
547: do_test savepoint-8-2 {
548: execsql { SAVEPOINT "Including whitespace " }
549: execsql { RELEASE "including Whitespace " }
550: } {}
551:
552: # Test that the authorization callback works.
553: #
554: ifcapable auth {
555: proc auth {args} {
556: eval lappend ::authdata $args
557: return SQLITE_OK
558: }
559: db auth auth
560:
561: do_test savepoint-9.1 {
562: set ::authdata [list]
563: execsql { SAVEPOINT sp1 }
564: set ::authdata
565: } {SQLITE_SAVEPOINT BEGIN sp1 {} {}}
566: do_test savepoint-9.2 {
567: set ::authdata [list]
568: execsql { ROLLBACK TO sp1 }
569: set ::authdata
570: } {SQLITE_SAVEPOINT ROLLBACK sp1 {} {}}
571: do_test savepoint-9.3 {
572: set ::authdata [list]
573: execsql { RELEASE sp1 }
574: set ::authdata
575: } {SQLITE_SAVEPOINT RELEASE sp1 {} {}}
576:
577: proc auth {args} {
578: eval lappend ::authdata $args
579: return SQLITE_DENY
580: }
581: db auth auth
582:
583: do_test savepoint-9.4 {
584: set ::authdata [list]
585: set res [catchsql { SAVEPOINT sp1 }]
586: concat $::authdata $res
587: } {SQLITE_SAVEPOINT BEGIN sp1 {} {} 1 {not authorized}}
588: do_test savepoint-9.5 {
589: set ::authdata [list]
590: set res [catchsql { ROLLBACK TO sp1 }]
591: concat $::authdata $res
592: } {SQLITE_SAVEPOINT ROLLBACK sp1 {} {} 1 {not authorized}}
593: do_test savepoint-9.6 {
594: set ::authdata [list]
595: set res [catchsql { RELEASE sp1 }]
596: concat $::authdata $res
597: } {SQLITE_SAVEPOINT RELEASE sp1 {} {} 1 {not authorized}}
598:
599: catch { db eval ROLLBACK }
600: db auth ""
601: }
602:
603: #-------------------------------------------------------------------------
604: # The following tests - savepoint-10.* - test the interaction of
605: # savepoints and ATTACH statements.
606: #
607:
608: # First make sure it is not possible to attach or detach a database while
609: # a savepoint is open (it is not possible if any transaction is open).
610: #
611: do_test savepoint-10.1.1 {
612: catchsql {
613: SAVEPOINT one;
614: ATTACH 'test2.db' AS aux;
615: }
616: } {1 {cannot ATTACH database within transaction}}
617: do_test savepoint-10.1.2 {
618: execsql {
619: RELEASE one;
620: ATTACH 'test2.db' AS aux;
621: }
622: catchsql {
623: SAVEPOINT one;
624: DETACH aux;
625: }
626: } {1 {cannot DETACH database within transaction}}
627: do_test savepoint-10.1.3 {
628: execsql {
629: RELEASE one;
630: DETACH aux;
631: }
632: } {}
633:
634: # The lock state of the TEMP database can vary if SQLITE_TEMP_STORE=3
635: # And the following set of tests is only really interested in the status
636: # of the aux1 and aux2 locks. So record the current lock status of
637: # TEMP for use in the answers.
638: set templockstate [lindex [db eval {PRAGMA lock_status}] 3]
639:
640:
641: if {[wal_is_wal_mode]==0} {
642: do_test savepoint-10.2.1 {
643: forcedelete test3.db
644: forcedelete test2.db
645: execsql {
646: ATTACH 'test2.db' AS aux1;
647: ATTACH 'test3.db' AS aux2;
648: DROP TABLE t1;
649: CREATE TABLE main.t1(x, y);
650: CREATE TABLE aux1.t2(x, y);
651: CREATE TABLE aux2.t3(x, y);
652: SELECT name FROM sqlite_master
653: UNION ALL
654: SELECT name FROM aux1.sqlite_master
655: UNION ALL
656: SELECT name FROM aux2.sqlite_master;
657: }
658: } {t1 t2 t3}
659: do_test savepoint-10.2.2 {
660: execsql { PRAGMA lock_status }
661: } [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked]
662:
663: do_test savepoint-10.2.3 {
664: execsql {
665: SAVEPOINT one;
666: INSERT INTO t1 VALUES(1, 2);
667: PRAGMA lock_status;
668: }
669: } [list main reserved temp $templockstate aux1 unlocked aux2 unlocked]
670: do_test savepoint-10.2.4 {
671: execsql {
672: INSERT INTO t3 VALUES(3, 4);
673: PRAGMA lock_status;
674: }
675: } [list main reserved temp $templockstate aux1 unlocked aux2 reserved]
676: do_test savepoint-10.2.5 {
677: execsql {
678: SAVEPOINT two;
679: INSERT INTO t2 VALUES(5, 6);
680: PRAGMA lock_status;
681: }
682: } [list main reserved temp $templockstate aux1 reserved aux2 reserved]
683: do_test savepoint-10.2.6 {
684: execsql { SELECT * FROM t2 }
685: } {5 6}
686: do_test savepoint-10.2.7 {
687: execsql { ROLLBACK TO two }
688: execsql { SELECT * FROM t2 }
689: } {}
690: do_test savepoint-10.2.8 {
691: execsql { PRAGMA lock_status }
692: } [list main reserved temp $templockstate aux1 reserved aux2 reserved]
693: do_test savepoint-10.2.9 {
694: execsql { SELECT 'a', * FROM t1 UNION ALL SELECT 'b', * FROM t3 }
695: } {a 1 2 b 3 4}
696: do_test savepoint-10.2.9 {
697: execsql {
698: INSERT INTO t2 VALUES(5, 6);
699: RELEASE one;
700: }
701: execsql {
702: SELECT * FROM t1;
703: SELECT * FROM t2;
704: SELECT * FROM t3;
705: }
706: } {1 2 5 6 3 4}
707: do_test savepoint-10.2.9 {
708: execsql { PRAGMA lock_status }
709: } [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked]
710:
711: do_test savepoint-10.2.10 {
712: execsql {
713: SAVEPOINT one;
714: INSERT INTO t1 VALUES('a', 'b');
715: SAVEPOINT two;
716: INSERT INTO t2 VALUES('c', 'd');
717: SAVEPOINT three;
718: INSERT INTO t3 VALUES('e', 'f');
719: }
720: execsql {
721: SELECT * FROM t1;
722: SELECT * FROM t2;
723: SELECT * FROM t3;
724: }
725: } {1 2 a b 5 6 c d 3 4 e f}
726: do_test savepoint-10.2.11 {
727: execsql { ROLLBACK TO two }
728: execsql {
729: SELECT * FROM t1;
730: SELECT * FROM t2;
731: SELECT * FROM t3;
732: }
733: } {1 2 a b 5 6 3 4}
734: do_test savepoint-10.2.12 {
735: execsql {
736: INSERT INTO t3 VALUES('g', 'h');
737: ROLLBACK TO two;
738: }
739: execsql {
740: SELECT * FROM t1;
741: SELECT * FROM t2;
742: SELECT * FROM t3;
743: }
744: } {1 2 a b 5 6 3 4}
745: do_test savepoint-10.2.13 {
746: execsql { ROLLBACK }
747: execsql {
748: SELECT * FROM t1;
749: SELECT * FROM t2;
750: SELECT * FROM t3;
751: }
752: } {1 2 5 6 3 4}
753: do_test savepoint-10.2.14 {
754: execsql { PRAGMA lock_status }
755: } [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked]
756: }
757:
758: #-------------------------------------------------------------------------
759: # The following tests - savepoint-11.* - test the interaction of
760: # savepoints and creating or dropping tables and indexes in
761: # auto-vacuum mode.
762: #
763: do_test savepoint-11.1 {
764: db close
765: forcedelete test.db
766: sqlite3 db test.db
767: execsql { PRAGMA auto_vacuum = full; }
768: wal_set_journal_mode
769: execsql {
770: CREATE TABLE t1(a, b, UNIQUE(a, b));
771: INSERT INTO t1 VALUES(1, randstr(1000,1000));
772: INSERT INTO t1 VALUES(2, randstr(1000,1000));
773: }
774: } {}
775: do_test savepoint-11.2 {
776: execsql {
777: SAVEPOINT one;
778: CREATE TABLE t2(a, b, UNIQUE(a, b));
779: SAVEPOINT two;
780: CREATE TABLE t3(a, b, UNIQUE(a, b));
781: }
782: } {}
783: integrity_check savepoint-11.3
784: do_test savepoint-11.4 {
785: execsql { ROLLBACK TO two }
786: } {}
787: integrity_check savepoint-11.5
788: do_test savepoint-11.6 {
789: execsql {
790: CREATE TABLE t3(a, b, UNIQUE(a, b));
791: ROLLBACK TO one;
792: }
793: } {}
794: integrity_check savepoint-11.7
795: do_test savepoint-11.8 {
796: execsql { ROLLBACK }
797: execsql { PRAGMA wal_checkpoint }
798: file size test.db
799: } {8192}
800:
801: do_test savepoint-11.9 {
802: execsql {
803: DROP TABLE IF EXISTS t1;
804: DROP TABLE IF EXISTS t2;
805: DROP TABLE IF EXISTS t3;
806: }
807: } {}
808: do_test savepoint-11.10 {
809: execsql {
810: BEGIN;
811: CREATE TABLE t1(a, b);
812: CREATE TABLE t2(x, y);
813: INSERT INTO t2 VALUES(1, 2);
814: SAVEPOINT one;
815: INSERT INTO t2 VALUES(3, 4);
816: SAVEPOINT two;
817: DROP TABLE t1;
818: ROLLBACK TO two;
819: }
820: execsql {SELECT * FROM t2}
821: } {1 2 3 4}
822: do_test savepoint-11.11 {
823: execsql COMMIT
824: } {}
825: do_test savepoint-11.12 {
826: execsql {SELECT * FROM t2}
827: } {1 2 3 4}
828: wal_check_journal_mode savepoint-11.13
829:
830: #-------------------------------------------------------------------------
831: # The following tests - savepoint-12.* - test the interaction of
832: # savepoints and "ON CONFLICT ROLLBACK" clauses.
833: #
834: do_test savepoint-12.1 {
835: execsql {
836: CREATE TABLE t4(a PRIMARY KEY, b);
837: INSERT INTO t4 VALUES(1, 'one');
838: }
839: } {}
840: do_test savepoint-12.2 {
841: # The final statement of the following SQL hits a constraint when the
842: # conflict handling mode is "OR ROLLBACK" and there are a couple of
843: # open savepoints. At one point this would fail to clear the internal
844: # record of the open savepoints, resulting in an assert() failure
845: # later on.
846: #
847: catchsql {
848: BEGIN;
849: INSERT INTO t4 VALUES(2, 'two');
850: SAVEPOINT sp1;
851: INSERT INTO t4 VALUES(3, 'three');
852: SAVEPOINT sp2;
853: INSERT OR ROLLBACK INTO t4 VALUES(1, 'one');
854: }
855: } {1 {column a is not unique}}
856: do_test savepoint-12.3 {
857: sqlite3_get_autocommit db
858: } {1}
859: do_test savepoint-12.4 {
860: execsql { SAVEPOINT one }
861: } {}
862: wal_check_journal_mode savepoint-12.5
863:
864: #-------------------------------------------------------------------------
865: # The following tests - savepoint-13.* - test the interaction of
866: # savepoints and "journal_mode = off".
867: #
868: if {[wal_is_wal_mode]==0} {
869: do_test savepoint-13.1 {
870: db close
871: catch {forcedelete test.db}
872: sqlite3 db test.db
873: execsql {
874: BEGIN;
875: CREATE TABLE t1(a PRIMARY KEY, b);
876: INSERT INTO t1 VALUES(1, 2);
877: COMMIT;
878: PRAGMA journal_mode = off;
879: }
880: } {off}
881: do_test savepoint-13.2 {
882: execsql {
883: BEGIN;
884: INSERT INTO t1 VALUES(3, 4);
885: INSERT INTO t1 SELECT a+4,b+4 FROM t1;
886: COMMIT;
887: }
888: } {}
889: do_test savepoint-13.3 {
890: execsql {
891: BEGIN;
892: INSERT INTO t1 VALUES(9, 10);
893: SAVEPOINT s1;
894: INSERT INTO t1 VALUES(11, 12);
895: COMMIT;
896: }
897: } {}
898: do_test savepoint-13.4 {
899: execsql {
900: BEGIN;
901: INSERT INTO t1 VALUES(13, 14);
902: SAVEPOINT s1;
903: INSERT INTO t1 VALUES(15, 16);
904: ROLLBACK TO s1;
905: ROLLBACK;
906: SELECT * FROM t1;
907: }
908: } {1 2 3 4 5 6 7 8 9 10 11 12}
909: }
910:
911: db close
912: delete_file test.db
913: do_multiclient_test tn {
914: do_test savepoint-14.$tn.1 {
915: sql1 {
916: CREATE TABLE foo(x);
917: INSERT INTO foo VALUES(1);
918: INSERT INTO foo VALUES(2);
919: }
920: sql2 {
921: BEGIN;
922: SELECT * FROM foo;
923: }
924: } {1 2}
925: do_test savepoint-14.$tn.2 {
926: sql1 {
927: SAVEPOINT one;
928: INSERT INTO foo VALUES(1);
929: }
930: csql1 { RELEASE one }
931: } {1 {database is locked}}
932: do_test savepoint-14.$tn.3 {
933: sql1 { ROLLBACK TO one }
934: sql2 { COMMIT }
935: sql1 { RELEASE one }
936: } {}
937:
938: do_test savepoint-14.$tn.4 {
939: sql2 {
940: BEGIN;
941: SELECT * FROM foo;
942: }
943: } {1 2}
944: do_test savepoint-14.$tn.5 {
945: sql1 {
946: SAVEPOINT one;
947: INSERT INTO foo VALUES(1);
948: }
949: csql1 { RELEASE one }
950: } {1 {database is locked}}
951: do_test savepoint-14.$tn.6 {
952: sql2 { COMMIT }
953: sql1 {
954: ROLLBACK TO one;
955: INSERT INTO foo VALUES(3);
956: INSERT INTO foo VALUES(4);
957: INSERT INTO foo VALUES(5);
958: RELEASE one;
959: }
960: } {}
961: do_test savepoint-14.$tn.7 {
962: sql2 { CREATE INDEX fooidx ON foo(x); }
963: sql3 { PRAGMA integrity_check }
964: } {ok}
965: }
966:
967: do_multiclient_test tn {
968: do_test savepoint-15.$tn.1 {
969: sql1 {
970: CREATE TABLE foo(x);
971: INSERT INTO foo VALUES(1);
972: INSERT INTO foo VALUES(2);
973: }
974: sql2 { BEGIN; SELECT * FROM foo; }
975: } {1 2}
976: do_test savepoint-15.$tn.2 {
977: sql1 {
978: PRAGMA locking_mode = EXCLUSIVE;
979: BEGIN;
980: INSERT INTO foo VALUES(3);
981: }
982: csql1 { COMMIT }
983: } {1 {database is locked}}
984: do_test savepoint-15.$tn.3 {
985: sql1 { ROLLBACK }
986: sql2 { COMMIT }
987: sql1 {
988: INSERT INTO foo VALUES(3);
989: PRAGMA locking_mode = NORMAL;
990: INSERT INTO foo VALUES(4);
991: }
992: sql2 { CREATE INDEX fooidx ON foo(x); }
993: sql3 { PRAGMA integrity_check }
994: } {ok}
995: }
996:
997: do_multiclient_test tn {
998: do_test savepoint-16.$tn.1 {
999: sql1 {
1000: CREATE TABLE foo(x);
1001: INSERT INTO foo VALUES(1);
1002: INSERT INTO foo VALUES(2);
1003: }
1004: } {}
1005: do_test savepoint-16.$tn.2 {
1006:
1007: db eval {SELECT * FROM foo} {
1008: sql1 { INSERT INTO foo VALUES(3) }
1009: sql2 { SELECT * FROM foo }
1010: sql1 { INSERT INTO foo VALUES(4) }
1011: break
1012: }
1013:
1014: sql2 { CREATE INDEX fooidx ON foo(x); }
1015: sql3 { PRAGMA integrity_check }
1016: } {ok}
1017: do_test savepoint-16.$tn.3 {
1018: sql1 { SELECT * FROM foo }
1019: } {1 2 3 4}
1020: }
1021:
1022: #-------------------------------------------------------------------------
1023: # This next block of tests verifies that a problem reported on the mailing
1024: # list has been resolved. At one point the second "CREATE TABLE t6" would
1025: # fail as table t6 still existed in the internal cache of the db schema
1026: # (even though it had been removed from the database by the ROLLBACK
1027: # command).
1028: #
1029: sqlite3 db test.db
1030: do_execsql_test savepoint-17.1 {
1031: BEGIN;
1032: CREATE TABLE t6(a, b);
1033: INSERT INTO t6 VALUES(1, 2);
1034: SAVEPOINT one;
1035: INSERT INTO t6 VALUES(3, 4);
1036: ROLLBACK TO one;
1037: SELECT * FROM t6;
1038: ROLLBACK;
1039: } {1 2}
1040:
1041: do_execsql_test savepoint-17.2 {
1042: CREATE TABLE t6(a, b);
1043: } {}
1044:
1045: finish_test
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>