xref: /sqlite-3.40.0/test/interrupt.test (revision e0a04a36)
193581642Sdrh# 2004 Feb 8
293581642Sdrh#
393581642Sdrh# The author disclaims copyright to this source code.  In place of
493581642Sdrh# a legal notice, here is a blessing:
593581642Sdrh#
693581642Sdrh#    May you do good and not evil.
793581642Sdrh#    May you find forgiveness for yourself and forgive others.
893581642Sdrh#    May you share freely, never taking more than you give.
993581642Sdrh#
1093581642Sdrh#***********************************************************************
1193581642Sdrh# This file implements regression tests for SQLite library.  The
1293581642Sdrh# focus of this script is the sqlite_interrupt() API.
1393581642Sdrh#
1493aed5a1Sdrh# $Id: interrupt.test,v 1.16 2008/01/16 17:46:38 drh Exp $
1593581642Sdrh
1693581642Sdrh
1793581642Sdrhset testdir [file dirname $argv0]
1893581642Sdrhsource $testdir/tester.tcl
19dddca286Sdrhset DB [sqlite3_connection_pointer db]
2093581642Sdrh
2193581642Sdrh# This routine attempts to execute the sql in $sql.  It triggers an
22f11bded5Sdrh# interrupt at progressively later and later points during the processing
2393581642Sdrh# and checks to make sure SQLITE_INTERRUPT is returned.  Eventually,
2493581642Sdrh# the routine completes successfully.
2593581642Sdrh#
2693581642Sdrhproc interrupt_test {testid sql result {initcnt 0}} {
2793581642Sdrh  set orig_sum [cksum]
2893581642Sdrh  set i $initcnt
2993581642Sdrh  while 1 {
3093581642Sdrh    incr i
3193581642Sdrh    set ::sqlite_interrupt_count $i
3293581642Sdrh    do_test $testid.$i.1 [format {
3393581642Sdrh      set ::r [catchsql %s]
3493581642Sdrh      set ::code [db errorcode]
3593581642Sdrh      expr {$::code==0 || $::code==9}
3693581642Sdrh    } [list $sql]] 1
3793581642Sdrh    if {$::code==9} {
3893581642Sdrh      do_test $testid.$i.2 {
3993581642Sdrh        cksum
4093581642Sdrh      } $orig_sum
4193581642Sdrh    } else {
4293581642Sdrh      do_test $testid.$i.99 {
4393581642Sdrh        set ::r
4493581642Sdrh      } [list 0 $result]
4593581642Sdrh      break
4693581642Sdrh    }
4793581642Sdrh  }
4893581642Sdrh  set ::sqlite_interrupt_count 0
4993581642Sdrh}
5093581642Sdrh
5193581642Sdrhdo_test interrupt-1.1 {
5293581642Sdrh  execsql {
5393581642Sdrh    CREATE TABLE t1(a,b);
5493581642Sdrh    SELECT name FROM sqlite_master;
5593581642Sdrh  }
5693581642Sdrh} {t1}
5793581642Sdrhinterrupt_test interrupt-1.2 {DROP TABLE t1} {}
5893581642Sdrhdo_test interrupt-1.3 {
5993581642Sdrh  execsql {
6093581642Sdrh    SELECT name FROM sqlite_master;
6193581642Sdrh  }
6293581642Sdrh} {}
6393581642Sdrhintegrity_check interrupt-1.4
6493581642Sdrh
6593581642Sdrhdo_test interrrupt-2.1 {
6693581642Sdrh  execsql {
6793581642Sdrh    BEGIN;
6893581642Sdrh    CREATE TABLE t1(a,b);
6993581642Sdrh    INSERT INTO t1 VALUES(1,randstr(300,400));
7093581642Sdrh    INSERT INTO t1 SELECT a+1, randstr(300,400) FROM t1;
7193581642Sdrh    INSERT INTO t1 SELECT a+2, a || '-' || b FROM t1;
7293581642Sdrh    INSERT INTO t1 SELECT a+4, a || '-' || b FROM t1;
7393581642Sdrh    INSERT INTO t1 SELECT a+8, a || '-' || b FROM t1;
7493581642Sdrh    INSERT INTO t1 SELECT a+16, a || '-' || b FROM t1;
7593581642Sdrh    INSERT INTO t1 SELECT a+32, a || '-' || b FROM t1;
7693581642Sdrh    COMMIT;
7793581642Sdrh    UPDATE t1 SET b=substr(b,-5,5);
7893581642Sdrh    SELECT count(*) from t1;
7993581642Sdrh  }
8093581642Sdrh} 64
8193581642Sdrhset origsize [file size test.db]
8293581642Sdrhset cksum [db eval {SELECT md5sum(a || b) FROM t1}]
83798da52cSdrhifcapable {vacuum} {
8493581642Sdrh  interrupt_test interrupt-2.2 {VACUUM} {} 100
85798da52cSdrh}
8693581642Sdrhdo_test interrupt-2.3 {
8793581642Sdrh  execsql {
8893581642Sdrh    SELECT md5sum(a || b) FROM t1;
8993581642Sdrh  }
9093581642Sdrh} $cksum
915436dc2dSdrhifcapable {vacuum && !default_autovacuum} {
9293581642Sdrh  do_test interrupt-2.4 {
9393581642Sdrh    expr {$::origsize>[file size test.db]}
9493581642Sdrh  } 1
9527d258a3Sdrh}
96c5cdca61Sdrhifcapable {explain} {
97c5cdca61Sdrh  do_test interrupt-2.5 {
98c5cdca61Sdrh    set sql {EXPLAIN SELECT max(a,b), a, b FROM t1}
99c5cdca61Sdrh    execsql $sql
100c5cdca61Sdrh    set rc [catch {db eval $sql {sqlite3_interrupt $DB}} msg]
101c5cdca61Sdrh    lappend rc $msg
102c5cdca61Sdrh  } {1 interrupted}
103c5cdca61Sdrh}
104c5cdca61Sdrhintegrity_check interrupt-2.6
10593581642Sdrh
1068ef83ffeSdrh# Ticket #594.  If an interrupt occurs in the middle of a transaction
1078ef83ffeSdrh# and that transaction is later rolled back, the internal schema tables do
1088ef83ffeSdrh# not reset.
1098ef83ffeSdrh#
1103fe11f30Sdanielk1977# UPDATE: Interrupting a DML statement in the middle of a transaction now
1113fe11f30Sdanielk1977# causes the transaction to roll back. Leaving the transaction open after
1123fe11f30Sdanielk1977# an SQL statement was interrupted halfway through risks database corruption.
1133fe11f30Sdanielk1977#
11453c0f748Sdanielk1977ifcapable tempdb {
1158ef83ffeSdrh  for {set i 1} {$i<50} {incr i 5} {
1168ef83ffeSdrh    do_test interrupt-3.$i.1 {
1178ef83ffeSdrh      execsql {
1188ef83ffeSdrh        BEGIN;
1198ef83ffeSdrh        CREATE TEMP TABLE t2(x,y);
1208ef83ffeSdrh        SELECT name FROM sqlite_temp_master;
1218ef83ffeSdrh      }
1228ef83ffeSdrh    } {t2}
1238ef83ffeSdrh    do_test interrupt-3.$i.2 {
1248ef83ffeSdrh      set ::sqlite_interrupt_count $::i
1258ef83ffeSdrh      catchsql {
1268ef83ffeSdrh        INSERT INTO t2 SELECT * FROM t1;
1278ef83ffeSdrh      }
1288ef83ffeSdrh    } {1 interrupted}
1298ef83ffeSdrh    do_test interrupt-3.$i.3 {
1308ef83ffeSdrh      execsql {
131*e0a04a36Sdrh        SELECT name FROM temp.sqlite_master;
1328ef83ffeSdrh      }
1333fe11f30Sdanielk1977    } {}
1348ef83ffeSdrh    do_test interrupt-3.$i.4 {
1358ef83ffeSdrh      catchsql {
1368ef83ffeSdrh        ROLLBACK
1378ef83ffeSdrh      }
1383fe11f30Sdanielk1977    } {1 {cannot rollback - no transaction is active}}
1398ef83ffeSdrh    do_test interrupt-3.$i.5 {
1408ef83ffeSdrh      catchsql {SELECT name FROM sqlite_temp_master};
1418ef83ffeSdrh      execsql {
142*e0a04a36Sdrh        SELECT name FROM temp.sqlite_master;
1438ef83ffeSdrh      }
1448ef83ffeSdrh    } {}
1458ef83ffeSdrh  }
14653c0f748Sdanielk1977}
14793581642Sdrh
14823068027Sdrh# There are reports of a memory leak if an interrupt occurs during
14923068027Sdrh# the beginning of a complex query - before the first callback.  We
15023068027Sdrh# will try to reproduce it here:
15123068027Sdrh#
15223068027Sdrhexecsql {
1539cbe7ca7Sdrh  CREATE TABLE t2(a,b,c);
1549cbe7ca7Sdrh  INSERT INTO t2 SELECT round(a/10), randstr(50,80), randstr(50,60) FROM t1;
15523068027Sdrh}
15623068027Sdrhset sql {
1579cbe7ca7Sdrh  SELECT max(min(b,c)), min(max(b,c)), a FROM t2 GROUP BY a ORDER BY a;
15823068027Sdrh}
15923068027Sdrhset sqlite_interrupt_count 1000000
16023068027Sdrhexecsql $sql
16123068027Sdrhset max_count [expr {1000000-$sqlite_interrupt_count}]
16223068027Sdrhfor {set i 1} {$i<$max_count-5} {incr i 1} {
16323068027Sdrh  do_test interrupt-4.$i.1 {
16423068027Sdrh    set ::sqlite_interrupt_count $::i
1659cbe7ca7Sdrh    catchsql $sql
16623068027Sdrh  } {1 interrupted}
16723068027Sdrh}
16823068027Sdrh
169580c8c18Sdrhif {0} {  # This doesn't work anymore since the collation factor is
170580c8c18Sdrh          # no longer called during schema parsing.
17148e5aa27Sdrh# Interrupt during parsing
17248e5aa27Sdrh#
17348e5aa27Sdrhdo_test interrupt-5.1 {
1747e326c09Sdrh  proc fake_interrupt {args} {
1757e326c09Sdrh    db collate fake_collation no-op
1767e326c09Sdrh    sqlite3_interrupt db
1777e326c09Sdrh    return SQLITE_OK
17848e5aa27Sdrh  }
179f11bded5Sdrh  db collation_needed fake_interrupt
180f11bded5Sdrh  catchsql {
181f11bded5Sdrh    CREATE INDEX fake ON fake1(a COLLATE fake_collation, b, c DESC);
182f11bded5Sdrh  }
183f11bded5Sdrh} {1 interrupt}
184580c8c18Sdrh}
18593581642Sdrhfinish_test
186