1*c7af484bSdanielk1977#
2a503d731Srdc# The author disclaims copyright to this source code.  In place of
3a503d731Srdc# a legal notice, here is a blessing:
4a503d731Srdc#
5a503d731Srdc#    May you do good and not evil.
6a503d731Srdc#    May you find forgiveness for yourself and forgive others.
7a503d731Srdc#    May you share freely, never taking more than you give.
8a503d731Srdc#
9a503d731Srdc#***********************************************************************
10a503d731Srdc#
11b28af71aSdanielk1977# Tests to make sure that values returned by changes() and total_changes()
12b28af71aSdanielk1977# are updated properly, especially inside triggers
13a503d731Srdc#
14b28af71aSdanielk1977# Note 1: changes() remains constant within a statement and only updates
15b28af71aSdanielk1977#         once the statement is finished (triggers count as part of
16b28af71aSdanielk1977#         statement).
17b28af71aSdanielk1977# Note 2: changes() is changed within the context of a trigger much like
18b28af71aSdanielk1977#         last_insert_rowid() (see lastinsert.test), but is restored once
19b28af71aSdanielk1977#         the trigger exits.
20b28af71aSdanielk1977# Note 3: changes() is not changed by a change to a view (since everything
21b28af71aSdanielk1977#         is done within instead of trigger context).
22a503d731Srdc#
23*c7af484bSdanielk1977# $Id: laststmtchanges.test,v 1.7 2008/10/27 13:59:34 danielk1977 Exp $
24a503d731Srdc
25a503d731Srdcset testdir [file dirname $argv0]
26a503d731Srdcsource $testdir/tester.tcl
27a503d731Srdc
28a503d731Srdc# ----------------------------------------------------------------------------
29a503d731Srdc# 1.x - basic tests (no triggers)
30a503d731Srdc
31b28af71aSdanielk1977# changes() set properly after insert
32a503d731Srdcdo_test laststmtchanges-1.1 {
33a503d731Srdc    catchsql {
34a503d731Srdc        create table t0 (x);
35a503d731Srdc        insert into t0 values (1);
36a503d731Srdc        insert into t0 values (1);
37a503d731Srdc        insert into t0 values (2);
38a503d731Srdc        insert into t0 values (2);
39a503d731Srdc        insert into t0 values (1);
40a503d731Srdc        insert into t0 values (1);
41a503d731Srdc        insert into t0 values (1);
42a503d731Srdc        insert into t0 values (2);
43b28af71aSdanielk1977        select changes(), total_changes();
44a503d731Srdc    }
45b28af71aSdanielk1977} {0 {1 8}}
46a503d731Srdc
47b28af71aSdanielk1977# changes() set properly after update
48a503d731Srdcdo_test laststmtchanges-1.2 {
49a503d731Srdc    catchsql {
50a503d731Srdc        update t0 set x=3 where x=1;
51b28af71aSdanielk1977        select changes(), total_changes();
52a503d731Srdc    }
53b28af71aSdanielk1977} {0 {5 13}}
54a503d731Srdc
55e0e11e2dSdrh# There was some goofy change-counting logic in sqlite3_exec() that
56e0e11e2dSdrh# appears to have been left over from SQLite version 2.  This test
57e0e11e2dSdrh# makes sure it has been removed.
58e0e11e2dSdrh#
59e0e11e2dSdrhdo_test laststmtchanges-1.2.1 {
60e0e11e2dSdrh    db cache flush
61e0e11e2dSdrh    sqlite3_exec_printf db {update t0 set x=4 where x=3; select 1;} {}
62e0e11e2dSdrh    execsql {select changes()}
63e0e11e2dSdrh} {5}
64e0e11e2dSdrh
65b28af71aSdanielk1977# changes() unchanged within an update statement
66a503d731Srdcdo_test laststmtchanges-1.3 {
67e0e11e2dSdrh    execsql {update t0 set x=3 where x=4}
68a503d731Srdc    catchsql {
69b28af71aSdanielk1977        update t0 set x=x+changes() where x=3;
70a503d731Srdc        select count() from t0 where x=8;
71a503d731Srdc    }
72a503d731Srdc} {0 5}
73a503d731Srdc
74b28af71aSdanielk1977# changes() set properly after update on table where no rows changed
75a503d731Srdcdo_test laststmtchanges-1.4 {
76a503d731Srdc    catchsql {
77a503d731Srdc        update t0 set x=77 where x=88;
78b28af71aSdanielk1977        select changes();
79a503d731Srdc    }
80a503d731Srdc} {0 0}
81a503d731Srdc
82b28af71aSdanielk1977# changes() set properly after delete from table
83a503d731Srdcdo_test laststmtchanges-1.5 {
84a503d731Srdc    catchsql {
85a503d731Srdc        delete from t0 where x=2;
86b28af71aSdanielk1977        select changes();
87a503d731Srdc    }
88a503d731Srdc} {0 3}
89a503d731Srdc
90798da52cSdrh# All remaining tests involve triggers.  Skip them if triggers are not
91798da52cSdrh# supported in this build.
92798da52cSdrh#
93798da52cSdrhifcapable {!trigger} {
94798da52cSdrh  finish_test
95798da52cSdrh  return
96798da52cSdrh}
97798da52cSdrh
98798da52cSdrh
99a503d731Srdc# ----------------------------------------------------------------------------
100a503d731Srdc# 2.x - tests with after insert trigger
101a503d731Srdc
102b28af71aSdanielk1977# changes() changed properly after insert into table containing after trigger
103a503d731Srdcdo_test laststmtchanges-2.1 {
104b28af71aSdanielk1977    set ::tc [db total_changes]
105a503d731Srdc    catchsql {
106a503d731Srdc        create table t1 (k integer primary key);
107a503d731Srdc        create table t2 (k integer primary key, v1, v2);
108a503d731Srdc        create trigger r1 after insert on t1 for each row begin
109b28af71aSdanielk1977            insert into t2 values (NULL, changes(), NULL);
110a503d731Srdc            update t0 set x=x;
111b28af71aSdanielk1977            update t2 set v2=changes();
112a503d731Srdc        end;
113a503d731Srdc        insert into t1 values (77);
114b28af71aSdanielk1977        select changes();
115a503d731Srdc    }
116a503d731Srdc} {0 1}
117a503d731Srdc
118b28af71aSdanielk1977# changes() unchanged upon entry into after insert trigger
119a503d731Srdcdo_test laststmtchanges-2.2 {
120a503d731Srdc    catchsql {
121a503d731Srdc        select v1 from t2;
122a503d731Srdc    }
123a503d731Srdc} {0 3}
124a503d731Srdc
125b28af71aSdanielk1977# changes() changed properly by update within context of after insert trigger
126a503d731Srdcdo_test laststmtchanges-2.3 {
127a503d731Srdc    catchsql {
128a503d731Srdc        select v2 from t2;
129a503d731Srdc    }
130a503d731Srdc} {0 5}
131a503d731Srdc
132b28af71aSdanielk1977# Total changes caused by firing the trigger above:
133b28af71aSdanielk1977#
134b28af71aSdanielk1977#   1 from "insert into t1 values(77)" +
135b28af71aSdanielk1977#   1 from "insert into t2 values (NULL, changes(), NULL);" +
136b28af71aSdanielk1977#   5 from "update t0 set x=x;" +
137b28af71aSdanielk1977#   1 from "update t2 set v2=changes();"
138b28af71aSdanielk1977#
139b28af71aSdanielk1977do_test laststmtchanges-2.4 {
140b28af71aSdanielk1977  expr [db total_changes] - $::tc
141b28af71aSdanielk1977} {8}
142b28af71aSdanielk1977
143a503d731Srdc# ----------------------------------------------------------------------------
144a503d731Srdc# 3.x - tests with after update trigger
145a503d731Srdc
146b28af71aSdanielk1977# changes() changed properly after update into table containing after trigger
147a503d731Srdcdo_test laststmtchanges-3.1 {
148a503d731Srdc    catchsql {
149a503d731Srdc        drop trigger r1;
150a503d731Srdc        delete from t2; delete from t2;
151a503d731Srdc        create trigger r1 after update on t1 for each row begin
152b28af71aSdanielk1977            insert into t2 values (NULL, changes(), NULL);
153a503d731Srdc            delete from t0 where oid=1 or oid=2;
154b28af71aSdanielk1977            update t2 set v2=changes();
155a503d731Srdc        end;
156a503d731Srdc        update t1 set k=k;
157b28af71aSdanielk1977        select changes();
158a503d731Srdc    }
159a503d731Srdc} {0 1}
160a503d731Srdc
161b28af71aSdanielk1977# changes() unchanged upon entry into after update trigger
162a503d731Srdcdo_test laststmtchanges-3.2 {
163a503d731Srdc    catchsql {
164a503d731Srdc        select v1 from t2;
165a503d731Srdc    }
166a503d731Srdc} {0 0}
167a503d731Srdc
168b28af71aSdanielk1977# changes() changed properly by delete within context of after update trigger
169a503d731Srdcdo_test laststmtchanges-3.3 {
170a503d731Srdc    catchsql {
171a503d731Srdc        select v2 from t2;
172a503d731Srdc    }
173a503d731Srdc} {0 2}
174a503d731Srdc
175a503d731Srdc# ----------------------------------------------------------------------------
176a503d731Srdc# 4.x - tests with before delete trigger
177a503d731Srdc
178b28af71aSdanielk1977# changes() changed properly on delete from table containing before trigger
179a503d731Srdcdo_test laststmtchanges-4.1 {
180a503d731Srdc    catchsql {
181a503d731Srdc        drop trigger r1;
182a503d731Srdc        delete from t2; delete from t2;
183a503d731Srdc        create trigger r1 before delete on t1 for each row begin
184b28af71aSdanielk1977            insert into t2 values (NULL, changes(), NULL);
185a503d731Srdc            insert into t0 values (5);
186b28af71aSdanielk1977            update t2 set v2=changes();
187a503d731Srdc        end;
188a503d731Srdc        delete from t1;
189b28af71aSdanielk1977        select changes();
190a503d731Srdc    }
191a503d731Srdc} {0 1}
192a503d731Srdc
193b28af71aSdanielk1977# changes() unchanged upon entry into before delete trigger
194a503d731Srdcdo_test laststmtchanges-4.2 {
195a503d731Srdc    catchsql {
196a503d731Srdc        select v1 from t2;
197a503d731Srdc    }
198a503d731Srdc} {0 0}
199a503d731Srdc
200b28af71aSdanielk1977# changes() changed properly by insert within context of before delete trigger
201a503d731Srdcdo_test laststmtchanges-4.3 {
202a503d731Srdc    catchsql {
203a503d731Srdc        select v2 from t2;
204a503d731Srdc    }
205a503d731Srdc} {0 1}
206a503d731Srdc
207a503d731Srdc# ----------------------------------------------------------------------------
208a503d731Srdc# 5.x - complex tests with temporary tables and nested instead of triggers
2090fa8ddbdSdanielk1977# These tests cannot run if the library does not have view support enabled.
2100fa8ddbdSdanielk1977
21153c0f748Sdanielk1977ifcapable view&&tempdb {
212a503d731Srdc
213a503d731Srdcdo_test laststmtchanges-5.1 {
214a503d731Srdc    catchsql {
215a503d731Srdc        drop table t0; drop table t1; drop table t2;
216a503d731Srdc        create temp table t0(x);
217a503d731Srdc        create temp table t1 (k integer primary key);
218a503d731Srdc        create temp table t2 (k integer primary key);
219a503d731Srdc        create temp view v1 as select * from t1;
220a503d731Srdc        create temp view v2 as select * from t2;
221a503d731Srdc        create temp table n1 (k integer primary key, n);
222a503d731Srdc        create temp table n2 (k integer primary key, n);
223a503d731Srdc        insert into t0 values (1);
224a503d731Srdc        insert into t0 values (2);
225a503d731Srdc        insert into t0 values (1);
226a503d731Srdc        insert into t0 values (1);
227a503d731Srdc        insert into t0 values (1);
228a503d731Srdc        insert into t0 values (2);
229a503d731Srdc        insert into t0 values (2);
230a503d731Srdc        insert into t0 values (1);
231a503d731Srdc        create temp trigger r1 instead of insert on v1 for each row begin
232b28af71aSdanielk1977            insert into n1 values (NULL, changes());
233a503d731Srdc            update t0 set x=x*10 where x=1;
234b28af71aSdanielk1977            insert into n1 values (NULL, changes());
235a503d731Srdc            insert into t1 values (NEW.k);
236b28af71aSdanielk1977            insert into n1 values (NULL, changes());
237a503d731Srdc            update t0 set x=x*10 where x=0;
238a503d731Srdc            insert into v2 values (100+NEW.k);
239b28af71aSdanielk1977            insert into n1 values (NULL, changes());
240a503d731Srdc        end;
241a503d731Srdc        create temp trigger r2 instead of insert on v2 for each row begin
242b28af71aSdanielk1977            insert into n2 values (NULL, changes());
243a503d731Srdc            insert into t2 values (1000+NEW.k);
244b28af71aSdanielk1977            insert into n2 values (NULL, changes());
245a503d731Srdc            update t0 set x=x*100 where x=0;
246b28af71aSdanielk1977            insert into n2 values (NULL, changes());
247a503d731Srdc            delete from t0 where x=2;
248b28af71aSdanielk1977            insert into n2 values (NULL, changes());
249a503d731Srdc        end;
250a503d731Srdc        insert into t1 values (77);
251b28af71aSdanielk1977        select changes();
252a503d731Srdc    }
253a503d731Srdc} {0 1}
254a503d731Srdc
255a503d731Srdcdo_test laststmtchanges-5.2 {
256a503d731Srdc    catchsql {
257a503d731Srdc        delete from t1 where k=88;
258b28af71aSdanielk1977        select changes();
259a503d731Srdc    }
260a503d731Srdc} {0 0}
261a503d731Srdc
262a503d731Srdcdo_test laststmtchanges-5.3 {
263a503d731Srdc    catchsql {
264a503d731Srdc        insert into v1 values (5);
265b28af71aSdanielk1977        select changes();
266a503d731Srdc    }
267a503d731Srdc} {0 0}
268a503d731Srdc
269a503d731Srdcdo_test laststmtchanges-5.4 {
270a503d731Srdc    catchsql {
271a503d731Srdc        select n from n1;
272a503d731Srdc    }
273a503d731Srdc} {0 {0 5 1 0}}
274a503d731Srdc
275a503d731Srdcdo_test laststmtchanges-5.5 {
276a503d731Srdc    catchsql {
277a503d731Srdc        select n from n2;
278a503d731Srdc    }
279a503d731Srdc} {0 {0 1 0 3}}
280a503d731Srdc
2810fa8ddbdSdanielk1977} ;# ifcapable view
2820fa8ddbdSdanielk1977
283*c7af484bSdanielk1977
284*c7af484bSdanielk1977# ----------------------------------------------------------------------------
285*c7af484bSdanielk1977# 6.x - Test "DELETE FROM <table>" in the absence of triggers
286*c7af484bSdanielk1977#
287*c7af484bSdanielk1977do_test laststmtchanges-6.1 {
288*c7af484bSdanielk1977  execsql {
289*c7af484bSdanielk1977    CREATE TABLE t3(a, b, c);
290*c7af484bSdanielk1977    INSERT INTO t3 VALUES(1, 2, 3);
291*c7af484bSdanielk1977    INSERT INTO t3 VALUES(4, 5, 6);
292*c7af484bSdanielk1977  }
293*c7af484bSdanielk1977} {}
294*c7af484bSdanielk1977do_test laststmtchanges-6.2 {
295*c7af484bSdanielk1977  execsql {
296*c7af484bSdanielk1977    BEGIN;
297*c7af484bSdanielk1977    DELETE FROM t3;
298*c7af484bSdanielk1977    SELECT changes();
299*c7af484bSdanielk1977  }
300*c7af484bSdanielk1977} {2}
301*c7af484bSdanielk1977do_test laststmtchanges-6.3 {
302*c7af484bSdanielk1977  execsql {
303*c7af484bSdanielk1977    ROLLBACK;
304*c7af484bSdanielk1977    BEGIN;
305*c7af484bSdanielk1977    DELETE FROM t3 WHERE a IS NOT NULL;
306*c7af484bSdanielk1977    SELECT changes();
307*c7af484bSdanielk1977  }
308*c7af484bSdanielk1977} {2}
309*c7af484bSdanielk1977do_test laststmtchanges-6.4 {
310*c7af484bSdanielk1977  execsql {
311*c7af484bSdanielk1977    ROLLBACK;
312*c7af484bSdanielk1977    CREATE INDEX t3_i1 ON t3(a);
313*c7af484bSdanielk1977    BEGIN;
314*c7af484bSdanielk1977    DELETE FROM t3;
315*c7af484bSdanielk1977    SELECT changes();
316*c7af484bSdanielk1977  }
317*c7af484bSdanielk1977} {2}
318*c7af484bSdanielk1977do_test laststmtchanges-6.5 {
319*c7af484bSdanielk1977  execsql { ROLLBACK }
320*c7af484bSdanielk1977  set nTotalChange [execsql {SELECT total_changes()}]
321*c7af484bSdanielk1977  expr 0
322*c7af484bSdanielk1977} {0}
323*c7af484bSdanielk1977do_test laststmtchanges-6.6 {
324*c7af484bSdanielk1977  execsql {
325*c7af484bSdanielk1977    SELECT total_changes();
326*c7af484bSdanielk1977    DELETE FROM t3;
327*c7af484bSdanielk1977    SELECT total_changes();
328*c7af484bSdanielk1977  }
329*c7af484bSdanielk1977} [list $nTotalChange [expr $nTotalChange+2]]
330*c7af484bSdanielk1977
331a503d731Srdcfinish_test
332