persistentstorage/sqlite3api/TEST/TclScript/interrupt.test
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 # 2004 Feb 8
       
     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 script is the sqlite_interrupt() API.
       
    13 #
       
    14 # $Id: interrupt.test,v 1.16 2008/01/16 17:46:38 drh Exp $
       
    15 
       
    16 
       
    17 set testdir [file dirname $argv0]
       
    18 source $testdir/tester.tcl
       
    19 set DB [sqlite3_connection_pointer db]
       
    20 
       
    21 # This routine attempts to execute the sql in $sql.  It triggers an
       
    22 # interrupt at progressively later and later points during the processing
       
    23 # and checks to make sure SQLITE_INTERRUPT is returned.  Eventually,
       
    24 # the routine completes successfully.
       
    25 #
       
    26 proc interrupt_test {testid sql result {initcnt 0}} {
       
    27   set orig_sum [cksum]
       
    28   set i $initcnt
       
    29   while 1 {
       
    30     incr i
       
    31     set ::sqlite_interrupt_count $i
       
    32     do_test $testid.$i.1 [format {
       
    33       set ::r [catchsql %s]
       
    34       set ::code [db errorcode]
       
    35       expr {$::code==0 || $::code==9}
       
    36     } [list $sql]] 1
       
    37     if {$::code==9} {
       
    38       do_test $testid.$i.2 {
       
    39         cksum
       
    40       } $orig_sum
       
    41     } else {
       
    42       do_test $testid.$i.99 {
       
    43         set ::r
       
    44       } [list 0 $result]
       
    45       break
       
    46     }
       
    47   }
       
    48   set ::sqlite_interrupt_count 0
       
    49 }
       
    50 
       
    51 do_test interrupt-1.1 {
       
    52   execsql {
       
    53     CREATE TABLE t1(a,b);
       
    54     SELECT name FROM sqlite_master;
       
    55   }
       
    56 } {t1}
       
    57 interrupt_test interrupt-1.2 {DROP TABLE t1} {}
       
    58 do_test interrupt-1.3 {
       
    59   execsql {
       
    60     SELECT name FROM sqlite_master;
       
    61   }
       
    62 } {}
       
    63 integrity_check interrupt-1.4
       
    64 
       
    65 do_test interrrupt-2.1 {
       
    66   execsql {
       
    67     BEGIN;
       
    68     CREATE TABLE t1(a,b);
       
    69     INSERT INTO t1 VALUES(1,randstr(300,400));
       
    70     INSERT INTO t1 SELECT a+1, randstr(300,400) FROM t1;
       
    71     INSERT INTO t1 SELECT a+2, a || '-' || b FROM t1;
       
    72     INSERT INTO t1 SELECT a+4, a || '-' || b FROM t1;
       
    73     INSERT INTO t1 SELECT a+8, a || '-' || b FROM t1;
       
    74     INSERT INTO t1 SELECT a+16, a || '-' || b FROM t1;
       
    75     INSERT INTO t1 SELECT a+32, a || '-' || b FROM t1;
       
    76     COMMIT;
       
    77     UPDATE t1 SET b=substr(b,-5,5);
       
    78     SELECT count(*) from t1;
       
    79   }
       
    80 } 64
       
    81 set origsize [file size test.db]
       
    82 set cksum [db eval {SELECT md5sum(a || b) FROM t1}]
       
    83 ifcapable {vacuum} {
       
    84   interrupt_test interrupt-2.2 {VACUUM} {} 100
       
    85 }
       
    86 do_test interrupt-2.3 {
       
    87   execsql {
       
    88     SELECT md5sum(a || b) FROM t1;
       
    89   }
       
    90 } $cksum
       
    91 ifcapable {vacuum && !default_autovacuum} {
       
    92   do_test interrupt-2.4 {
       
    93     expr {$::origsize>[file size test.db]}
       
    94   } 1
       
    95 }
       
    96 ifcapable {explain} {
       
    97   do_test interrupt-2.5 {
       
    98     set sql {EXPLAIN SELECT max(a,b), a, b FROM t1}
       
    99     execsql $sql
       
   100     set rc [catch {db eval $sql {sqlite3_interrupt $DB}} msg]
       
   101     lappend rc $msg
       
   102   } {1 interrupted}
       
   103 }
       
   104 integrity_check interrupt-2.6
       
   105 
       
   106 # Ticket #594.  If an interrupt occurs in the middle of a transaction
       
   107 # and that transaction is later rolled back, the internal schema tables do
       
   108 # not reset.
       
   109 #
       
   110 # UPDATE: Interrupting a DML statement in the middle of a transaction now
       
   111 # causes the transaction to roll back. Leaving the transaction open after
       
   112 # an SQL statement was interrupted halfway through risks database corruption.
       
   113 #
       
   114 ifcapable tempdb {
       
   115   for {set i 1} {$i<50} {incr i 5} {
       
   116     do_test interrupt-3.$i.1 {
       
   117       execsql {
       
   118         BEGIN;
       
   119         CREATE TEMP TABLE t2(x,y);
       
   120         SELECT name FROM sqlite_temp_master;
       
   121       }
       
   122     } {t2}
       
   123     do_test interrupt-3.$i.2 {
       
   124       set ::sqlite_interrupt_count $::i
       
   125       catchsql {
       
   126         INSERT INTO t2 SELECT * FROM t1;
       
   127       }
       
   128     } {1 interrupted}
       
   129     do_test interrupt-3.$i.3 {
       
   130       execsql {
       
   131         SELECT name FROM sqlite_temp_master;
       
   132       }
       
   133     } {}
       
   134     do_test interrupt-3.$i.4 {
       
   135       catchsql {
       
   136         ROLLBACK
       
   137       }
       
   138     } {1 {cannot rollback - no transaction is active}}
       
   139     do_test interrupt-3.$i.5 {
       
   140       catchsql {SELECT name FROM sqlite_temp_master};
       
   141       execsql {
       
   142         SELECT name FROM sqlite_temp_master;
       
   143       }
       
   144     } {}
       
   145   }
       
   146 }
       
   147 
       
   148 # There are reports of a memory leak if an interrupt occurs during
       
   149 # the beginning of a complex query - before the first callback.  We
       
   150 # will try to reproduce it here:
       
   151 #
       
   152 execsql {
       
   153   CREATE TABLE t2(a,b,c);
       
   154   INSERT INTO t2 SELECT round(a/10), randstr(50,80), randstr(50,60) FROM t1;
       
   155 }
       
   156 set sql {
       
   157   SELECT max(min(b,c)), min(max(b,c)), a FROM t2 GROUP BY a ORDER BY a;
       
   158 }
       
   159 set sqlite_interrupt_count 1000000
       
   160 execsql $sql
       
   161 set max_count [expr {1000000-$sqlite_interrupt_count}]
       
   162 for {set i 1} {$i<$max_count-5} {incr i 1} {
       
   163   do_test interrupt-4.$i.1 {
       
   164     set ::sqlite_interrupt_count $::i
       
   165     catchsql $sql
       
   166   } {1 interrupted}
       
   167 }
       
   168 
       
   169 # Interrupt during parsing
       
   170 #
       
   171 do_test interrupt-5.1 {
       
   172   proc fake_interrupt {args} {
       
   173     db collate fake_collation no-op
       
   174     sqlite3_interrupt db
       
   175     return SQLITE_OK
       
   176   }
       
   177   db collation_needed fake_interrupt
       
   178   catchsql {
       
   179     CREATE INDEX fake ON fake1(a COLLATE fake_collation, b, c DESC);
       
   180   }
       
   181 } {1 interrupt}
       
   182 
       
   183 finish_test