Home | History | Annotate | Download | only in test
      1 # 2001 September 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 # This file implements regression tests for SQLite library.  The
     12 # focus of this file is testing the 'progress callback'.
     13 #
     14 # $Id: progress.test,v 1.8 2007/06/15 14:53:53 danielk1977 Exp $
     15 
     16 set testdir [file dirname $argv0]
     17 source $testdir/tester.tcl
     18 
     19 # If the progress callback is not available in this build, skip this
     20 # whole file.
     21 ifcapable !progress {
     22   finish_test
     23   return
     24 }
     25 
     26 # Build some test data
     27 #
     28 execsql {
     29   BEGIN;
     30   CREATE TABLE t1(a);
     31   INSERT INTO t1 VALUES(1);
     32   INSERT INTO t1 VALUES(2);
     33   INSERT INTO t1 VALUES(3);
     34   INSERT INTO t1 VALUES(4);
     35   INSERT INTO t1 VALUES(5);
     36   INSERT INTO t1 VALUES(6);
     37   INSERT INTO t1 VALUES(7);
     38   INSERT INTO t1 VALUES(8);
     39   INSERT INTO t1 VALUES(9);
     40   INSERT INTO t1 VALUES(10);
     41   COMMIT;
     42 }
     43 
     44 
     45 # Test that the progress callback is invoked.
     46 do_test progress-1.0 {
     47   set counter 0
     48   db progress 1 "[namespace code {incr counter}] ; expr 0"
     49   execsql {
     50     SELECT * FROM t1
     51   }
     52   expr $counter > 1
     53 } 1
     54 do_test progress-1.0.1 {
     55   db progress
     56 } {::namespace inscope :: {incr counter} ; expr 0}
     57 do_test progress-1.0.2 {
     58   set v [catch {db progress xyz bogus} msg]
     59   lappend v $msg
     60 } {1 {expected integer but got "xyz"}}
     61 
     62 # Test that the query is abandoned when the progress callback returns non-zero
     63 do_test progress-1.1 {
     64   set counter 0
     65   db progress 1 "[namespace code {incr counter}] ; expr 1"
     66   set rc [catch {execsql {
     67     SELECT * FROM t1
     68   }}]
     69   list $counter $rc
     70 } {1 1}
     71 
     72 # Test that the query is rolled back when the progress callback returns
     73 # non-zero.
     74 do_test progress-1.2 {
     75 
     76   # This figures out how many opcodes it takes to copy 5 extra rows into t1.
     77   db progress 1 "[namespace code {incr five_rows}] ; expr 0"
     78   set five_rows 0
     79   execsql {
     80     INSERT INTO t1 SELECT a+10 FROM t1 WHERE a < 6
     81   }
     82   db progress 0 ""
     83   execsql {
     84     DELETE FROM t1 WHERE a > 10
     85   }
     86 
     87   # Now set up the progress callback to abandon the query after the number of
     88   # opcodes to copy 5 rows. That way, when we try to copy 6 rows, we know
     89   # some data will have been inserted into the table by the time the progress
     90   # callback abandons the query.
     91   db progress $five_rows "expr 1"
     92   catchsql {
     93     INSERT INTO t1 SELECT a+10 FROM t1 WHERE a < 9
     94   }
     95   execsql {
     96     SELECT count(*) FROM t1
     97   }
     98 } 10
     99 
    100 # Test that an active transaction remains active and not rolled back 
    101 # after the progress query abandons a query. 
    102 #
    103 # UPDATE: It is now recognised that this is a sure route to database
    104 # corruption. So the transaction is rolled back.
    105 do_test progress-1.3 {
    106 
    107   db progress 0 ""
    108   execsql BEGIN
    109   execsql {
    110     INSERT INTO t1 VALUES(11)
    111   }
    112   db progress 1 "expr 1"
    113   catchsql {
    114     INSERT INTO t1 VALUES(12)
    115   }
    116   db progress 0 ""
    117   catchsql COMMIT
    118 } {1 {cannot commit - no transaction is active}}
    119 do_test progress-1.3.1 {
    120   execsql {
    121     SELECT count(*) FROM t1
    122   }
    123 } 10
    124 
    125 # Check that a value of 0 for N means no progress callback
    126 do_test progress-1.4 {
    127   set counter 0
    128   db progress 0 "[namespace code {incr counter}] ; expr 0"
    129   execsql {
    130     SELECT * FROM t1;
    131   }
    132   set counter
    133 } 0
    134 
    135 db progress 0 ""
    136 
    137 # Make sure other queries can be run from within the progress
    138 # handler.  Ticket #1827
    139 #
    140 do_test progress-1.5 {
    141   set rx 0
    142   proc set_rx {args} {
    143     db progress 0 {}
    144     set ::rx [db eval {SELECT count(*) FROM t1}]
    145     return [expr 0]
    146   }
    147   db progress 10 set_rx
    148   db eval {
    149     SELECT sum(a) FROM t1
    150   }
    151 } {55}
    152 do_test progress-1.6 {
    153   set ::rx
    154 } {10}
    155 
    156 # Check that abandoning a query using the progress handler does
    157 # not cause other queries to abort. Ticket #2415.
    158 do_test progress-1.7 {
    159   execsql {
    160     CREATE TABLE abc(a, b, c);
    161     INSERT INTO abc VALUES(1, 2, 3);
    162     INSERT INTO abc VALUES(4, 5, 6);
    163     INSERT INTO abc VALUES(7, 8, 9);
    164   }
    165 
    166   set ::res [list]
    167   db eval {SELECT a, b, c FROM abc} {
    168     lappend ::res $a $b $c
    169     db progress 10 "expr 1"
    170     catch {db eval {SELECT a, b, c FROM abc} { }} msg
    171     lappend ::res $msg
    172   }
    173 
    174   set ::res
    175 } {1 2 3 interrupted 4 5 6 interrupted 7 8 9 interrupted}
    176 
    177 finish_test
    178