summaryrefslogtreecommitdiff
path: root/test/progress.test
blob: b25a100530ba63d45d13cdb763136c4cca2d85e3 (plain)
1
2
3
4
5
6
7
8
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# 2001 September 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the 'progress callback'.
#
# $Id: progress.test,v 1.8 2007/06/15 14:53:53 danielk1977 Exp $

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

# If the progress callback is not available in this build, skip this
# whole file.
ifcapable !progress {
  finish_test
  return
}

# Build some test data
#
execsql {
  BEGIN;
  CREATE TABLE t1(a);
  INSERT INTO t1 VALUES(1);
  INSERT INTO t1 VALUES(2);
  INSERT INTO t1 VALUES(3);
  INSERT INTO t1 VALUES(4);
  INSERT INTO t1 VALUES(5);
  INSERT INTO t1 VALUES(6);
  INSERT INTO t1 VALUES(7);
  INSERT INTO t1 VALUES(8);
  INSERT INTO t1 VALUES(9);
  INSERT INTO t1 VALUES(10);
  COMMIT;
}


# Test that the progress callback is invoked.
do_test progress-1.0 {
  set counter 0
  db progress 1 "[namespace code {incr counter}] ; expr 0"
  execsql {
    SELECT * FROM t1
  }
  expr $counter > 1
} 1
do_test progress-1.0.1 {
  db progress
} {::namespace inscope :: {incr counter} ; expr 0}
do_test progress-1.0.2 {
  set v [catch {db progress xyz bogus} msg]
  lappend v $msg
} {1 {expected integer but got "xyz"}}

# Test that the query is abandoned when the progress callback returns non-zero
do_test progress-1.1 {
  set counter 0
  db progress 1 "[namespace code {incr counter}] ; expr 1"
  set rc [catch {execsql {
    SELECT * FROM t1
  }}]
  list $counter $rc
} {1 1}

# Test that the query is rolled back when the progress callback returns
# non-zero.
do_test progress-1.2 {

  # This figures out how many opcodes it takes to copy 5 extra rows into t1.
  db progress 1 "[namespace code {incr five_rows}] ; expr 0"
  set five_rows 0
  execsql {
    INSERT INTO t1 SELECT a+10 FROM t1 WHERE a < 6
  }
  db progress 0 ""
  execsql {
    DELETE FROM t1 WHERE a > 10
  }

  # Now set up the progress callback to abandon the query after the number of
  # opcodes to copy 5 rows. That way, when we try to copy 6 rows, we know
  # some data will have been inserted into the table by the time the progress
  # callback abandons the query.
  db progress $five_rows "expr 1"
  catchsql {
    INSERT INTO t1 SELECT a+10 FROM t1 WHERE a < 9
  }
  execsql {
    SELECT count(*) FROM t1
  }
} 10

# Test that an active transaction remains active and not rolled back 
# after the progress query abandons a query. 
#
# UPDATE: It is now recognised that this is a sure route to database
# corruption. So the transaction is rolled back.
do_test progress-1.3 {

  db progress 0 ""
  execsql BEGIN
  execsql {
    INSERT INTO t1 VALUES(11)
  }
  db progress 1 "expr 1"
  catchsql {
    INSERT INTO t1 VALUES(12)
  }
  db progress 0 ""
  catchsql COMMIT
} {1 {cannot commit - no transaction is active}}
do_test progress-1.3.1 {
  execsql {
    SELECT count(*) FROM t1
  }
} 10

# Check that a value of 0 for N means no progress callback
do_test progress-1.4 {
  set counter 0
  db progress 0 "[namespace code {incr counter}] ; expr 0"
  execsql {
    SELECT * FROM t1;
  }
  set counter
} 0

db progress 0 ""

# Make sure other queries can be run from within the progress
# handler.  Ticket #1827
#
do_test progress-1.5 {
  set rx 0
  proc set_rx {args} {
    db progress 0 {}
    set ::rx [db eval {SELECT count(*) FROM t1}]
    return [expr 0]
  }
  db progress 10 set_rx
  db eval {
    SELECT sum(a) FROM t1
  }
} {55}
do_test progress-1.6 {
  set ::rx
} {10}

# Check that abandoning a query using the progress handler does
# not cause other queries to abort. Ticket #2415.
do_test progress-1.7 {
  execsql {
    CREATE TABLE abc(a, b, c);
    INSERT INTO abc VALUES(1, 2, 3);
    INSERT INTO abc VALUES(4, 5, 6);
    INSERT INTO abc VALUES(7, 8, 9);
  }

  set ::res [list]
  db eval {SELECT a, b, c FROM abc} {
    lappend ::res $a $b $c
    db progress 10 "expr 1"
    catch {db eval {SELECT a, b, c FROM abc} { }} msg
    lappend ::res $msg
  }

  set ::res
} {1 2 3 interrupted 4 5 6 interrupted 7 8 9 interrupted}

finish_test