/ Check-in [205e5d8a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add the "wal" permutation to run existing test files savepoint.test and savepoint2.test in WAL mode.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | wal
Files: files | file ages | folders
SHA1: 205e5d8ac08f7d7853427b4cd235fca125155d2d
User & Date: dan 2010-04-26 12:39:04
Context
2010-04-26
16:57
Fixes for problems with small caches and SAVEPOINT rollback in WAL mode. check-in: 6a944f02 user: dan tags: wal
12:39
Add the "wal" permutation to run existing test files savepoint.test and savepoint2.test in WAL mode. check-in: 205e5d8a user: dan tags: wal
10:40
Add mutexes to fix a race condition in wal.c. This isn't a very good fix. check-in: 3d159939 user: dan tags: wal
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to test/permutations.test.

751
752
753
754
755
756
757







758
759
760
761
762
763
764
  } -shutdown {
    unregister_demovfs
  } -include {
    insert.test   insert2.test  insert3.test rollback.test 
    select1.test  select2.test  select3.test
  }
}








# End of tests
#############################################################################

if {$::perm::testmode eq "targets"} { puts "" ; exit }

# Restore the [sqlite3] command.







>
>
>
>
>
>
>







751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
  } -shutdown {
    unregister_demovfs
  } -include {
    insert.test   insert2.test  insert3.test rollback.test 
    select1.test  select2.test  select3.test
  }
}

run_tests "wal" -description {
  Run tests with journal_mode=WAL
} -include {
  savepoint.test
  savepoint2.test
}

# End of tests
#############################################################################

if {$::perm::testmode eq "targets"} { puts "" ; exit }

# Restore the [sqlite3] command.

Changes to test/savepoint.test.

10
11
12
13
14
15
16
17
18
19
20
21
22
23

24
25
26
27
28
29
30
..
89
90
91
92
93
94
95

96
97
98
99
100
101
102
...
171
172
173
174
175
176
177

178
179
180
181
182
183




184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
...
260
261
262
263
264
265
266

267
268
269
270
271
272
273
...
308
309
310
311
312
313
314












315
316
317
318
319
320
321
322
323






324
325
326
327
328
329

330
331
332



333

334
335
336
337
338
339
340
341
342
343
344


345
346
347
348
349
350
351
352
353
...
372
373
374
375
376
377
378


379
380
381
382
383
384
385
386
387
388
389


390
391
392
393
394
395
396
397
398
...
445
446
447
448
449
450
451

452
453
454
455
456


457
458
459
460
461
462
463
464
465
...
493
494
495
496
497
498
499

500
501
502
503
504
505
506
...
594
595
596
597
598
599
600

601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715

716
717
718
719
720
721
722
723
724


725
726
727
728
729
730
731
732
733
...
747
748
749
750
751
752
753

754
755
756
757
758
759
760
761
762
763
...
778
779
780
781
782
783
784

785
786
787
788
789
790
791
...
811
812
813
814
815
816
817

818
819
820
821
822

823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863

864
#***********************************************************************
#
# $Id: savepoint.test,v 1.13 2009/07/18 08:30:45 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl


#----------------------------------------------------------------------
# The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE
# and ROLLBACK TO comands are correctly parsed, and that the auto-commit
# flag is correctly set and unset as a result.
#
do_test savepoint-1.1 {

  execsql {
    SAVEPOINT sp1;
    RELEASE sp1;
  }
} {}
do_test savepoint-1.2 {
  execsql {
................................................................................
    SAVEPOINT sp1;
    ROLLBACK TO sp1;
  }
} {}
do_test savepoint-1.6 {
  execsql COMMIT
} {}


#------------------------------------------------------------------------
# These tests - savepoint-2.* - test rollbacks and releases of savepoints
# with a very simple data set.
# 

do_test savepoint-2.1 {
................................................................................
} {1 2 3 a b c d e f}
do_test savepoint-2.11 {
  execsql {
    ROLLBACK;
  }
  execsql { SELECT * FROM t1 }
} {}


#------------------------------------------------------------------------
# This block of tests - savepoint-3.* - test that when a transaction
# savepoint is rolled back, locks are not released from database files.
# And that when a transaction savepoint is released, they are released.
# 




do_test savepoint-3.1 {
  execsql { SAVEPOINT "transaction" }
  execsql { PRAGMA lock_status }
} {main unlocked temp closed}

do_test savepoint-3.2 {
  execsql { INSERT INTO t1 VALUES(1, 2, 3) }
  execsql { PRAGMA lock_status }
} {main reserved temp closed}

do_test savepoint-3.3 {
  execsql { ROLLBACK TO "transaction" }
  execsql { PRAGMA lock_status }
} {main reserved temp closed}

do_test savepoint-3.4 {
  execsql { INSERT INTO t1 VALUES(1, 2, 3) }
  execsql { PRAGMA lock_status }
} {main reserved temp closed}

do_test savepoint-3.5 {
  execsql { RELEASE "transaction" }
  execsql { PRAGMA lock_status }
} {main unlocked temp closed}


#------------------------------------------------------------------------
# Test that savepoints that include schema modifications are handled
# correctly. Test cases savepoint-4.*.
# 
do_test savepoint-4.1 {
  execsql {
................................................................................
    INSERT INTO t3 VALUES('value');
  }
  execsql {SELECT * FROM t3}
} {value}
do_test savepoint-4.8 {
  execsql COMMIT
} {}


#------------------------------------------------------------------------
# Test some logic errors to do with the savepoint feature.
# 

ifcapable incrblob {
  do_test savepoint-5.1.1 {
................................................................................
    catchsql {release def}
  } {1 {cannot release savepoint - SQL statements in progress}}
  do_test savepoint-5.3.5 {
    close $fd
    execsql {release abc}
  } {}
  












  do_test savepoint-5.4.1 {
    execsql {
      SAVEPOINT main;
      INSERT INTO blobs VALUES('another blob');
    }
  } {}
  do_test savepoint-5.4.2 {
    sqlite3 db2 test.db
    execsql { BEGIN ; SELECT * FROM blobs } db2






    catchsql { RELEASE main }
  } {1 {database is locked}}
  do_test savepoint-5.4.3 {
    db2 close
    catchsql { RELEASE main }
  } {0 {}}

  do_test savepoint-5.4.4 {
    execsql { SELECT x FROM blobs WHERE rowid = 2 }
  } {{another blob}}



}


#-------------------------------------------------------------------------
# The following tests, savepoint-6.*, test an incr-vacuum inside of a
# couple of nested savepoints.
#
ifcapable {autovacuum && pragma} {
  db close
  file delete -force test.db
  sqlite3 db test.db

  do_test savepoint-6.1 {


    execsql { 
      PRAGMA auto_vacuum = incremental;
      CREATE TABLE t1(a, b, c);
      CREATE INDEX i1 ON t1(a, b);
      BEGIN;
      INSERT INTO t1 VALUES(randstr(10,400),randstr(10,400),randstr(10,400));
    }
    set r "randstr(10,400)"
    for {set ii 0} {$ii < 10} {incr ii} {
................................................................................
            PRAGMA incr_vacuum;
        ROLLBACK TO one;
      COMMIT;
    }
  } {}

  integrity_check savepoint-6.4


}

#-------------------------------------------------------------------------
# The following tests, savepoint-7.*, attempt to break the logic 
# surrounding savepoints by growing and shrinking the database file.
#
db close
file delete -force test.db
sqlite3 db test.db

do_test savepoint-7.1 {


  execsql {
    PRAGMA auto_vacuum = incremental;
    PRAGMA cache_size = 10;
    BEGIN;
    CREATE TABLE t1(a PRIMARY KEY, b);
      INSERT INTO t1(a) VALUES('alligator');
      INSERT INTO t1(a) VALUES('angelfish');
      INSERT INTO t1(a) VALUES('ant');
      INSERT INTO t1(a) VALUES('antelope');
................................................................................
        SAVEPOINT two;
          INSERT INTO t2 SELECT a, b FROM t1;
        ROLLBACK TO two;
    COMMIT;
  }
  execsql { PRAGMA integrity_check }
} {ok}


do_test savepoint-7.4.1 {
  db close
  file delete -force test.db
  sqlite3 db test.db


  execsql {
    PRAGMA auto_vacuum = incremental;
    CREATE TABLE t1(a, b, PRIMARY KEY(a, b));
    INSERT INTO t1 VALUES(randstr(1000,1000), randstr(1000,1000));
    BEGIN;
      DELETE FROM t1;
      SAVEPOINT one;
      PRAGMA incremental_vacuum;
      ROLLBACK TO one;
................................................................................
  }
} {ok}
do_test savepoint-7.5.2 {
  execsql {
    DROP TABLE t5;
  }
} {}


# Test oddly named and quoted savepoints.
#
do_test savepoint-8-1 {
  execsql { SAVEPOINT "save1" }
  execsql { RELEASE save1 }
} {}
................................................................................
# The lock state of the TEMP database can vary if SQLITE_TEMP_STORE=3
# And the following set of tests is only really interested in the status
# of the aux1 and aux2 locks.  So record the current lock status of
# TEMP for use in the answers.
set templockstate [lindex [db eval {PRAGMA lock_status}] 3]



do_test savepoint-10.2.1 {
  file delete -force test3.db
  file delete -force test2.db
  execsql {
    ATTACH 'test2.db' AS aux1;
    ATTACH 'test3.db' AS aux2;
    DROP TABLE t1;
    CREATE TABLE main.t1(x, y);
    CREATE TABLE aux1.t2(x, y);
    CREATE TABLE aux2.t3(x, y);
    SELECT name FROM sqlite_master 
      UNION ALL
    SELECT name FROM aux1.sqlite_master 
      UNION ALL
    SELECT name FROM aux2.sqlite_master;
  }
} {t1 t2 t3}
do_test savepoint-10.2.2 {
  execsql { PRAGMA lock_status }
} [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked]

do_test savepoint-10.2.3 {
  execsql {
    SAVEPOINT one;
    INSERT INTO t1 VALUES(1, 2);
    PRAGMA lock_status;
  }
} [list main reserved temp $templockstate aux1 unlocked aux2 unlocked]
do_test savepoint-10.2.4 {
  execsql {
    INSERT INTO t3 VALUES(3, 4);
    PRAGMA lock_status;
  }
} [list main reserved temp $templockstate aux1 unlocked aux2 reserved]
do_test savepoint-10.2.5 {
  execsql {
    SAVEPOINT two;
    INSERT INTO t2 VALUES(5, 6);
    PRAGMA lock_status;
  }
} [list main reserved temp $templockstate aux1 reserved aux2 reserved]
do_test savepoint-10.2.6 {
  execsql { SELECT * FROM t2 }
} {5 6}
do_test savepoint-10.2.7 {
  execsql { ROLLBACK TO two }
  execsql { SELECT * FROM t2 }
} {}
do_test savepoint-10.2.8 {
  execsql { PRAGMA lock_status }
} [list main reserved temp $templockstate aux1 reserved aux2 reserved]
do_test savepoint-10.2.9 {
  execsql { SELECT 'a', * FROM t1 UNION ALL SELECT 'b', * FROM t3 }
} {a 1 2 b 3 4}
do_test savepoint-10.2.9 {
  execsql {
    INSERT INTO t2 VALUES(5, 6);
    RELEASE one;
  }
  execsql { 
    SELECT * FROM t1;
    SELECT * FROM t2;
    SELECT * FROM t3;
  }
} {1 2 5 6 3 4}
do_test savepoint-10.2.9 {
  execsql { PRAGMA lock_status }
} [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked]

do_test savepoint-10.2.10 {
  execsql { 
    SAVEPOINT one;
      INSERT INTO t1 VALUES('a', 'b');
      SAVEPOINT two;
        INSERT INTO t2 VALUES('c', 'd');
        SAVEPOINT three;
          INSERT INTO t3 VALUES('e', 'f');
  }
  execsql { 
    SELECT * FROM t1;
    SELECT * FROM t2;
    SELECT * FROM t3;
  }
} {1 2 a b 5 6 c d 3 4 e f}
do_test savepoint-10.2.11 {
  execsql { ROLLBACK TO two }
  execsql { 
    SELECT * FROM t1;
    SELECT * FROM t2;
    SELECT * FROM t3;
  }
} {1 2 a b 5 6 3 4}
do_test savepoint-10.2.12 {
  execsql { 
    INSERT INTO t3 VALUES('g', 'h');
    ROLLBACK TO two;
  }
  execsql { 
    SELECT * FROM t1;
    SELECT * FROM t2;
    SELECT * FROM t3;
  }
} {1 2 a b 5 6 3 4}
do_test savepoint-10.2.13 {
  execsql { ROLLBACK }
  execsql { 
    SELECT * FROM t1;
    SELECT * FROM t2;
    SELECT * FROM t3;
  }
} {1 2 5 6 3 4}
do_test savepoint-10.2.14 {
  execsql { PRAGMA lock_status }
} [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked]


#-------------------------------------------------------------------------
# The following tests - savepoint-11.* - test the interaction of 
# savepoints and creating or dropping tables and indexes in 
# auto-vacuum mode.
# 
do_test savepoint-11.1 {
  db close
  file delete -force test.db
  sqlite3 db test.db


  execsql {
    PRAGMA auto_vacuum = full;
    CREATE TABLE t1(a, b, UNIQUE(a, b));
    INSERT INTO t1 VALUES(1, randstr(1000,1000));
    INSERT INTO t1 VALUES(2, randstr(1000,1000));
  }
} {}
do_test savepoint-11.2 {
  execsql {
................................................................................
    CREATE TABLE t3(a, b, UNIQUE(a, b));
    ROLLBACK TO one;
  }
} {}
integrity_check savepoint-11.7
do_test savepoint-11.8 {
  execsql { ROLLBACK }

  file size test.db
} {8192}


do_test savepoint-11.9 {
  execsql {
    DROP TABLE IF EXISTS t1;
    DROP TABLE IF EXISTS t2;
    DROP TABLE IF EXISTS t3;
  }
................................................................................
} {1 2 3 4}
do_test savepoint-11.11 {
  execsql COMMIT
} {}
do_test savepoint-11.12 {
  execsql {SELECT * FROM t2}
} {1 2 3 4}


#-------------------------------------------------------------------------
# The following tests - savepoint-12.* - test the interaction of 
# savepoints and "ON CONFLICT ROLLBACK" clauses.
# 
do_test savepoint-12.1 {
  execsql {
................................................................................
} {1 {column a is not unique}}
do_test savepoint-12.3 {
  sqlite3_get_autocommit db
} {1}
do_test savepoint-12.4 {
  execsql { SAVEPOINT one }
} {}


#-------------------------------------------------------------------------
# The following tests - savepoint-13.* - test the interaction of 
# savepoints and "journal_mode = off".
# 

do_test savepoint-13.1 {
  db close
  catch {file delete -force test.db}
  sqlite3 db test.db
  execsql {
    BEGIN;
      CREATE TABLE t1(a PRIMARY KEY, b);
      INSERT INTO t1 VALUES(1, 2);
    COMMIT;
    PRAGMA journal_mode = off;
  }
} {off}
do_test savepoint-13.2 {
  execsql {
    BEGIN;
    INSERT INTO t1 VALUES(3, 4);
    INSERT INTO t1 SELECT a+4,b+4  FROM t1;
    COMMIT;
  }
} {}
do_test savepoint-13.3 {
  execsql {
    BEGIN;
      INSERT INTO t1 VALUES(9, 10);
      SAVEPOINT s1;
        INSERT INTO t1 VALUES(11, 12);
    COMMIT;
  }
} {}
do_test savepoint-13.4 {
  execsql {
    BEGIN;
      INSERT INTO t1 VALUES(13, 14);
      SAVEPOINT s1;
        INSERT INTO t1 VALUES(15, 16);
      ROLLBACK TO s1;
    ROLLBACK;
    SELECT * FROM t1;
  }
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}


finish_test







<






>







 







>







 







>





|
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>








|
>
>
>
>
>
>
|
|
|
|
|
|
>
|


>
>
>

>











>
>
|
<







 







>
>











>
>

<







 







>





>
>

<







 







>







 







>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>









>
>

<







 







>


<







 







>







 







>





>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>

10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
25
26
27
28
29
30
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378

379
380
381
382
383
384
385
...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426

427
428
429
430
431
432
433
...
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495

496
497
498
499
500
501
502
...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
...
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767

768
769
770
771
772
773
774
...
788
789
790
791
792
793
794
795
796
797

798
799
800
801
802
803
804
...
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
...
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
#***********************************************************************
#
# $Id: savepoint.test,v 1.13 2009/07/18 08:30:45 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl


#----------------------------------------------------------------------
# The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE
# and ROLLBACK TO comands are correctly parsed, and that the auto-commit
# flag is correctly set and unset as a result.
#
do_test savepoint-1.1 {
  wal_set_journal_mode
  execsql {
    SAVEPOINT sp1;
    RELEASE sp1;
  }
} {}
do_test savepoint-1.2 {
  execsql {
................................................................................
    SAVEPOINT sp1;
    ROLLBACK TO sp1;
  }
} {}
do_test savepoint-1.6 {
  execsql COMMIT
} {}
wal_check_journal_mode savepoint-1.7

#------------------------------------------------------------------------
# These tests - savepoint-2.* - test rollbacks and releases of savepoints
# with a very simple data set.
# 

do_test savepoint-2.1 {
................................................................................
} {1 2 3 a b c d e f}
do_test savepoint-2.11 {
  execsql {
    ROLLBACK;
  }
  execsql { SELECT * FROM t1 }
} {}
wal_check_journal_mode savepoint-2.12

#------------------------------------------------------------------------
# This block of tests - savepoint-3.* - test that when a transaction
# savepoint is rolled back, locks are not released from database files.
# And that when a transaction savepoint is released, they are released.
#
# These tests do not work in WAL mode. WAL mode does not take RESERVED
# locks on the database file.
# 
if {[wal_is_wal_mode]==0} {
  do_test savepoint-3.1 {
    execsql { SAVEPOINT "transaction" }
    execsql { PRAGMA lock_status }
  } {main unlocked temp closed}
  
  do_test savepoint-3.2 {
    execsql { INSERT INTO t1 VALUES(1, 2, 3) }
    execsql { PRAGMA lock_status }
  } {main reserved temp closed}
  
  do_test savepoint-3.3 {
    execsql { ROLLBACK TO "transaction" }
    execsql { PRAGMA lock_status }
  } {main reserved temp closed}
  
  do_test savepoint-3.4 {
    execsql { INSERT INTO t1 VALUES(1, 2, 3) }
    execsql { PRAGMA lock_status }
  } {main reserved temp closed}
  
  do_test savepoint-3.5 {
    execsql { RELEASE "transaction" }
    execsql { PRAGMA lock_status }
  } {main unlocked temp closed}
}

#------------------------------------------------------------------------
# Test that savepoints that include schema modifications are handled
# correctly. Test cases savepoint-4.*.
# 
do_test savepoint-4.1 {
  execsql {
................................................................................
    INSERT INTO t3 VALUES('value');
  }
  execsql {SELECT * FROM t3}
} {value}
do_test savepoint-4.8 {
  execsql COMMIT
} {}
wal_check_journal_mode savepoint-4.9

#------------------------------------------------------------------------
# Test some logic errors to do with the savepoint feature.
# 

ifcapable incrblob {
  do_test savepoint-5.1.1 {
................................................................................
    catchsql {release def}
  } {1 {cannot release savepoint - SQL statements in progress}}
  do_test savepoint-5.3.5 {
    close $fd
    execsql {release abc}
  } {}
  
  # Rollback mode:
  #
  #   Open a savepoint transaction and insert a row into the database. Then,
  #   using a second database handle, open a read-only transaction on the
  #   database file. Check that the savepoint transaction cannot be committed
  #   until after the read-only transaction has been closed.
  #
  # WAL mode:
  # 
  #   As above, except that the savepoint transaction can be successfully
  #   committed before the read-only transaction has been closed.
  #
  do_test savepoint-5.4.1 {
    execsql {
      SAVEPOINT main;
      INSERT INTO blobs VALUES('another blob');
    }
  } {}
  do_test savepoint-5.4.2 {
    sqlite3 db2 test.db
    execsql { BEGIN ; SELECT count(*) FROM blobs } db2
  } {1}
  if {[wal_is_wal_mode]} {
    do_test savepoint-5.4.3 { catchsql "RELEASE main" } {0 {}}
    do_test savepoint-5.4.4 { db2 close               } {}
  } else {
    do_test savepoint-5.4.3 {
      catchsql { RELEASE main }
    } {1 {database is locked}}
    do_test savepoint-5.4.4 {
      db2 close
      catchsql { RELEASE main }
    } {0 {}}
  }
  do_test savepoint-5.4.5 {
    execsql { SELECT x FROM blobs WHERE rowid = 2 }
  } {{another blob}}
  do_test savepoint-5.4.6 {
    execsql { SELECT count(*) FROM blobs }
  } {2}
}
wal_check_journal_mode savepoint-5.5

#-------------------------------------------------------------------------
# The following tests, savepoint-6.*, test an incr-vacuum inside of a
# couple of nested savepoints.
#
ifcapable {autovacuum && pragma} {
  db close
  file delete -force test.db
  sqlite3 db test.db

  do_test savepoint-6.1 {
    execsql { PRAGMA auto_vacuum = incremental }
    wal_set_journal_mode
    execsql {

      CREATE TABLE t1(a, b, c);
      CREATE INDEX i1 ON t1(a, b);
      BEGIN;
      INSERT INTO t1 VALUES(randstr(10,400),randstr(10,400),randstr(10,400));
    }
    set r "randstr(10,400)"
    for {set ii 0} {$ii < 10} {incr ii} {
................................................................................
            PRAGMA incr_vacuum;
        ROLLBACK TO one;
      COMMIT;
    }
  } {}

  integrity_check savepoint-6.4

  wal_check_journal_mode savepoint-6.5
}

#-------------------------------------------------------------------------
# The following tests, savepoint-7.*, attempt to break the logic 
# surrounding savepoints by growing and shrinking the database file.
#
db close
file delete -force test.db
sqlite3 db test.db

do_test savepoint-7.1 {
  execsql { PRAGMA auto_vacuum = incremental }
  wal_set_journal_mode
  execsql {

    PRAGMA cache_size = 10;
    BEGIN;
    CREATE TABLE t1(a PRIMARY KEY, b);
      INSERT INTO t1(a) VALUES('alligator');
      INSERT INTO t1(a) VALUES('angelfish');
      INSERT INTO t1(a) VALUES('ant');
      INSERT INTO t1(a) VALUES('antelope');
................................................................................
        SAVEPOINT two;
          INSERT INTO t2 SELECT a, b FROM t1;
        ROLLBACK TO two;
    COMMIT;
  }
  execsql { PRAGMA integrity_check }
} {ok}
wal_check_journal_mode savepoint-7.3.3

do_test savepoint-7.4.1 {
  db close
  file delete -force test.db
  sqlite3 db test.db
  execsql { PRAGMA auto_vacuum = incremental }
  wal_set_journal_mode
  execsql {

    CREATE TABLE t1(a, b, PRIMARY KEY(a, b));
    INSERT INTO t1 VALUES(randstr(1000,1000), randstr(1000,1000));
    BEGIN;
      DELETE FROM t1;
      SAVEPOINT one;
      PRAGMA incremental_vacuum;
      ROLLBACK TO one;
................................................................................
  }
} {ok}
do_test savepoint-7.5.2 {
  execsql {
    DROP TABLE t5;
  }
} {}
wal_check_journal_mode savepoint-7.5.3

# Test oddly named and quoted savepoints.
#
do_test savepoint-8-1 {
  execsql { SAVEPOINT "save1" }
  execsql { RELEASE save1 }
} {}
................................................................................
# The lock state of the TEMP database can vary if SQLITE_TEMP_STORE=3
# And the following set of tests is only really interested in the status
# of the aux1 and aux2 locks.  So record the current lock status of
# TEMP for use in the answers.
set templockstate [lindex [db eval {PRAGMA lock_status}] 3]


if {[wal_is_wal_mode]==0} {
  do_test savepoint-10.2.1 {
    file delete -force test3.db
    file delete -force test2.db
    execsql {
      ATTACH 'test2.db' AS aux1;
      ATTACH 'test3.db' AS aux2;
      DROP TABLE t1;
      CREATE TABLE main.t1(x, y);
      CREATE TABLE aux1.t2(x, y);
      CREATE TABLE aux2.t3(x, y);
      SELECT name FROM sqlite_master 
        UNION ALL
      SELECT name FROM aux1.sqlite_master 
        UNION ALL
      SELECT name FROM aux2.sqlite_master;
    }
  } {t1 t2 t3}
  do_test savepoint-10.2.2 {
    execsql { PRAGMA lock_status }
  } [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked]
  
  do_test savepoint-10.2.3 {
    execsql {
      SAVEPOINT one;
      INSERT INTO t1 VALUES(1, 2);
      PRAGMA lock_status;
    }
  } [list main reserved temp $templockstate aux1 unlocked aux2 unlocked]
  do_test savepoint-10.2.4 {
    execsql {
      INSERT INTO t3 VALUES(3, 4);
      PRAGMA lock_status;
    }
  } [list main reserved temp $templockstate aux1 unlocked aux2 reserved]
  do_test savepoint-10.2.5 {
    execsql {
      SAVEPOINT two;
      INSERT INTO t2 VALUES(5, 6);
      PRAGMA lock_status;
    }
  } [list main reserved temp $templockstate aux1 reserved aux2 reserved]
  do_test savepoint-10.2.6 {
    execsql { SELECT * FROM t2 }
  } {5 6}
  do_test savepoint-10.2.7 {
    execsql { ROLLBACK TO two }
    execsql { SELECT * FROM t2 }
  } {}
  do_test savepoint-10.2.8 {
    execsql { PRAGMA lock_status }
  } [list main reserved temp $templockstate aux1 reserved aux2 reserved]
  do_test savepoint-10.2.9 {
    execsql { SELECT 'a', * FROM t1 UNION ALL SELECT 'b', * FROM t3 }
  } {a 1 2 b 3 4}
  do_test savepoint-10.2.9 {
    execsql {
      INSERT INTO t2 VALUES(5, 6);
      RELEASE one;
    }
    execsql { 
      SELECT * FROM t1;
      SELECT * FROM t2;
      SELECT * FROM t3;
    }
  } {1 2 5 6 3 4}
  do_test savepoint-10.2.9 {
    execsql { PRAGMA lock_status }
  } [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked]
  
  do_test savepoint-10.2.10 {
    execsql { 
      SAVEPOINT one;
        INSERT INTO t1 VALUES('a', 'b');
        SAVEPOINT two;
          INSERT INTO t2 VALUES('c', 'd');
          SAVEPOINT three;
            INSERT INTO t3 VALUES('e', 'f');
    }
    execsql { 
      SELECT * FROM t1;
      SELECT * FROM t2;
      SELECT * FROM t3;
    }
  } {1 2 a b 5 6 c d 3 4 e f}
  do_test savepoint-10.2.11 {
    execsql { ROLLBACK TO two }
    execsql { 
      SELECT * FROM t1;
      SELECT * FROM t2;
      SELECT * FROM t3;
    }
  } {1 2 a b 5 6 3 4}
  do_test savepoint-10.2.12 {
    execsql { 
      INSERT INTO t3 VALUES('g', 'h');
      ROLLBACK TO two;
    }
    execsql { 
      SELECT * FROM t1;
      SELECT * FROM t2;
      SELECT * FROM t3;
    }
  } {1 2 a b 5 6 3 4}
  do_test savepoint-10.2.13 {
    execsql { ROLLBACK }
    execsql { 
      SELECT * FROM t1;
      SELECT * FROM t2;
      SELECT * FROM t3;
    }
  } {1 2 5 6 3 4}
  do_test savepoint-10.2.14 {
    execsql { PRAGMA lock_status }
  } [list main unlocked temp $templockstate aux1 unlocked aux2 unlocked]
}

#-------------------------------------------------------------------------
# The following tests - savepoint-11.* - test the interaction of 
# savepoints and creating or dropping tables and indexes in 
# auto-vacuum mode.
# 
do_test savepoint-11.1 {
  db close
  file delete -force test.db
  sqlite3 db test.db
  execsql { PRAGMA auto_vacuum = full; }
  wal_set_journal_mode
  execsql {

    CREATE TABLE t1(a, b, UNIQUE(a, b));
    INSERT INTO t1 VALUES(1, randstr(1000,1000));
    INSERT INTO t1 VALUES(2, randstr(1000,1000));
  }
} {}
do_test savepoint-11.2 {
  execsql {
................................................................................
    CREATE TABLE t3(a, b, UNIQUE(a, b));
    ROLLBACK TO one;
  }
} {}
integrity_check savepoint-11.7
do_test savepoint-11.8 {
  execsql { ROLLBACK }
  execsql { PRAGMA checkpoint }
  file size test.db
} {8192}


do_test savepoint-11.9 {
  execsql {
    DROP TABLE IF EXISTS t1;
    DROP TABLE IF EXISTS t2;
    DROP TABLE IF EXISTS t3;
  }
................................................................................
} {1 2 3 4}
do_test savepoint-11.11 {
  execsql COMMIT
} {}
do_test savepoint-11.12 {
  execsql {SELECT * FROM t2}
} {1 2 3 4}
wal_check_journal_mode savepoint-11.13

#-------------------------------------------------------------------------
# The following tests - savepoint-12.* - test the interaction of 
# savepoints and "ON CONFLICT ROLLBACK" clauses.
# 
do_test savepoint-12.1 {
  execsql {
................................................................................
} {1 {column a is not unique}}
do_test savepoint-12.3 {
  sqlite3_get_autocommit db
} {1}
do_test savepoint-12.4 {
  execsql { SAVEPOINT one }
} {}
wal_check_journal_mode savepoint-12.5

#-------------------------------------------------------------------------
# The following tests - savepoint-13.* - test the interaction of 
# savepoints and "journal_mode = off".
# 
if {[wal_is_wal_mode]==0} {
  do_test savepoint-13.1 {
    db close
    catch {file delete -force test.db}
    sqlite3 db test.db
    execsql {
      BEGIN;
        CREATE TABLE t1(a PRIMARY KEY, b);
        INSERT INTO t1 VALUES(1, 2);
      COMMIT;
      PRAGMA journal_mode = off;
    }
  } {off}
  do_test savepoint-13.2 {
    execsql {
      BEGIN;
      INSERT INTO t1 VALUES(3, 4);
      INSERT INTO t1 SELECT a+4,b+4  FROM t1;
      COMMIT;
    }
  } {}
  do_test savepoint-13.3 {
    execsql {
      BEGIN;
        INSERT INTO t1 VALUES(9, 10);
        SAVEPOINT s1;
          INSERT INTO t1 VALUES(11, 12);
      COMMIT;
    }
  } {}
  do_test savepoint-13.4 {
    execsql {
      BEGIN;
        INSERT INTO t1 VALUES(13, 14);
        SAVEPOINT s1;
          INSERT INTO t1 VALUES(15, 16);
        ROLLBACK TO s1;
      ROLLBACK;
      SELECT * FROM t1;
    }
  } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
}

finish_test

Changes to test/savepoint2.test.

9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24
25

26
27
28
29
30
31
32
..
38
39
40
41
42
43
44

45
46
47
48
49
50
51
...
136
137
138
139
140
141
142



143
144
145
146
147
148
#
#***********************************************************************
#
# $Id: savepoint2.test,v 1.5 2009/06/05 17:09:12 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl


# Tests in this file are quite similar to those run by trans.test and
# avtrans.test.
#

proc signature {} {
  return [db eval {SELECT count(*), md5sum(x) FROM t3}]
}

do_test savepoint2-1 {

  execsql {
    PRAGMA cache_size=10;
    BEGIN;
    CREATE TABLE t3(x TEXT);
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
................................................................................
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    COMMIT;
    SELECT count(*) FROM t3;
  }
} {1024}


unset -nocomplain ::sig
unset -nocomplain SQL

set iterations 20

set SQL(1) {
................................................................................
  #
  do_test savepoint2-$ii.6 {
    execsql $SQL(4)
    execsql COMMIT
    sqlite3_get_autocommit db
  } {1}
  integrity_check savepoint2-$ii.6.1



}

unset -nocomplain ::sig
unset -nocomplain SQL

finish_test







>










>







 







>







 







>
>
>






9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
..
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#
#***********************************************************************
#
# $Id: savepoint2.test,v 1.5 2009/06/05 17:09:12 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl


# Tests in this file are quite similar to those run by trans.test and
# avtrans.test.
#

proc signature {} {
  return [db eval {SELECT count(*), md5sum(x) FROM t3}]
}

do_test savepoint2-1 {
  wal_set_journal_mode
  execsql {
    PRAGMA cache_size=10;
    BEGIN;
    CREATE TABLE t3(x TEXT);
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
................................................................................
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    COMMIT;
    SELECT count(*) FROM t3;
  }
} {1024}
wal_check_journal_mode savepoint2-1.1

unset -nocomplain ::sig
unset -nocomplain SQL

set iterations 20

set SQL(1) {
................................................................................
  #
  do_test savepoint2-$ii.6 {
    execsql $SQL(4)
    execsql COMMIT
    sqlite3_get_autocommit db
  } {1}
  integrity_check savepoint2-$ii.6.1

  # Check that the connection is still running in WAL mode.
  wal_check_journal_mode savepoint2-$ii.7
}

unset -nocomplain ::sig
unset -nocomplain SQL

finish_test

Changes to test/tester.tcl.

978
979
980
981
982
983
984




































985
986
987
988
989
990
991
      $db eval "DROP $type $t"
    }
  }
  ifcapable trigger&&foreignkey {
    $db eval "PRAGMA foreign_keys = $pk"
  }
}






































# If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set
# to non-zero, then set the global variable $AUTOVACUUM to 1.
set AUTOVACUUM $sqlite_options(default_autovacuum)

source $testdir/thread_common.tcl







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
      $db eval "DROP $type $t"
    }
  }
  ifcapable trigger&&foreignkey {
    $db eval "PRAGMA foreign_keys = $pk"
  }
}

#-------------------------------------------------------------------------
# If a test script is executed with global variable 
# $::permutations_test_prefix set to "wal", then the tests are run
# in WAL mode. Otherwise, they should be run in rollback mode. The 
# following Tcl procs are used to make this less intrusive:
#
#   wal_set_journal_mode ?DB?
#
#     If running a WAL test, execute "PRAGMA journal_mode = wal" using
#     connection handle DB. Otherwise, this command is a no-op.
#
#   wal_check_journal_mode TESTNAME ?DB?
#
#     If running a WAL test, execute a tests case that fails if the main
#     database for connection handle DB is not currently a WAL database.
#     Otherwise (if not running a WAL permutation) this is a no-op.
#
#   wal_is_wal_mode
#   
#     Returns true if this test should be run in WAL mode. False otherwise.
# 
proc wal_is_wal_mode {} {
  expr { [catch {set ::permutations_test_prefix} v]==0 && $v == "wal" }
}
proc wal_set_journal_mode {{db db}} {
  if { [wal_is_wal_mode] } {
    $db eval "PRAGMA journal_mode = WAL"
  }
}
proc wal_check_journal_mode {testname {db db}} {
  if { [wal_is_wal_mode] } {
    $db eval { SELECT * FROM sqlite_master }
    do_test $testname [list $db eval "PRAGMA main.journal_mode"] {wal}
  }
}


# If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set
# to non-zero, then set the global variable $AUTOVACUUM to 1.
set AUTOVACUUM $sqlite_options(default_autovacuum)

source $testdir/thread_common.tcl