1aa55563dSdan# 2011 May 06 2aa55563dSdan# 3aa55563dSdan# The author disclaims copyright to this source code. In place of 4aa55563dSdan# a legal notice, here is a blessing: 5aa55563dSdan# 6aa55563dSdan# May you do good and not evil. 7aa55563dSdan# May you find forgiveness for yourself and forgive others. 8aa55563dSdan# May you share freely, never taking more than you give. 9aa55563dSdan# 10aa55563dSdan#*********************************************************************** 11aa55563dSdan# 12aa55563dSdan 13aa55563dSdanset testdir [file dirname $argv0] 14aa55563dSdansource $testdir/tester.tcl 15aa55563dSdanset testprefix e_totalchanges 16aa55563dSdan 17aa55563dSdan# Like [do_execsql_test], except it appends the value returned by 18aa55563dSdan# [db total_changes] to the result of executing the SQL script. 19aa55563dSdan# 20aa55563dSdanproc do_tc_test {tn sql res} { 21aa55563dSdan uplevel [list \ 22aa55563dSdan do_test $tn "concat \[execsql {$sql}\] \[db total_changes\]" $res 23aa55563dSdan ] 24aa55563dSdan} 25aa55563dSdan 26aa55563dSdando_execsql_test 1.0 { 27aa55563dSdan CREATE TABLE t1(a, b); 28aa55563dSdan CREATE INDEX t1_b ON t1(b); 29aa55563dSdan CREATE TABLE t2(x, y, PRIMARY KEY(x, y)) WITHOUT ROWID; 30aa55563dSdan CREATE INDEX t2_y ON t2(y); 31aa55563dSdan} 32aa55563dSdan 33aa55563dSdan 34aa55563dSdan#-------------------------------------------------------------------------- 35c0bd26a2Sdrh# EVIDENCE-OF: R-38914-26427 The total_changes() function returns the 36c0bd26a2Sdrh# number of row changes caused by INSERT, UPDATE or DELETE statements 37c0bd26a2Sdrh# since the current database connection was opened. 38aa55563dSdan# 39aa55563dSdan# 1.1.*: different types of I/U/D statements, 40aa55563dSdan# 1.2.*: trigger programs. 41aa55563dSdan# 42aa55563dSdando_tc_test 1.1.1 { 43aa55563dSdan INSERT INTO t1 VALUES(1, 2); 44aa55563dSdan INSERT INTO t1 VALUES(3, 4); 45aa55563dSdan UPDATE t1 SET a = a+1; 46aa55563dSdan DELETE FROM t1; 47aa55563dSdan} {6} 48aa55563dSdando_tc_test 1.1.2 { 49aa55563dSdan DELETE FROM t1 50aa55563dSdan} {6} 51aa55563dSdan 52aa55563dSdando_tc_test 1.1.3 { 53aa55563dSdan WITH data(a,b) AS ( 54aa55563dSdan SELECT 0, 0 UNION ALL SELECT a+1, b+1 FROM data WHERE a<99 55aa55563dSdan ) 56aa55563dSdan INSERT INTO t1 SELECT * FROM data; 57aa55563dSdan} {106} 58aa55563dSdan 59aa55563dSdando_tc_test 1.1.4 { 60aa55563dSdan INSERT INTO t2 SELECT * FROM t1 WHERE a<50; 61aa55563dSdan UPDATE t2 SET y=y+1; 62aa55563dSdan} {206} 63aa55563dSdan 64aa55563dSdando_tc_test 1.1.5 { 65aa55563dSdan DELETE FROM t2 WHERE y<=25 66aa55563dSdan} {231} 67aa55563dSdan 68aa55563dSdando_execsql_test 1.2.1 { 69aa55563dSdan DELETE FROM t1; 70aa55563dSdan DELETE FROM t2; 71aa55563dSdan} 72aa55563dSdansqlite3 db test.db ; # To reset total_changes 73aa55563dSdando_tc_test 1.2.2 { 74aa55563dSdan CREATE TABLE log(detail); 75aa55563dSdan CREATE TRIGGER t1_after_insert AFTER INSERT ON t1 BEGIN 76aa55563dSdan INSERT INTO log VALUES('inserted into t1'); 77aa55563dSdan END; 78aa55563dSdan 79aa55563dSdan CREATE TRIGGER t1_before_delete BEFORE DELETE ON t1 BEGIN 80aa55563dSdan INSERT INTO log VALUES('deleting from t1'); 81aa55563dSdan INSERT INTO log VALUES('here we go!'); 82aa55563dSdan END; 83aa55563dSdan 84aa55563dSdan CREATE TRIGGER t1_after_update AFTER UPDATE ON t1 BEGIN 85aa55563dSdan INSERT INTO log VALUES('update'); 86aa55563dSdan DELETE FROM log; 87aa55563dSdan END; 88aa55563dSdan 89aa55563dSdan INSERT INTO t1 VALUES('a', 'b'); -- 1 + 1 90aa55563dSdan UPDATE t1 SET b='c'; -- 1 + 1 + 2 91aa55563dSdan DELETE FROM t1; -- 1 + 1 + 1 92aa55563dSdan} {9} 93aa55563dSdan 94aa55563dSdan#-------------------------------------------------------------------------- 95aa55563dSdan# EVIDENCE-OF: R-61766-15253 Executing any other type of SQL statement 96aa55563dSdan# does not affect the value returned by sqlite3_total_changes(). 97*37f3ac8fSdanifcapable altertable { 98aa55563dSdan do_tc_test 2.1 { 99aa55563dSdan INSERT INTO t1 VALUES(1, 2), (3, 4); 100aa55563dSdan INSERT INTO t2 VALUES(1, 2), (3, 4); 101aa55563dSdan } {15} 102aa55563dSdan do_tc_test 2.2 { 103aa55563dSdan SELECT count(*) FROM t1; 104aa55563dSdan } {2 15} 105aa55563dSdan do_tc_test 2.3 { 106aa55563dSdan CREATE TABLE t4(a, b); 107aa55563dSdan ALTER TABLE t4 ADD COLUMN c; 108aa55563dSdan CREATE INDEX i4 ON t4(c); 109aa55563dSdan ALTER TABLE t4 RENAME TO t5; 110aa55563dSdan ANALYZE; 111aa55563dSdan BEGIN; 112aa55563dSdan DROP TABLE t2; 113aa55563dSdan ROLLBACK; 114aa55563dSdan VACUUM; 115aa55563dSdan } {15} 116*37f3ac8fSdan} 117aa55563dSdan 118aa55563dSdan 119aa55563dSdan#-------------------------------------------------------------------------- 120aa55563dSdan# EVIDENCE-OF: R-36043-10590 Changes made as part of foreign key 121aa55563dSdan# actions are included in the count, but those made as part of REPLACE 122aa55563dSdan# constraint resolution are not. 123aa55563dSdan# 124aa55563dSdan# 3.1.*: foreign key actions 125aa55563dSdan# 3.2.*: REPLACE constraints. 126aa55563dSdan# 127aa55563dSdansqlite3 db test.db ; # To reset total_changes 128aa55563dSdando_tc_test 3.1.1 { 129aa55563dSdan CREATE TABLE p1(c PRIMARY KEY, d); 130aa55563dSdan CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET NULL); 131aa55563dSdan CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE CASCADE); 132aa55563dSdan CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET DEFAULT); 133aa55563dSdan 134aa55563dSdan INSERT INTO p1 VALUES(1, 'one'); 135aa55563dSdan INSERT INTO p1 VALUES(2, 'two'); 136aa55563dSdan INSERT INTO p1 VALUES(3, 'three'); 137aa55563dSdan INSERT INTO p1 VALUES(4, 'four'); 138aa55563dSdan 139aa55563dSdan INSERT INTO c1 VALUES(1, 'i'); 140aa55563dSdan INSERT INTO c2 VALUES(2, 'ii'); 141aa55563dSdan INSERT INTO c3 VALUES(3, 'iii'); 142aa55563dSdan PRAGMA foreign_keys = ON; 143aa55563dSdan} {7} 144aa55563dSdan 145aa55563dSdando_tc_test 3.1.2 { DELETE FROM p1 WHERE c=1; } {9} 146aa55563dSdando_tc_test 3.1.3 { DELETE FROM p1 WHERE c=2; } {11} 147aa55563dSdando_tc_test 3.1.4 { DELETE FROM p1 WHERE c=3; } {13} 148aa55563dSdando_tc_test 3.1.5 { DELETE FROM p1 WHERE c=4; } {14} ; # only 1 this time. 149aa55563dSdan 150aa55563dSdansqlite3 db test.db ; # To reset total_changes 151aa55563dSdando_tc_test 3.1.6 { 152aa55563dSdan DROP TABLE c1; 153aa55563dSdan DROP TABLE c2; 154aa55563dSdan DROP TABLE c3; 155aa55563dSdan CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET NULL); 156aa55563dSdan CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE CASCADE); 157aa55563dSdan CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET DEFAULT); 158aa55563dSdan 159aa55563dSdan INSERT INTO p1 VALUES(1, 'one'); 160aa55563dSdan INSERT INTO p1 VALUES(2, 'two'); 161aa55563dSdan INSERT INTO p1 VALUES(3, 'three'); 162aa55563dSdan INSERT INTO p1 VALUES(4, 'four'); 163aa55563dSdan 164aa55563dSdan INSERT INTO c1 VALUES(1, 'i'); 165aa55563dSdan INSERT INTO c2 VALUES(2, 'ii'); 166aa55563dSdan INSERT INTO c3 VALUES(3, 'iii'); 167aa55563dSdan PRAGMA foreign_keys = ON; 168aa55563dSdan} {7} 169aa55563dSdan 170aa55563dSdando_tc_test 3.1.7 { UPDATE p1 SET c=c+4 WHERE c=1; } {9} 171aa55563dSdando_tc_test 3.1.8 { UPDATE p1 SET c=c+4 WHERE c=2; } {11} 172aa55563dSdando_tc_test 3.1.9 { UPDATE p1 SET c=c+4 WHERE c=3; } {13} 173aa55563dSdando_tc_test 3.1.10 { UPDATE p1 SET c=c+4 WHERE c=4; } {14} ; # only 1 this time. 174aa55563dSdan 175aa55563dSdansqlite3 db test.db ; # To reset total_changes 176aa55563dSdando_tc_test 3.2.1 { 177aa55563dSdan CREATE TABLE t3(a UNIQUE, b UNIQUE); 178aa55563dSdan INSERT INTO t3 VALUES('one', 'one'); 179aa55563dSdan INSERT INTO t3 VALUES('two', 'two'); 180aa55563dSdan INSERT OR REPLACE INTO t3 VALUES('one', 'two'); 181aa55563dSdan} {3} 182aa55563dSdan 183aa55563dSdando_tc_test 3.2.2 { 184aa55563dSdan INSERT INTO t3 VALUES('three', 'one'); 185aa55563dSdan UPDATE OR REPLACE t3 SET b='two' WHERE b='one'; 186aa55563dSdan SELECT * FROM t3; 187aa55563dSdan} {three two 5} 188aa55563dSdan 189aa55563dSdan#-------------------------------------------------------------------------- 190aa55563dSdan# EVIDENCE-OF: R-54872-08741 Changes to a view that are intercepted by 191aa55563dSdan# INSTEAD OF triggers are not counted. 192aa55563dSdan# 193aa55563dSdansqlite3 db test.db ; # To reset total_changes 194aa55563dSdando_tc_test 4.1 { 195aa55563dSdan CREATE TABLE t6(x); 196aa55563dSdan CREATE VIEW v1 AS SELECT * FROM t6; 197aa55563dSdan CREATE TRIGGER v1_tr1 INSTEAD OF INSERT ON v1 BEGIN 198aa55563dSdan SELECT 'no-op'; 199aa55563dSdan END; 200aa55563dSdan 201aa55563dSdan INSERT INTO v1 VALUES('a'); 202aa55563dSdan INSERT INTO v1 VALUES('b'); 203aa55563dSdan} {0} 204aa55563dSdando_tc_test 4.2 { 205aa55563dSdan CREATE TRIGGER v1_tr2 INSTEAD OF INSERT ON v1 BEGIN 206aa55563dSdan INSERT INTO t6 VALUES(new.x); 207aa55563dSdan END; 208aa55563dSdan 209aa55563dSdan INSERT INTO v1 VALUES('c'); 210aa55563dSdan INSERT INTO v1 VALUES('d'); 211aa55563dSdan} {2} 212aa55563dSdan 213aa55563dSdan 214aa55563dSdanfinish_test 215