000001  # 2011 May 06
000002  #
000003  # The author disclaims copyright to this source code.  In place of
000004  # a legal notice, here is a blessing:
000005  #
000006  #    May you do good and not evil.
000007  #    May you find forgiveness for yourself and forgive others.
000008  #    May you share freely, never taking more than you give.
000009  #
000010  #***********************************************************************
000011  #
000012  
000013  set testdir [file dirname $argv0]
000014  source $testdir/tester.tcl
000015  set testprefix e_totalchanges
000016  
000017  # Like [do_execsql_test], except it appends the value returned by 
000018  # [db total_changes] to the result of executing the SQL script.
000019  #
000020  proc do_tc_test {tn sql res} {
000021    uplevel [list \
000022      do_test $tn "concat \[execsql {$sql}\] \[db total_changes\]" $res
000023    ]
000024  }
000025  
000026  do_execsql_test 1.0 {
000027    CREATE TABLE t1(a, b);
000028    CREATE INDEX t1_b ON t1(b);
000029    CREATE TABLE t2(x, y, PRIMARY KEY(x, y)) WITHOUT ROWID;
000030    CREATE INDEX t2_y ON t2(y);
000031  }
000032  
000033  
000034  #--------------------------------------------------------------------------
000035  # EVIDENCE-OF: R-38914-26427 The total_changes() function returns the
000036  # number of row changes caused by INSERT, UPDATE or DELETE statements
000037  # since the current database connection was opened.
000038  #
000039  #   1.1.*: different types of I/U/D statements,
000040  #   1.2.*: trigger programs.
000041  #
000042  do_tc_test 1.1.1 {
000043    INSERT INTO t1 VALUES(1, 2);
000044    INSERT INTO t1 VALUES(3, 4);
000045    UPDATE t1 SET a = a+1;
000046    DELETE FROM t1;
000047  } {6}
000048  do_tc_test 1.1.2 {
000049    DELETE FROM t1
000050  } {6}
000051  
000052  do_tc_test 1.1.3 {
000053    WITH data(a,b) AS (
000054        SELECT 0, 0 UNION ALL SELECT a+1, b+1 FROM data WHERE a<99
000055    )
000056    INSERT INTO t1 SELECT * FROM data;
000057  } {106}
000058  
000059  do_tc_test 1.1.4 {
000060    INSERT INTO t2 SELECT * FROM t1 WHERE a<50;
000061    UPDATE t2 SET y=y+1;
000062  } {206}
000063  
000064  do_tc_test 1.1.5 {
000065    DELETE FROM t2 WHERE y<=25
000066  } {231}
000067  
000068  do_execsql_test 1.2.1 {
000069    DELETE FROM t1;
000070    DELETE FROM t2;
000071  }
000072  sqlite3 db test.db     ; # To reset total_changes
000073  do_tc_test 1.2.2 {
000074    CREATE TABLE log(detail);
000075    CREATE TRIGGER t1_after_insert AFTER INSERT ON t1 BEGIN 
000076      INSERT INTO log VALUES('inserted into t1');
000077    END;
000078  
000079    CREATE TRIGGER t1_before_delete BEFORE DELETE ON t1 BEGIN 
000080      INSERT INTO log VALUES('deleting from t1');
000081      INSERT INTO log VALUES('here we go!');
000082    END;
000083  
000084    CREATE TRIGGER t1_after_update AFTER UPDATE ON t1 BEGIN 
000085      INSERT INTO log VALUES('update');
000086      DELETE FROM log;
000087    END;
000088  
000089    INSERT INTO t1 VALUES('a', 'b');   -- 1 + 1
000090    UPDATE t1 SET b='c';               -- 1 + 1 + 2
000091    DELETE FROM t1;                    -- 1 + 1 + 1
000092  } {9}
000093  
000094  #--------------------------------------------------------------------------
000095  # EVIDENCE-OF: R-61766-15253 Executing any other type of SQL statement
000096  # does not affect the value returned by sqlite3_total_changes().
000097  ifcapable altertable {
000098    do_tc_test 2.1 {
000099      INSERT INTO t1 VALUES(1, 2), (3, 4);
000100      INSERT INTO t2 VALUES(1, 2), (3, 4);
000101    } {15}
000102    do_tc_test 2.2 {
000103      SELECT count(*) FROM t1;
000104    } {2 15}
000105    do_tc_test 2.3 {
000106      CREATE TABLE t4(a, b);
000107      ALTER TABLE t4 ADD COLUMN c;
000108      CREATE INDEX i4 ON t4(c);
000109      ALTER TABLE t4 RENAME TO t5;
000110      ANALYZE;
000111      BEGIN;
000112      DROP TABLE t2;
000113      ROLLBACK;
000114      VACUUM;
000115    } {15}
000116  }
000117  
000118  
000119  #--------------------------------------------------------------------------
000120  # EVIDENCE-OF: R-36043-10590 Changes made as part of foreign key
000121  # actions are included in the count, but those made as part of REPLACE
000122  # constraint resolution are not.
000123  #
000124  #   3.1.*: foreign key actions
000125  #   3.2.*: REPLACE constraints.
000126  #
000127  sqlite3 db test.db     ; # To reset total_changes
000128  do_tc_test 3.1.1 {
000129    CREATE TABLE p1(c PRIMARY KEY, d);
000130    CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET NULL);
000131    CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE CASCADE);
000132    CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET DEFAULT);
000133  
000134    INSERT INTO p1 VALUES(1, 'one');
000135    INSERT INTO p1 VALUES(2, 'two');
000136    INSERT INTO p1 VALUES(3, 'three');
000137    INSERT INTO p1 VALUES(4, 'four');
000138  
000139    INSERT INTO c1 VALUES(1, 'i');
000140    INSERT INTO c2 VALUES(2, 'ii');
000141    INSERT INTO c3 VALUES(3, 'iii');
000142    PRAGMA foreign_keys = ON;
000143  } {7}
000144  
000145  do_tc_test 3.1.2 { DELETE FROM p1 WHERE c=1; } {9}
000146  do_tc_test 3.1.3 { DELETE FROM p1 WHERE c=2; } {11}
000147  do_tc_test 3.1.4 { DELETE FROM p1 WHERE c=3; } {13}
000148  do_tc_test 3.1.5 { DELETE FROM p1 WHERE c=4; } {14}  ; # only 1 this time.
000149  
000150  sqlite3 db test.db     ; # To reset total_changes
000151  do_tc_test 3.1.6 {
000152    DROP TABLE c1;
000153    DROP TABLE c2;
000154    DROP TABLE c3;
000155    CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET NULL);
000156    CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE CASCADE);
000157    CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET DEFAULT);
000158  
000159    INSERT INTO p1 VALUES(1, 'one');
000160    INSERT INTO p1 VALUES(2, 'two');
000161    INSERT INTO p1 VALUES(3, 'three');
000162    INSERT INTO p1 VALUES(4, 'four');
000163  
000164    INSERT INTO c1 VALUES(1, 'i');
000165    INSERT INTO c2 VALUES(2, 'ii');
000166    INSERT INTO c3 VALUES(3, 'iii');
000167    PRAGMA foreign_keys = ON;
000168  } {7}
000169  
000170  do_tc_test 3.1.7  { UPDATE p1 SET c=c+4 WHERE c=1; } {9}
000171  do_tc_test 3.1.8  { UPDATE p1 SET c=c+4 WHERE c=2; } {11}
000172  do_tc_test 3.1.9  { UPDATE p1 SET c=c+4 WHERE c=3; } {13}
000173  do_tc_test 3.1.10 { UPDATE p1 SET c=c+4 WHERE c=4; } {14}  ; # only 1 this time.
000174  
000175  sqlite3 db test.db     ; # To reset total_changes
000176  do_tc_test 3.2.1 {
000177    CREATE TABLE t3(a UNIQUE, b UNIQUE);
000178    INSERT INTO t3 VALUES('one', 'one');
000179    INSERT INTO t3 VALUES('two', 'two');
000180    INSERT OR REPLACE INTO t3 VALUES('one', 'two');
000181  } {3}
000182  
000183  do_tc_test 3.2.2 {
000184    INSERT INTO t3 VALUES('three', 'one');
000185    UPDATE OR REPLACE t3 SET b='two' WHERE b='one';
000186    SELECT * FROM t3;
000187  } {three two 5}
000188  
000189  #--------------------------------------------------------------------------
000190  # EVIDENCE-OF: R-54872-08741 Changes to a view that are intercepted by
000191  # INSTEAD OF triggers are not counted.
000192  #
000193  sqlite3 db test.db     ; # To reset total_changes
000194  do_tc_test 4.1 {
000195    CREATE TABLE t6(x);
000196    CREATE VIEW v1 AS SELECT * FROM t6;
000197    CREATE TRIGGER v1_tr1 INSTEAD OF INSERT ON v1 BEGIN
000198      SELECT 'no-op';
000199    END;
000200  
000201    INSERT INTO v1 VALUES('a');
000202    INSERT INTO v1 VALUES('b');
000203  } {0}
000204  do_tc_test 4.2 {
000205    CREATE TRIGGER v1_tr2 INSTEAD OF INSERT ON v1 BEGIN
000206      INSERT INTO t6 VALUES(new.x);
000207    END;
000208  
000209    INSERT INTO v1 VALUES('c');
000210    INSERT INTO v1 VALUES('d');
000211  } {2}
000212  
000213  
000214  finish_test