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 14set testdir [file dirname $argv0] 15source $testdir/tester.tcl 16source $testdir/lock_common.tcl 17source $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# 24do_test savepoint-1.1 { 25 wal_set_journal_mode 26 execsql { 27 SAVEPOINT sp1; 28 RELEASE sp1; 29 } 30} {} 31do_test savepoint-1.2 { 32 execsql { 33 SAVEPOINT sp1; 34 ROLLBACK TO sp1; 35 } 36} {} 37do_test savepoint-1.3 { 38 execsql { SAVEPOINT sp1 } 39 db close 40} {} 41sqlite3 db test.db 42do_test savepoint-1.4.1 { 43 execsql { 44 SAVEPOINT sp1; 45 SAVEPOINT sp2; 46 RELEASE sp1; 47 } 48 sqlite3_get_autocommit db 49} {1} 50do_test savepoint-1.4.2 { 51 execsql { 52 SAVEPOINT sp1; 53 SAVEPOINT sp2; 54 RELEASE sp2; 55 } 56 sqlite3_get_autocommit db 57} {0} 58do_test savepoint-1.4.3 { 59 execsql { RELEASE sp1 } 60 sqlite3_get_autocommit db 61} {1} 62do_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} 70do_test savepoint-1.4.5 { 71 execsql { RELEASE SAVEPOINT sp1 } 72 sqlite3_get_autocommit db 73} {1} 74do_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} 85do_test savepoint-1.4.7 { 86 execsql { RELEASE SAVEPOINT SP1 } 87 sqlite3_get_autocommit db 88} {1} 89do_test savepoint-1.5 { 90 execsql { 91 SAVEPOINT sp1; 92 ROLLBACK TO sp1; 93 } 94} {} 95do_test savepoint-1.6 { 96 execsql COMMIT 97} {} 98wal_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 105do_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} 115do_test savepoint-2.2 { 116 execsql { 117 ROLLBACK TO one; 118 } 119 execsql { SELECT * FROM t1 } 120} {1 2 3} 121do_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} 127do_test savepoint-2.4 { 128 execsql { 129 ROLLBACK TO one; 130 } 131 execsql { SELECT * FROM t1 } 132} {1 2 3} 133 134 135do_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} 143do_test savepoint-2.6 { 144 execsql { 145 ROLLBACK TO two; 146 } 147 execsql { SELECT * FROM t1 } 148} {1 2 3 7 8 9} 149do_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} 155do_test savepoint-2.8 { 156 execsql { 157 ROLLBACK TO one; 158 } 159 execsql { SELECT * FROM t1 } 160} {1 2 3} 161do_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} 169do_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} 175do_test savepoint-2.11 { 176 execsql { 177 ROLLBACK; 178 } 179 execsql { SELECT * FROM t1 } 180} {} 181wal_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# 191if {[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# 222do_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)}} 228do_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} {} 237do_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} 244do_test savepoint-4.4 { 245 execsql { ROLLBACK TO one; } 246 execsql {SELECT * FROM t3} 247} {I II} 248do_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 255do_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} 265do_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} 273do_test savepoint-4.8 { 274 execsql COMMIT 275} {} 276wal_check_journal_mode savepoint-4.9 277 278#------------------------------------------------------------------------ 279# Test some logic errors to do with the savepoint feature. 280# 281 282ifcapable 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} 366wal_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# 372ifcapable {autovacuum && pragma} { 373 db close 374 file delete -force 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# 421db close 422file delete -force test.db 423sqlite3 db test.db 424 425do_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} 451do_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} 463do_test savepoint-7.2.2 { 464 execsql { 465 COMMIT; 466 PRAGMA integrity_check; 467 } 468} {ok} 469 470do_test savepoint-7.3.1 { 471 execsql { 472 CREATE TABLE t2(a, b); 473 INSERT INTO t2 SELECT a, b FROM t1; 474 } 475} {} 476do_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} 489wal_check_journal_mode savepoint-7.3.3 490 491do_test savepoint-7.4.1 { 492 db close 493 file delete -force 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 511do_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} 534do_test savepoint-7.5.2 { 535 execsql { 536 DROP TABLE t5; 537 } 538} {} 539wal_check_journal_mode savepoint-7.5.3 540 541# Test oddly named and quoted savepoints. 542# 543do_test savepoint-8-1 { 544 execsql { SAVEPOINT "save1" } 545 execsql { RELEASE save1 } 546} {} 547do_test savepoint-8-2 { 548 execsql { SAVEPOINT "Including whitespace " } 549 execsql { RELEASE "including Whitespace " } 550} {} 551 552# Test that the authorization callback works. 553# 554ifcapable 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# 611do_test savepoint-10.1.1 { 612 catchsql { 613 SAVEPOINT one; 614 ATTACH 'test2.db' AS aux; 615 } 616} {1 {cannot ATTACH database within transaction}} 617do_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}} 627do_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. 638set templockstate [lindex [db eval {PRAGMA lock_status}] 3] 639 640 641if {[wal_is_wal_mode]==0} { 642 do_test savepoint-10.2.1 { 643 file delete -force test3.db 644 file delete -force 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# 763do_test savepoint-11.1 { 764 db close 765 file delete -force 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} {} 775do_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} {} 783integrity_check savepoint-11.3 784do_test savepoint-11.4 { 785 execsql { ROLLBACK TO two } 786} {} 787integrity_check savepoint-11.5 788do_test savepoint-11.6 { 789 execsql { 790 CREATE TABLE t3(a, b, UNIQUE(a, b)); 791 ROLLBACK TO one; 792 } 793} {} 794integrity_check savepoint-11.7 795do_test savepoint-11.8 { 796 execsql { ROLLBACK } 797 execsql { PRAGMA wal_checkpoint } 798 file size test.db 799} {8192} 800 801do_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} {} 808do_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} 822do_test savepoint-11.11 { 823 execsql COMMIT 824} {} 825do_test savepoint-11.12 { 826 execsql {SELECT * FROM t2} 827} {1 2 3 4} 828wal_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# 834do_test savepoint-12.1 { 835 execsql { 836 CREATE TABLE t4(a PRIMARY KEY, b); 837 INSERT INTO t4 VALUES(1, 'one'); 838 } 839} {} 840do_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}} 856do_test savepoint-12.3 { 857 sqlite3_get_autocommit db 858} {1} 859do_test savepoint-12.4 { 860 execsql { SAVEPOINT one } 861} {} 862wal_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# 868if {[wal_is_wal_mode]==0} { 869 do_test savepoint-13.1 { 870 db close 871 catch {file delete -force 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 911db close 912file delete test.db 913do_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 967do_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 997do_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# 1029sqlite3 db test.db 1030do_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 1041do_execsql_test savepoint-17.2 { 1042 CREATE TABLE t6(a, b); 1043} {} 1044 1045finish_test 1046