]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add new test script triggerC.test.
authordan <dan@noemail.net>
Tue, 1 Sep 2009 16:19:19 +0000 (16:19 +0000)
committerdan <dan@noemail.net>
Tue, 1 Sep 2009 16:19:19 +0000 (16:19 +0000)
FossilOrigin-Name: a2a062a4b52f45af85c195582a36d1b76d2675db

manifest
manifest.uuid
test/triggerC.test [new file with mode: 0644]

index 3d0174186b9826495e34468a945b092db5c51941..df05713bf21c67911e566c05a7fe15c3b301e14c 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C More\sfixes\sand\scomment\supdates.
-D 2009-09-01T12:16:01
+C Add\snew\stest\sscript\striggerC.test.
+D 2009-09-01T16:19:19
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 73ddeec9dd10b85876c5c2ce1fdce627e1dcc7f8
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -681,6 +681,7 @@ F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
 F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31
 F test/triggerA.test 0718ad2d9bfef27c7af00e636df79bee6b988da7
 F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
+F test/triggerC.test 3806d257b32e95ada0b230161ce9d36e4a7f335a
 F test/types.test 9a825ec8eea4e965d7113b74c76a78bb5240f2ac
 F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
 F test/types3.test a0f66bf12f80fad89493535474f7a6d16fa58150
@@ -748,7 +749,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 85d9f23be1e8673dbda42e43b9b23332ada9225f
-R 95c6e7fce5f16ea2a0796830099d3492
+P 38a9327bad1a01e3d7a47fad44ece2f6c7e88643
+R 1df7bed4841ce53fcaba0907c0d2e83a
 U dan
-Z 4646825fb4a0fb39bbc35c33fbd7d7cc
+Z 25a88a87e4ee91c661bde2c4b892fd01
index 8bfec9342a5515071d4441213c5eadfce822d93c..71e30eb46f0521323a3ac6acb430367ae7e1d9d7 100644 (file)
@@ -1 +1 @@
-38a9327bad1a01e3d7a47fad44ece2f6c7e88643
\ No newline at end of file
+a2a062a4b52f45af85c195582a36d1b76d2675db
\ No newline at end of file
diff --git a/test/triggerC.test b/test/triggerC.test
new file mode 100644 (file)
index 0000000..fc4c950
--- /dev/null
@@ -0,0 +1,460 @@
+# 2009 August 24
+#
+# 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.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+ifcapable {!trigger} {
+  finish_test
+  return
+}
+
+# Enable recursive triggers for this file.
+#
+execsql { PRAGMA disable_recursive_triggers = 0 }
+
+#sqlite3_db_config_lookaside db 0 0 0
+
+#-------------------------------------------------------------------------
+# This block of tests, triggerC-1.*, are not aimed at any specific
+# property of the triggers sub-system. They were created to debug
+# specific problems while modifying SQLite to support recursive
+# triggers. They are left here in case they can help debug the
+# same problems again.
+#
+do_test triggerC-1.1 {
+  execsql {
+    CREATE TABLE t1(a, b, c);
+    CREATE TABLE log(t, a1, b1, c1, a2, b2, c2);
+    CREATE TRIGGER trig1 BEFORE INSERT ON t1 BEGIN
+      INSERT INTO log VALUES('before', NULL, NULL, NULL, new.a, new.b, new.c);
+    END;
+    CREATE TRIGGER trig2 AFTER INSERT ON t1 BEGIN
+      INSERT INTO log VALUES('after', NULL, NULL, NULL, new.a, new.b, new.c);
+    END;
+    CREATE TRIGGER trig3 BEFORE UPDATE ON t1 BEGIN
+      INSERT INTO log VALUES('before', old.a,old.b,old.c, new.a,new.b,new.c);
+    END;
+    CREATE TRIGGER trig4 AFTER UPDATE ON t1 BEGIN
+      INSERT INTO log VALUES('after', old.a,old.b,old.c, new.a,new.b,new.c);
+    END;
+
+    CREATE TRIGGER trig5 BEFORE DELETE ON t1 BEGIN
+      INSERT INTO log VALUES('before', old.a,old.b,old.c, NULL,NULL,NULL);
+    END;
+    CREATE TRIGGER trig6 AFTER DELETE ON t1 BEGIN
+      INSERT INTO log VALUES('after', old.a,old.b,old.c, NULL,NULL,NULL);
+    END;
+  }
+} {}
+do_test triggerC-1.2 {
+  execsql {
+    INSERT INTO t1 VALUES('A', 'B', 'C');
+    SELECT * FROM log;
+  }
+} {before {} {} {} A B C after {} {} {} A B C}
+do_test triggerC-1.3 {
+  execsql { SELECT * FROM t1 }
+} {A B C}
+do_test triggerC-1.4 {
+  execsql {
+    DELETE FROM log;
+    UPDATE t1 SET a = 'a';
+    SELECT * FROM log;
+  }
+} {before A B C a B C after A B C a B C}
+do_test triggerC-1.5 {
+  execsql { SELECT * FROM t1 }
+} {a B C}
+do_test triggerC-1.6 {
+  execsql {
+    DELETE FROM log;
+    DELETE FROM t1;
+    SELECT * FROM log;
+  }
+} {before a B C {} {} {} after a B C {} {} {}}
+do_test triggerC-1.7 {
+  execsql { SELECT * FROM t1 }
+} {}
+do_test triggerC-1.8 {
+  execsql {
+    CREATE TABLE t4(a, b);
+    CREATE TRIGGER t4t AFTER DELETE ON t4 BEGIN
+      SELECT RAISE(ABORT, 'delete is not supported');
+    END;
+  }
+} {}
+do_test triggerC-1.9 {
+  execsql { INSERT INTO t4 VALUES(1, 2) }
+  catchsql { DELETE FROM t4 }
+} {1 {delete is not supported}}
+do_test triggerC-1.10 {
+  execsql { SELECT * FROM t4 }
+} {1 2}
+do_test triggerC-1.11 {
+  execsql {
+    CREATE TABLE t5 (a primary key, b, c);
+    INSERT INTO t5 values (1, 2, 3);
+    CREATE TRIGGER au_tbl AFTER UPDATE ON t5 BEGIN
+      UPDATE OR IGNORE t5 SET a = new.a, c = 10;
+    END;
+  }
+} {}
+do_test triggerC-1.12 {
+  catchsql { UPDATE OR REPLACE t5 SET a = 4 WHERE a = 1 }
+} {1 {too many levels of trigger recursion}}
+do_test triggerC-1.13 {
+  execsql {
+    CREATE TABLE t6(a INTEGER PRIMARY KEY, b);
+    INSERT INTO t6 VALUES(1, 2);
+    create trigger r1 after update on t6 for each row begin
+      SELECT 1;
+    end;
+    UPDATE t6 SET a=a; 
+  }
+} {}
+do_test triggerC-1.14 {
+  execsql {
+    DROP TABLE t1;
+    CREATE TABLE cnt(n);
+    INSERT INTO cnt VALUES(0);
+    CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE, c, d, e);
+    CREATE INDEX t1cd ON t1(c,d);
+    CREATE TRIGGER t1r1 AFTER UPDATE ON t1 BEGIN UPDATE cnt SET n=n+1; END;
+    INSERT INTO t1 VALUES(1,2,3,4,5);
+    INSERT INTO t1 VALUES(6,7,8,9,10);
+    INSERT INTO t1 VALUES(11,12,13,14,15);
+  }
+} {}
+do_test triggerC-1.15 {
+  catchsql { UPDATE OR ROLLBACK t1 SET a=100 }
+} {1 {PRIMARY KEY must be unique}}
+
+
+#-------------------------------------------------------------------------
+# This block of tests, triggerC-2.*, tests that recursive trigger
+# programs (triggers that fire themselves) work. More specifically,
+# this block focuses on recursive INSERT triggers.
+#
+do_test triggerC-2.1.0 {
+  execsql {
+    CREATE TABLE t2(a PRIMARY KEY);
+  }
+} {}
+
+foreach {n tdefn rc} {
+  1 { 
+    CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN
+      INSERT INTO t2 VALUES(new.a - 1);
+    END; 
+  } {0 {10 9 8 7 6 5 4 3 2 1 0}}
+
+  2 {
+    CREATE TRIGGER t2_trig AFTER INSERT ON t2 BEGIN
+      SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END;
+      INSERT INTO t2 VALUES(new.a - 1);
+    END;
+  } {0 {10 9 8 7 6 5 4 3 2}}
+
+  3 { 
+    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN
+      INSERT INTO t2 VALUES(new.a - 1);
+    END; 
+  } {0 {0 1 2 3 4 5 6 7 8 9 10}}
+
+  4 { 
+    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN
+      SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END;
+      INSERT INTO t2 VALUES(new.a - 1);
+    END;
+  } {0 {3 4 5 6 7 8 9 10}}
+
+  5 { 
+    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN
+      INSERT INTO t2 VALUES(new.a - 1);
+    END;
+  } {1 {too many levels of trigger recursion}}
+
+  6 { 
+    CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN
+      INSERT OR IGNORE INTO t2 VALUES(new.a);
+    END;
+  } {0 10}
+
+  7 { 
+    CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN
+      INSERT OR IGNORE INTO t2 VALUES(new.a);
+    END;
+  } {1 {too many levels of trigger recursion}}
+} {
+  do_test triggerC-2.1.$n {
+    catchsql { DROP TRIGGER t2_trig }
+    execsql  { DELETE FROM t2 }
+    execsql  $tdefn
+    catchsql {
+      INSERT INTO t2 VALUES(10);
+      SELECT * FROM t2;
+    }
+  } $rc
+}
+
+do_test triggerC-2.2 {
+  execsql {
+    CREATE TABLE t22(x);
+
+    CREATE TRIGGER t22a AFTER INSERT ON t22 BEGIN
+      INSERT INTO t22 SELECT x + (SELECT max(x) FROM t22) FROM t22;
+    END;
+    CREATE TRIGGER t22b BEFORE INSERT ON t22 BEGIN
+      SELECT CASE WHEN (SELECT count(*) FROM t22) >= 100
+                  THEN RAISE(IGNORE)
+                  ELSE NULL END;
+    END;
+
+    INSERT INTO t22 VALUES(1);
+    SELECT count(*) FROM t22;
+  }
+} {100}
+
+do_test triggerC-2.3 {
+  execsql {
+    CREATE TABLE t23(x PRIMARY KEY);
+
+    CREATE TRIGGER t23a AFTER INSERT ON t23 BEGIN
+      INSERT INTO t23 VALUES(new.x + 1);
+    END;
+
+    CREATE TRIGGER t23b BEFORE INSERT ON t23 BEGIN
+      SELECT CASE WHEN new.x>500
+                  THEN RAISE(IGNORE)
+                  ELSE NULL END;
+    END;
+
+    INSERT INTO t23 VALUES(1);
+    SELECT count(*) FROM t23;
+  }
+} {500}
+
+#-----------------------------------------------------------------------
+# This block of tests, triggerC-3.*, test that SQLite throws an exception
+# when it detects excessive recursion.
+#
+do_test triggerC-3.1.1 {
+  execsql {
+    CREATE TABLE t3(a, b);
+    CREATE TRIGGER t3i AFTER INSERT ON t3 BEGIN
+      DELETE FROM t3 WHERE rowid = new.rowid;
+    END;
+    CREATE TRIGGER t3d AFTER DELETE ON t3 BEGIN
+      INSERT INTO t3 VALUES(old.a, old.b);
+    END;
+  }
+} {}
+do_test triggerC-3.1.2 {
+  catchsql { INSERT INTO t3 VALUES(0,0) }
+} {1 {too many levels of trigger recursion}}
+do_test triggerC-3.1.3 {
+  execsql { SELECT * FROM t3 }
+} {}
+
+#-----------------------------------------------------------------------
+# This next block of tests, triggerC-4.*, checks that affinity 
+# transformations and constraint processing is performed at the correct 
+# times relative to BEFORE and AFTER triggers.
+#
+# For an INSERT statement, for each row to be inserted:
+#
+#   1. Apply affinities to non-rowid values to be inserted.
+#   2. Fire BEFORE triggers.
+#   3. Process constraints.
+#   4. Insert new record.
+#   5. Fire AFTER triggers.
+#
+# If the value of the rowid field is to be automatically assigned, it is
+# set to -1 in the new.* record. Even if it is explicitly set to NULL
+# by the INSERT statement.
+#
+# For an UPDATE statement, for each row to be deleted:
+#
+#   1. Apply affinities to non-rowid values to be inserted.
+#   2. Fire BEFORE triggers.
+#   3. Process constraints.
+#   4. Insert new record.
+#   5. Fire AFTER triggers.
+#
+# For a DELETE statement, for each row to be deleted:
+#
+#   1. Fire BEFORE triggers.
+#   2. Remove database record.
+#   3. Fire AFTER triggers.
+#
+# When a numeric value that as an exact integer representation is stored
+# in a column with REAL affinity, it is actually stored as an integer.
+# These tests check that the typeof() such values is always 'real',
+# not 'integer'.
+#
+# triggerC-4.1.*: Check that affinity transformations are made before
+#                 triggers are invoked.
+#
+do_test triggerC-4.1.1 {
+  catchsql { DROP TABLE log }
+  catchsql { DROP TABLE t4 }
+  execsql {
+    CREATE TABLE log(t);
+    CREATE TABLE t4(a TEXT,b INTEGER,c REAL);
+    CREATE TRIGGER t4bi BEFORE INSERT ON t4 BEGIN
+      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
+                             new.a     || ' ' || typeof(new.a)     || ' ' ||
+                             new.b     || ' ' || typeof(new.b)     || ' ' ||
+                             new.c     || ' ' || typeof(new.c)
+      );
+    END;
+    CREATE TRIGGER t4ai AFTER INSERT ON t4 BEGIN
+      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
+                             new.a     || ' ' || typeof(new.a)     || ' ' ||
+                             new.b     || ' ' || typeof(new.b)     || ' ' ||
+                             new.c     || ' ' || typeof(new.c)
+      );
+    END;
+    CREATE TRIGGER t4bd BEFORE DELETE ON t4 BEGIN
+      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
+                             old.a     || ' ' || typeof(old.a)     || ' ' ||
+                             old.b     || ' ' || typeof(old.b)     || ' ' ||
+                             old.c     || ' ' || typeof(old.c)
+      );
+    END;
+    CREATE TRIGGER t4ad AFTER DELETE ON t4 BEGIN
+      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
+                             old.a     || ' ' || typeof(old.a)     || ' ' ||
+                             old.b     || ' ' || typeof(old.b)     || ' ' ||
+                             old.c     || ' ' || typeof(old.c)
+      );
+    END;
+    CREATE TRIGGER t4bu BEFORE UPDATE ON t4 BEGIN
+      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
+                             old.a     || ' ' || typeof(old.a)     || ' ' ||
+                             old.b     || ' ' || typeof(old.b)     || ' ' ||
+                             old.c     || ' ' || typeof(old.c)
+      );
+      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
+                             new.a     || ' ' || typeof(new.a)     || ' ' ||
+                             new.b     || ' ' || typeof(new.b)     || ' ' ||
+                             new.c     || ' ' || typeof(new.c)
+      );
+    END;
+    CREATE TRIGGER t4au AFTER UPDATE ON t4 BEGIN
+      INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
+                             old.a     || ' ' || typeof(old.a)     || ' ' ||
+                             old.b     || ' ' || typeof(old.b)     || ' ' ||
+                             old.c     || ' ' || typeof(old.c)
+      );
+      INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
+                             new.a     || ' ' || typeof(new.a)     || ' ' ||
+                             new.b     || ' ' || typeof(new.b)     || ' ' ||
+                             new.c     || ' ' || typeof(new.c)
+      );
+    END;
+  }
+} {}
+foreach {n insert log} {
+
+  2 { 
+   INSERT INTO t4 VALUES('1', '1', '1');
+   DELETE FROM t4;
+  } {
+    -1 integer 1 text 1 integer 1.0 real 
+     1 integer 1 text 1 integer 1.0 real
+     1 integer 1 text 1 integer 1.0 real 
+     1 integer 1 text 1 integer 1.0 real
+  }
+
+  3 { 
+   INSERT INTO t4(rowid,a,b,c) VALUES(45, 45, 45, 45);
+   DELETE FROM t4;
+  } {
+    45 integer 45 text 45 integer 45.0 real
+    45 integer 45 text 45 integer 45.0 real
+    45 integer 45 text 45 integer 45.0 real
+    45 integer 45 text 45 integer 45.0 real
+  }
+
+  4 { 
+   INSERT INTO t4(rowid,a,b,c) VALUES(-42.0, -42.0, -42.0, -42.0);
+   DELETE FROM t4;
+  } {
+    -42 integer -42.0 text -42 integer -42.0 real 
+    -42 integer -42.0 text -42 integer -42.0 real
+    -42 integer -42.0 text -42 integer -42.0 real 
+    -42 integer -42.0 text -42 integer -42.0 real
+  }
+
+  5 { 
+   INSERT INTO t4(rowid,a,b,c) VALUES(NULL, -42.4, -42.4, -42.4);
+   DELETE FROM t4;
+  } {
+    -1 integer -42.4 text -42.4 real -42.4 real
+     1 integer -42.4 text -42.4 real -42.4 real
+     1 integer -42.4 text -42.4 real -42.4 real
+     1 integer -42.4 text -42.4 real -42.4 real
+  }
+
+  6 { 
+   INSERT INTO t4 VALUES(7, 7, 7);
+   UPDATE t4 SET a=8, b=8, c=8;
+  } {
+    -1 integer 7 text 7 integer 7.0 real
+     1 integer 7 text 7 integer 7.0 real
+     1 integer 7 text 7 integer 7.0 real
+     1 integer 8 text 8 integer 8.0 real
+     1 integer 7 text 7 integer 7.0 real
+     1 integer 8 text 8 integer 8.0 real
+  }
+
+  7 { 
+   UPDATE t4 SET rowid=2;
+  } {
+     1 integer 8 text 8 integer 8.0 real
+     2 integer 8 text 8 integer 8.0 real
+     1 integer 8 text 8 integer 8.0 real
+     2 integer 8 text 8 integer 8.0 real
+  }
+
+  8 { 
+   UPDATE t4 SET a='9', b='9', c='9';
+  } {
+     2 integer 8 text 8 integer 8.0 real
+     2 integer 9 text 9 integer 9.0 real
+     2 integer 8 text 8 integer 8.0 real
+     2 integer 9 text 9 integer 9.0 real
+  }
+
+  9 { 
+   UPDATE t4 SET a='9.1', b='9.1', c='9.1';
+  } {
+     2 integer 9   text 9   integer 9.0 real
+     2 integer 9.1 text 9.1 real    9.1 real
+     2 integer 9   text 9   integer 9.0 real
+     2 integer 9.1 text 9.1 real    9.1 real
+  }
+} {
+  do_test triggerC-4.1.$n {
+    eval concat [execsql " 
+      DELETE FROM log;
+      $insert ; 
+      SELECT * FROM log;
+    "]
+  } [join $log " "]
+} 
+
+finish_test
+
+