gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/triggerC.test (about)

     1  # 2009 August 24
     2  #
     3  # The author disclaims copyright to this source code.  In place of
     4  # a legal notice', here is a blessing:
     5  #
     6  #    May you do good and not evil.
     7  #    May you find forgiveness for yourself and forgive others.
     8  #    May you share freely, never taking more than you give.
     9  #
    10  #***********************************************************************
    11  #
    12  
    13  set testdir [file dirname $argv0]
    14  source $testdir/tester.tcl
    15  set testprefix triggerC
    16  ifcapable {!trigger} {
    17    finish_test
    18    return
    19  }
    20  
    21  #-------------------------------------------------------------------------
    22  # Test organization:
    23  #
    24  # triggerC-1.*: Haphazardly designed trigger related tests that were useful
    25  #               during an upgrade of the triggers sub-system.
    26  # 
    27  # triggerC-2.*:
    28  #
    29  # triggerC-3.*:
    30  #
    31  # triggerC-4.*:
    32  #
    33  # triggerC-5.*: Test that when recursive triggers are enabled DELETE 
    34  #               triggers are fired when rows are deleted as part of OR
    35  #               REPLACE conflict resolution. And that they are not fired
    36  #               if recursive triggers are not enabled.
    37  #
    38  # triggerC-6.*: Test that the recursive_triggers pragma returns correct
    39  #               results when invoked without an argument.
    40  #
    41  
    42  # Enable recursive triggers for this file.
    43  #
    44  execsql { PRAGMA recursive_triggers = on }
    45  
    46  #sqlite3_db_config_lookaside db 0 0 0
    47  
    48  #-------------------------------------------------------------------------
    49  # This block of tests, triggerC-1.*, are not aimed at any specific
    50  # property of the triggers sub-system. They were created to debug
    51  # specific problems while modifying SQLite to support recursive
    52  # triggers. They are left here in case they can help debug the
    53  # same problems again.
    54  #
    55  do_test triggerC-1.1 {
    56    execsql {
    57      CREATE TABLE t1(a, b, c);
    58      CREATE TABLE log(t, a1, b1, c1, a2, b2, c2);
    59      CREATE TRIGGER trig1 BEFORE INSERT ON t1 BEGIN
    60        INSERT INTO log VALUES('before', NULL, NULL, NULL, new.a, new.b, new.c);
    61      END;
    62      CREATE TRIGGER trig2 AFTER INSERT ON t1 BEGIN
    63        INSERT INTO log VALUES('after', NULL, NULL, NULL, new.a, new.b, new.c);
    64      END;
    65      CREATE TRIGGER trig3 BEFORE UPDATE ON t1 BEGIN
    66        INSERT INTO log VALUES('before', old.a,old.b,old.c, new.a,new.b,new.c);
    67      END;
    68      CREATE TRIGGER trig4 AFTER UPDATE ON t1 BEGIN
    69        INSERT INTO log VALUES('after', old.a,old.b,old.c, new.a,new.b,new.c);
    70      END;
    71  
    72      CREATE TRIGGER trig5 BEFORE DELETE ON t1 BEGIN
    73        INSERT INTO log VALUES('before', old.a,old.b,old.c, NULL,NULL,NULL);
    74      END;
    75      CREATE TRIGGER trig6 AFTER DELETE ON t1 BEGIN
    76        INSERT INTO log VALUES('after', old.a,old.b,old.c, NULL,NULL,NULL);
    77      END;
    78    }
    79  } {}
    80  do_test triggerC-1.2 {
    81    execsql {
    82      INSERT INTO t1 VALUES('A', 'B', 'C');
    83      SELECT * FROM log;
    84    }
    85  } {before {} {} {} A B C after {} {} {} A B C}
    86  do_test triggerC-1.3 {
    87    execsql { SELECT * FROM t1 }
    88  } {A B C}
    89  do_test triggerC-1.4 {
    90    execsql {
    91      DELETE FROM log;
    92      UPDATE t1 SET a = 'a';
    93      SELECT * FROM log;
    94    }
    95  } {before A B C a B C after A B C a B C}
    96  do_test triggerC-1.5 {
    97    execsql { SELECT * FROM t1 }
    98  } {a B C}
    99  do_test triggerC-1.6 {
   100    execsql {
   101      DELETE FROM log;
   102      DELETE FROM t1;
   103      SELECT * FROM log;
   104    }
   105  } {before a B C {} {} {} after a B C {} {} {}}
   106  do_test triggerC-1.7 {
   107    execsql { SELECT * FROM t1 }
   108  } {}
   109  do_test triggerC-1.8 {
   110    execsql {
   111      CREATE TABLE t4(a, b);
   112      CREATE TRIGGER t4t AFTER DELETE ON t4 BEGIN
   113        SELECT RAISE(ABORT, 'delete is not supported');
   114      END;
   115    }
   116  } {}
   117  do_test triggerC-1.9 {
   118    execsql { INSERT INTO t4 VALUES(1, 2) }
   119    catchsql { DELETE FROM t4 }
   120  } {1 {delete is not supported}}
   121  do_test triggerC-1.10 {
   122    execsql { SELECT * FROM t4 }
   123  } {1 2}
   124  do_test triggerC-1.11 {
   125    execsql {
   126      CREATE TABLE t5 (a primary key, b, c);
   127      INSERT INTO t5 values (1, 2, 3);
   128      CREATE TRIGGER au_tbl AFTER UPDATE ON t5 BEGIN
   129        UPDATE OR IGNORE t5 SET a = new.a, c = 10;
   130      END;
   131    }
   132  } {}
   133  do_test triggerC-1.12 {
   134    catchsql { UPDATE OR REPLACE t5 SET a = 4 WHERE a = 1 }
   135  } {1 {too many levels of trigger recursion}}
   136  do_test triggerC-1.13 {
   137    execsql {
   138      CREATE TABLE t6(a INTEGER PRIMARY KEY, b);
   139      INSERT INTO t6 VALUES(1, 2);
   140      create trigger r1 after update on t6 for each row begin
   141        SELECT 1;
   142      end;
   143      UPDATE t6 SET a=a; 
   144    }
   145  } {}
   146  do_test triggerC-1.14 {
   147    execsql {
   148      DROP TABLE t1;
   149      CREATE TABLE cnt(n);
   150      INSERT INTO cnt VALUES(0);
   151      CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE, c, d, e);
   152      CREATE INDEX t1cd ON t1(c,d);
   153      CREATE TRIGGER t1r1 AFTER UPDATE ON t1 BEGIN UPDATE cnt SET n=n+1; END;
   154      INSERT INTO t1 VALUES(1,2,3,4,5);
   155      INSERT INTO t1 VALUES(6,7,8,9,10);
   156      INSERT INTO t1 VALUES(11,12,13,14,15);
   157    }
   158  } {}
   159  do_test triggerC-1.15 {
   160    catchsql { UPDATE OR ROLLBACK t1 SET a=100 }
   161  } {1 {UNIQUE constraint failed: t1.a}}
   162  
   163  
   164  #-------------------------------------------------------------------------
   165  # This block of tests, triggerC-2.*, tests that recursive trigger
   166  # programs (triggers that fire themselves) work. More specifically,
   167  # this block focuses on recursive INSERT triggers.
   168  #
   169  do_test triggerC-2.1.0 {
   170    execsql {
   171      CREATE TABLE t2(a PRIMARY KEY);
   172    }
   173  } {}
   174  
   175  foreach {n tdefn rc} {
   176    1 { 
   177      CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN
   178        INSERT INTO t2 VALUES(new.a - 1);
   179      END; 
   180    } {0 {10 9 8 7 6 5 4 3 2 1 0}}
   181  
   182    2 {
   183      CREATE TRIGGER t2_trig AFTER INSERT ON t2 BEGIN
   184        SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END;
   185        INSERT INTO t2 VALUES(new.a - 1);
   186      END;
   187    } {0 {10 9 8 7 6 5 4 3 2}}
   188  
   189    3 { 
   190      CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN
   191        INSERT INTO t2 VALUES(new.a - 1);
   192      END; 
   193    } {0 {0 1 2 3 4 5 6 7 8 9 10}}
   194  
   195    4 { 
   196      CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN
   197        SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END;
   198        INSERT INTO t2 VALUES(new.a - 1);
   199      END;
   200    } {0 {3 4 5 6 7 8 9 10}}
   201  
   202    5 { 
   203      CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN
   204        INSERT INTO t2 VALUES(new.a - 1);
   205      END;
   206    } {1 {too many levels of trigger recursion}}
   207  
   208    6 { 
   209      CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN
   210        INSERT OR IGNORE INTO t2 VALUES(new.a);
   211      END;
   212    } {0 10}
   213  
   214    7 { 
   215      CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN
   216        INSERT OR IGNORE INTO t2 VALUES(new.a);
   217      END;
   218    } {1 {too many levels of trigger recursion}}
   219  } {
   220    do_test triggerC-2.1.$n {
   221      catchsql { DROP TRIGGER t2_trig }
   222      execsql  { DELETE FROM t2 }
   223      execsql  $tdefn
   224      catchsql {
   225        INSERT INTO t2 VALUES(10);
   226        SELECT * FROM t2 ORDER BY rowid;
   227      }
   228    } $rc
   229  }
   230  
   231  do_test triggerC-2.2 {
   232    execsql "
   233      CREATE TABLE t22(x);
   234  
   235      CREATE TRIGGER t22a AFTER INSERT ON t22 BEGIN
   236        INSERT INTO t22 SELECT x + (SELECT max(x) FROM t22) FROM t22;
   237      END;
   238      CREATE TRIGGER t22b BEFORE INSERT ON t22 BEGIN
   239        SELECT CASE WHEN (SELECT count(*) FROM t22) >= [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]
   240                    THEN RAISE(IGNORE)
   241                    ELSE NULL END;
   242      END;
   243  
   244      INSERT INTO t22 VALUES(1);
   245      SELECT count(*) FROM t22;
   246    "
   247  } [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]]
   248  
   249  do_test triggerC-2.3 {
   250    execsql "
   251      CREATE TABLE t23(x PRIMARY KEY);
   252  
   253      CREATE TRIGGER t23a AFTER INSERT ON t23 BEGIN
   254        INSERT INTO t23 VALUES(new.x + 1);
   255      END;
   256  
   257      CREATE TRIGGER t23b BEFORE INSERT ON t23 BEGIN
   258        SELECT CASE WHEN new.x>[expr $SQLITE_MAX_TRIGGER_DEPTH / 2]
   259                    THEN RAISE(IGNORE)
   260                    ELSE NULL END;
   261      END;
   262  
   263      INSERT INTO t23 VALUES(1);
   264      SELECT count(*) FROM t23;
   265    "
   266  } [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]]
   267   
   268  
   269  #-----------------------------------------------------------------------
   270  # This block of tests, triggerC-3.*, test that SQLite throws an exception
   271  # when it detects excessive recursion.
   272  #
   273  do_test triggerC-3.1.1 {
   274    execsql {
   275      CREATE TABLE t3(a, b);
   276      CREATE TRIGGER t3i AFTER INSERT ON t3 BEGIN
   277        DELETE FROM t3 WHERE rowid = new.rowid;
   278      END;
   279      CREATE TRIGGER t3d AFTER DELETE ON t3 BEGIN
   280        INSERT INTO t3 VALUES(old.a, old.b);
   281      END;
   282    }
   283  } {}
   284  do_test triggerC-3.1.2 {
   285    catchsql { INSERT INTO t3 VALUES(0,0) }
   286  } {1 {too many levels of trigger recursion}}
   287  do_test triggerC-3.1.3 {
   288    execsql { SELECT * FROM t3 }
   289  } {}
   290  
   291  do_test triggerC-3.2.1 {
   292    execsql "
   293      CREATE TABLE t3b(x);
   294      CREATE TRIGGER t3bi AFTER INSERT ON t3b WHEN new.x<[expr $SQLITE_MAX_TRIGGER_DEPTH * 2] BEGIN
   295        INSERT INTO t3b VALUES(new.x+1);
   296      END;
   297    "
   298    catchsql {
   299      INSERT INTO t3b VALUES(1);
   300    }
   301  } {1 {too many levels of trigger recursion}}
   302  do_test triggerC-3.2.2 {
   303    db eval {SELECT * FROM t3b}
   304  } {}
   305  
   306  do_test triggerC-3.3.1 {
   307    catchsql "
   308      INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH + 1]);
   309    "
   310  } {0 {}}
   311  do_test triggerC-3.3.2 {
   312    db eval {SELECT count(*), max(x), min(x) FROM t3b}
   313  } [list $SQLITE_MAX_TRIGGER_DEPTH [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr $SQLITE_MAX_TRIGGER_DEPTH + 1]]
   314  
   315  do_test triggerC-3.4.1 {
   316    catchsql "
   317      DELETE FROM t3b;
   318      INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH - 1]);
   319    "
   320  } {1 {too many levels of trigger recursion}}
   321  do_test triggerC-3.4.2 {
   322    db eval {SELECT count(*), max(x), min(x) FROM t3b}
   323  } {0 {} {}}
   324  
   325  do_test triggerC-3.5.1 {
   326    sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH  [expr $SQLITE_MAX_TRIGGER_DEPTH / 10]
   327    catchsql "
   328      INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10) + 1]);
   329    "
   330  } {0 {}}
   331  do_test triggerC-3.5.2 {
   332    db eval {SELECT count(*), max(x), min(x) FROM t3b}
   333  } [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 10] [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10) + 1]]
   334  
   335  do_test triggerC-3.5.3 {
   336    catchsql "
   337      DELETE FROM t3b;
   338      INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10)]);
   339    "
   340  } {1 {too many levels of trigger recursion}}
   341  do_test triggerC-3.5.4 {
   342    db eval {SELECT count(*), max(x), min(x) FROM t3b}
   343  } {0 {} {}}
   344  
   345  do_test triggerC-3.6.1 {
   346    sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1
   347    catchsql "
   348      INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH * 2]);
   349    "
   350  } {0 {}}
   351  do_test triggerC-3.6.2 {
   352    db eval {SELECT count(*), max(x), min(x) FROM t3b}
   353  } [list 1 [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr $SQLITE_MAX_TRIGGER_DEPTH * 2]]
   354  
   355  do_test triggerC-3.6.3 {
   356    catchsql "
   357      DELETE FROM t3b;
   358      INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - 1]);
   359    "
   360  } {1 {too many levels of trigger recursion}}
   361  do_test triggerC-3.6.4 {
   362    db eval {SELECT count(*), max(x), min(x) FROM t3b}
   363  } {0 {} {}}
   364  sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH $SQLITE_MAX_TRIGGER_DEPTH
   365  
   366  
   367  #-----------------------------------------------------------------------
   368  # This next block of tests, triggerC-4.*, checks that affinity 
   369  # transformations and constraint processing is performed at the correct 
   370  # times relative to BEFORE and AFTER triggers.
   371  #
   372  # For an INSERT statement, for each row to be inserted:
   373  #
   374  #   1. Apply affinities to non-rowid values to be inserted.
   375  #   2. Fire BEFORE triggers.
   376  #   3. Process constraints.
   377  #   4. Insert new record.
   378  #   5. Fire AFTER triggers.
   379  #
   380  # If the value of the rowid field is to be automatically assigned, it is
   381  # set to -1 in the new.* record. Even if it is explicitly set to NULL
   382  # by the INSERT statement.
   383  #
   384  # For an UPDATE statement, for each row to be deleted:
   385  #
   386  #   1. Apply affinities to non-rowid values to be inserted.
   387  #   2. Fire BEFORE triggers.
   388  #   3. Process constraints.
   389  #   4. Insert new record.
   390  #   5. Fire AFTER triggers.
   391  #
   392  # For a DELETE statement, for each row to be deleted:
   393  #
   394  #   1. Fire BEFORE triggers.
   395  #   2. Remove database record.
   396  #   3. Fire AFTER triggers.
   397  #
   398  # When a numeric value that as an exact integer representation is stored
   399  # in a column with REAL affinity, it is actually stored as an integer.
   400  # These tests check that the typeof() such values is always 'real',
   401  # not 'integer'.
   402  #
   403  # triggerC-4.1.*: Check that affinity transformations are made before
   404  #                 triggers are invoked.
   405  #
   406  do_test triggerC-4.1.1 {
   407    catchsql { DROP TABLE log }
   408    catchsql { DROP TABLE t4 }
   409    execsql {
   410      CREATE TABLE log(t);
   411      CREATE TABLE t4(a TEXT,b INTEGER,c REAL);
   412      CREATE TRIGGER t4bi BEFORE INSERT ON t4 BEGIN
   413        INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
   414                               new.a     || ' ' || typeof(new.a)     || ' ' ||
   415                               new.b     || ' ' || typeof(new.b)     || ' ' ||
   416                               new.c     || ' ' || typeof(new.c)
   417        );
   418      END;
   419      CREATE TRIGGER t4ai AFTER INSERT ON t4 BEGIN
   420        INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
   421                               new.a     || ' ' || typeof(new.a)     || ' ' ||
   422                               new.b     || ' ' || typeof(new.b)     || ' ' ||
   423                               new.c     || ' ' || typeof(new.c)
   424        );
   425      END;
   426      CREATE TRIGGER t4bd BEFORE DELETE ON t4 BEGIN
   427        INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
   428                               old.a     || ' ' || typeof(old.a)     || ' ' ||
   429                               old.b     || ' ' || typeof(old.b)     || ' ' ||
   430                               old.c     || ' ' || typeof(old.c)
   431        );
   432      END;
   433      CREATE TRIGGER t4ad AFTER DELETE ON t4 BEGIN
   434        INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
   435                               old.a     || ' ' || typeof(old.a)     || ' ' ||
   436                               old.b     || ' ' || typeof(old.b)     || ' ' ||
   437                               old.c     || ' ' || typeof(old.c)
   438        );
   439      END;
   440      CREATE TRIGGER t4bu BEFORE UPDATE ON t4 BEGIN
   441        INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
   442                               old.a     || ' ' || typeof(old.a)     || ' ' ||
   443                               old.b     || ' ' || typeof(old.b)     || ' ' ||
   444                               old.c     || ' ' || typeof(old.c)
   445        );
   446        INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
   447                               new.a     || ' ' || typeof(new.a)     || ' ' ||
   448                               new.b     || ' ' || typeof(new.b)     || ' ' ||
   449                               new.c     || ' ' || typeof(new.c)
   450        );
   451      END;
   452      CREATE TRIGGER t4au AFTER UPDATE ON t4 BEGIN
   453        INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' ||
   454                               old.a     || ' ' || typeof(old.a)     || ' ' ||
   455                               old.b     || ' ' || typeof(old.b)     || ' ' ||
   456                               old.c     || ' ' || typeof(old.c)
   457        );
   458        INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' ||
   459                               new.a     || ' ' || typeof(new.a)     || ' ' ||
   460                               new.b     || ' ' || typeof(new.b)     || ' ' ||
   461                               new.c     || ' ' || typeof(new.c)
   462        );
   463      END;
   464    }
   465  } {}
   466  foreach {n insert log} {
   467  
   468    2 { 
   469     INSERT INTO t4 VALUES('1', '1', '1');
   470     DELETE FROM t4;
   471    } {
   472      -1 integer 1 text 1 integer 1.0 real 
   473       1 integer 1 text 1 integer 1.0 real
   474       1 integer 1 text 1 integer 1.0 real 
   475       1 integer 1 text 1 integer 1.0 real
   476    }
   477  
   478    3 { 
   479     INSERT INTO t4(rowid,a,b,c) VALUES(45, 45, 45, 45);
   480     DELETE FROM t4;
   481    } {
   482      45 integer 45 text 45 integer 45.0 real
   483      45 integer 45 text 45 integer 45.0 real
   484      45 integer 45 text 45 integer 45.0 real
   485      45 integer 45 text 45 integer 45.0 real
   486    }
   487  
   488    4 { 
   489     INSERT INTO t4(rowid,a,b,c) VALUES(-42.0, -42.0, -42.0, -42.0);
   490     DELETE FROM t4;
   491    } {
   492      -42 integer -42.0 text -42 integer -42.0 real 
   493      -42 integer -42.0 text -42 integer -42.0 real
   494      -42 integer -42.0 text -42 integer -42.0 real 
   495      -42 integer -42.0 text -42 integer -42.0 real
   496    }
   497  
   498    5 { 
   499     INSERT INTO t4(rowid,a,b,c) VALUES(NULL, -42.4, -42.4, -42.4);
   500     DELETE FROM t4;
   501    } {
   502      -1 integer -42.4 text -42.4 real -42.4 real
   503       1 integer -42.4 text -42.4 real -42.4 real
   504       1 integer -42.4 text -42.4 real -42.4 real
   505       1 integer -42.4 text -42.4 real -42.4 real
   506    }
   507  
   508    6 { 
   509     INSERT INTO t4 VALUES(7, 7, 7);
   510     UPDATE t4 SET a=8, b=8, c=8;
   511    } {
   512      -1 integer 7 text 7 integer 7.0 real
   513       1 integer 7 text 7 integer 7.0 real
   514       1 integer 7 text 7 integer 7.0 real
   515       1 integer 8 text 8 integer 8.0 real
   516       1 integer 7 text 7 integer 7.0 real
   517       1 integer 8 text 8 integer 8.0 real
   518    }
   519  
   520    7 { 
   521     UPDATE t4 SET rowid=2;
   522    } {
   523       1 integer 8 text 8 integer 8.0 real
   524       2 integer 8 text 8 integer 8.0 real
   525       1 integer 8 text 8 integer 8.0 real
   526       2 integer 8 text 8 integer 8.0 real
   527    }
   528  
   529    8 { 
   530     UPDATE t4 SET a='9', b='9', c='9';
   531    } {
   532       2 integer 8 text 8 integer 8.0 real
   533       2 integer 9 text 9 integer 9.0 real
   534       2 integer 8 text 8 integer 8.0 real
   535       2 integer 9 text 9 integer 9.0 real
   536    }
   537  
   538    9 { 
   539     UPDATE t4 SET a='9.1', b='9.1', c='9.1';
   540    } {
   541       2 integer 9   text 9   integer 9.0 real
   542       2 integer 9.1 text 9.1 real    9.1 real
   543       2 integer 9   text 9   integer 9.0 real
   544       2 integer 9.1 text 9.1 real    9.1 real
   545    }
   546  } {
   547    do_test triggerC-4.1.$n {
   548      eval concat [execsql " 
   549        DELETE FROM log;
   550        $insert ; 
   551        SELECT * FROM log ORDER BY rowid;
   552      "]
   553    } [join $log " "]
   554  } 
   555  
   556  #-------------------------------------------------------------------------
   557  # This block of tests, triggerC-5.*, test that DELETE triggers are fired
   558  # if a row is deleted as a result of OR REPLACE conflict resolution.
   559  #
   560  do_test triggerC-5.1.0 {
   561    execsql {
   562      DROP TABLE IF EXISTS t5;
   563      CREATE TABLE t5(a INTEGER PRIMARY KEY, b);
   564      CREATE UNIQUE INDEX t5i ON t5(b);
   565      INSERT INTO t5 VALUES(1, 'a');
   566      INSERT INTO t5 VALUES(2, 'b');
   567      INSERT INTO t5 VALUES(3, 'c');
   568  
   569      CREATE TABLE t5g(a, b, c);
   570      CREATE TRIGGER t5t BEFORE DELETE ON t5 BEGIN
   571        INSERT INTO t5g VALUES(old.a, old.b, (SELECT count(*) FROM t5));
   572      END;
   573    }
   574  } {}
   575  foreach {n dml t5g t5} {
   576    1 "DELETE FROM t5 WHERE a=2"                        {2 b 3} {1 a 3 c}
   577    2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')"        {2 b 3} {1 a 2 d 3 c}
   578    3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3"      {2 b 3} {1 a 2 c}
   579    4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')"        {2 b 3} {1 a 3 c 4 b}
   580    5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'"  {2 b 3} {1 a 3 b}
   581    6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')"        {2 b 3 3 c 2} {1 a 2 c}
   582    7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {1 a 3 2 b 2} {1 b}
   583  } {
   584    do_test triggerC-5.1.$n {
   585      execsql "
   586        BEGIN;
   587          $dml ;
   588          SELECT * FROM t5g ORDER BY rowid;
   589          SELECT * FROM t5 ORDER BY rowid;
   590        ROLLBACK;
   591      "
   592    } [concat $t5g $t5]
   593  }
   594  do_test triggerC-5.2.0 {
   595    execsql {
   596      DROP TRIGGER t5t;
   597      CREATE TRIGGER t5t AFTER DELETE ON t5 BEGIN
   598        INSERT INTO t5g VALUES(old.a, old.b, (SELECT count(*) FROM t5));
   599      END;
   600    }
   601  } {}
   602  foreach {n dml t5g t5} {
   603    1 "DELETE FROM t5 WHERE a=2"                        {2 b 2} {1 a 3 c}
   604    2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')"        {2 b 2} {1 a 2 d 3 c}
   605    3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3"      {2 b 2} {1 a 2 c}
   606    4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')"        {2 b 2} {1 a 3 c 4 b}
   607    5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'"  {2 b 2} {1 a 3 b}
   608    6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')"        {2 b 2 3 c 1} {1 a 2 c}
   609    7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {1 a 2 2 b 1} {1 b}
   610  } {
   611    do_test triggerC-5.2.$n {
   612      execsql "
   613        BEGIN;
   614          $dml ;
   615          SELECT * FROM t5g ORDER BY rowid;
   616          SELECT * FROM t5 ORDER BY rowid;
   617        ROLLBACK;
   618      "
   619    } [concat $t5g $t5]
   620  }
   621  do_test triggerC-5.3.0 {
   622    execsql { PRAGMA recursive_triggers = off }
   623  } {}
   624  foreach {n dml t5g t5} {
   625    1 "DELETE FROM t5 WHERE a=2"                        {2 b 2} {1 a 3 c}
   626    2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')"        {} {1 a 2 d 3 c}
   627    3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3"      {} {1 a 2 c}
   628    4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')"        {} {1 a 3 c 4 b}
   629    5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'"  {} {1 a 3 b}
   630    6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')"        {} {1 a 2 c}
   631    7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {} {1 b}
   632  } {
   633    do_test triggerC-5.3.$n {
   634      execsql "
   635        BEGIN;
   636          $dml ;
   637          SELECT * FROM t5g ORDER BY rowid;
   638          SELECT * FROM t5 ORDER BY rowid;
   639        ROLLBACK;
   640      "
   641    } [concat $t5g $t5]
   642  }
   643  do_test triggerC-5.3.8 {
   644    execsql { PRAGMA recursive_triggers = on }
   645  } {}
   646  
   647  #-------------------------------------------------------------------------
   648  # This block of tests, triggerC-6.*, tests that "PRAGMA recursive_triggers"
   649  # statements return the current value of the recursive triggers flag.
   650  #
   651  do_test triggerC-6.1 {
   652    execsql { PRAGMA recursive_triggers }
   653  } {1}
   654  do_test triggerC-6.2 {
   655    execsql { 
   656      PRAGMA recursive_triggers = off;
   657      PRAGMA recursive_triggers;
   658    }
   659  } {0}
   660  do_test triggerC-6.3 {
   661    execsql { 
   662      PRAGMA recursive_triggers = on;
   663      PRAGMA recursive_triggers;
   664    }
   665  } {1}
   666  
   667  #-------------------------------------------------------------------------
   668  # Test some of the "undefined behaviour" associated with triggers. The
   669  # undefined behaviour occurs when a row being updated or deleted is 
   670  # manipulated by a BEFORE trigger.
   671  # 
   672  do_test triggerC-7.1 {
   673    execsql {
   674      CREATE TABLE t8(x);
   675      CREATE TABLE t7(a, b);
   676      INSERT INTO t7 VALUES(1, 2);
   677      INSERT INTO t7 VALUES(3, 4);
   678      INSERT INTO t7 VALUES(5, 6);
   679      CREATE TRIGGER t7t BEFORE UPDATE ON t7 BEGIN
   680        DELETE FROM t7 WHERE a = 1;
   681      END;
   682      CREATE TRIGGER t7ta AFTER UPDATE ON t7 BEGIN
   683        INSERT INTO t8 VALUES('after fired ' || old.rowid || '->' || new.rowid);
   684      END;
   685    }
   686  } {}
   687  do_test triggerC-7.2 {
   688    execsql {
   689      BEGIN;
   690        UPDATE t7 SET b=7 WHERE a = 5;
   691        SELECT * FROM t7;
   692        SELECT * FROM t8;
   693      ROLLBACK;
   694    }
   695  } {3 4 5 7 {after fired 3->3}}
   696  do_test triggerC-7.3 {
   697    execsql {
   698      BEGIN;
   699        UPDATE t7 SET b=7 WHERE a = 1;
   700        SELECT * FROM t7;
   701        SELECT * FROM t8;
   702      ROLLBACK;
   703    }
   704  } {3 4 5 6}
   705  
   706  do_test triggerC-7.4 {
   707    execsql {
   708      DROP TRIGGER t7t;
   709      CREATE TRIGGER t7t BEFORE UPDATE ON t7 WHEN (old.rowid!=1 OR new.rowid!=8)
   710      BEGIN
   711        UPDATE t7 set rowid = 8 WHERE rowid=1;
   712      END;
   713    }
   714  } {}
   715  do_test triggerC-7.5 {
   716    execsql {
   717      BEGIN;
   718        UPDATE t7 SET b=7 WHERE a = 5;
   719        SELECT rowid, * FROM t7;
   720        SELECT * FROM t8;
   721      ROLLBACK;
   722    }
   723  } {2 3 4 3 5 7 8 1 2 {after fired 1->8} {after fired 3->3}}
   724  do_test triggerC-7.6 {
   725    execsql {
   726      BEGIN;
   727        UPDATE t7 SET b=7 WHERE a = 1;
   728        SELECT rowid, * FROM t7;
   729        SELECT * FROM t8;
   730      ROLLBACK;
   731    }
   732  } {2 3 4 3 5 6 8 1 2 {after fired 1->8}}
   733  
   734  do_test triggerC-7.7 {
   735    execsql {
   736      DROP TRIGGER t7t;
   737      DROP TRIGGER t7ta;
   738      CREATE TRIGGER t7t BEFORE DELETE ON t7 BEGIN
   739        UPDATE t7 set rowid = 8 WHERE rowid=1;
   740      END;
   741      CREATE TRIGGER t7ta AFTER DELETE ON t7 BEGIN
   742        INSERT INTO t8 VALUES('after fired ' || old.rowid);
   743      END;
   744    }
   745  } {}
   746  do_test triggerC-7.8 {
   747    execsql {
   748      BEGIN;
   749        DELETE FROM t7 WHERE a = 3;
   750        SELECT rowid, * FROM t7;
   751        SELECT * FROM t8;
   752      ROLLBACK;
   753    }
   754  } {3 5 6 8 1 2 {after fired 2}}
   755  do_test triggerC-7.9 {
   756    execsql {
   757      BEGIN;
   758        DELETE FROM t7 WHERE a = 1;
   759        SELECT rowid, * FROM t7;
   760        SELECT * FROM t8;
   761      ROLLBACK;
   762    }
   763  } {2 3 4 3 5 6 8 1 2}
   764  
   765  # Ticket [e25d9ea771febc9c311928c1c01c3163dcb26643]
   766  # 
   767  do_test triggerC-9.1 {
   768    execsql {
   769      CREATE TABLE t9(a,b);
   770      CREATE INDEX t9b ON t9(b);
   771      INSERT INTO t9 VALUES(1,0);
   772      INSERT INTO t9 VALUES(2,1);
   773      INSERT INTO t9 VALUES(3,2);
   774      INSERT INTO t9 SELECT a+3, a+2 FROM t9;
   775      INSERT INTO t9 SELECT a+6, a+5 FROM t9;
   776      SELECT a FROM t9 ORDER BY a;
   777    }
   778  } {1 2 3 4 5 6 7 8 9 10 11 12}
   779  do_test triggerC-9.2 {
   780    execsql {
   781      CREATE TRIGGER t9r1 AFTER DELETE ON t9 BEGIN
   782        DELETE FROM t9 WHERE b=old.a;
   783      END;
   784      DELETE FROM t9 WHERE b=4;
   785      SELECT a FROM t9 ORDER BY a;
   786    }
   787  } {1 2 3 4}
   788  
   789  # At one point (between versions 3.6.18 and 3.6.20 inclusive), an UPDATE 
   790  # that fired a BEFORE trigger that itself updated the same row as the 
   791  # statement causing it to fire was causing a strange side-effect: The 
   792  # values updated by the statement within the trigger were being overwritten 
   793  # by the values in the new.* array, even if those values were not 
   794  # themselves written by the parent UPDATE statement.
   795  #
   796  # Technically speaking this was not a bug. The SQLite documentation says
   797  # that if a BEFORE UPDATE or BEFORE DELETE trigger modifies or deletes the
   798  # row that the parent statement is operating on the results are undefined. 
   799  # But as of 3.6.21 behaviour is restored to the way it was in versions
   800  # 3.6.17 and earlier to avoid causing unnecessary difficulties.
   801  #
   802  do_test triggerC-10.1 {
   803    execsql {
   804      CREATE TABLE t10(a, updatecnt DEFAULT 0);
   805      CREATE TRIGGER t10_bu BEFORE UPDATE OF a ON t10 BEGIN
   806        UPDATE t10 SET updatecnt = updatecnt+1 WHERE rowid = old.rowid;
   807      END;
   808      INSERT INTO t10(a) VALUES('hello');
   809    }
   810  
   811    # Before the problem was fixed, table t10 would contain the tuple 
   812    # (world, 0) after running the following script (because the value
   813    # 1 written to column "updatecnt" was clobbered by the old value 0).
   814    #
   815    execsql {
   816      UPDATE t10 SET a = 'world';
   817      SELECT * FROM t10;
   818    }
   819  } {world 1}
   820  
   821  do_test triggerC-10.2 {
   822    execsql {
   823      UPDATE t10 SET a = 'tcl', updatecnt = 5;
   824      SELECT * FROM t10;
   825    }
   826  } {tcl 5}
   827  
   828  do_test triggerC-10.3 {
   829    execsql {
   830      CREATE TABLE t11(
   831        c1,   c2,  c3,  c4,  c5,  c6,  c7,  c8,  c9, c10,
   832        c11, c12, c13, c14, c15, c16, c17, c18, c19, c20,
   833        c21, c22, c23, c24, c25, c26, c27, c28, c29, c30,
   834        c31, c32, c33, c34, c35, c36, c37, c38, c39, c40
   835      );
   836  
   837      CREATE TRIGGER t11_bu BEFORE UPDATE OF c1 ON t11 BEGIN
   838        UPDATE t11 SET c31 = c31+1, c32=c32+1 WHERE rowid = old.rowid;
   839      END;
   840  
   841      INSERT INTO t11 VALUES(
   842        1,   2,  3,  4,  5,  6,  7,  8,  9, 10,
   843        11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
   844        21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
   845        31, 32, 33, 34, 35, 36, 37, 38, 39, 40
   846      );
   847    }
   848  
   849    # Before the problem was fixed, table t10 would contain the tuple 
   850    # (world, 0) after running the following script (because the value
   851    # 1 written to column "updatecnt" was clobbered by the old value 0).
   852    #
   853    execsql {
   854      UPDATE t11 SET c4=35, c33=22, c1=5;
   855      SELECT * FROM t11;
   856    } 
   857  } {5 2 3 35 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 32 33 22 34 35 36 37 38 39 40}
   858  
   859  #-------------------------------------------------------------------------
   860  # Test that bug [371bab5d65] has been fixed. BEFORE INSERT and INSTEAD OF
   861  # INSERT triggers with the DEFAULT VALUES INSERT syntax.
   862  #
   863  do_test triggerC-11.0 {
   864    catchsql { DROP TABLE log }
   865    execsql  { CREATE TABLE log(a, b) }
   866  } {}
   867  
   868  foreach {testno tbl defaults} {
   869    1 "CREATE TABLE t1(a, b)"                          {{} {}}
   870    2 "CREATE TABLE t1(a DEFAULT 1, b DEFAULT 'abc')"  {1 abc}
   871    3 "CREATE TABLE t1(a, b DEFAULT 4.5)"              {{} 4.5}
   872  } {
   873    do_test triggerC-11.$testno.1 {
   874      catchsql { DROP TABLE t1 }
   875      execsql { DELETE FROM log }
   876      execsql $tbl
   877      execsql {
   878        CREATE TRIGGER tt1 BEFORE INSERT ON t1 BEGIN 
   879          INSERT INTO log VALUES(new.a, new.b);
   880        END;
   881        INSERT INTO t1 DEFAULT VALUES;
   882        SELECT * FROM log;
   883      }
   884    } $defaults
   885  
   886    do_test triggerC-11.$testno.2 {
   887      execsql { DELETE FROM log }
   888      execsql {
   889        CREATE TRIGGER tt2 AFTER INSERT ON t1 BEGIN 
   890          INSERT INTO log VALUES(new.a, new.b);
   891        END;
   892        INSERT INTO t1 DEFAULT VALUES;
   893        SELECT * FROM log;
   894      }
   895    } [concat $defaults $defaults]
   896  
   897    do_test triggerC-11.$testno.3 {
   898      execsql { DROP TRIGGER tt1 }
   899      execsql { DELETE FROM log }
   900      execsql {
   901        INSERT INTO t1 DEFAULT VALUES;
   902        SELECT * FROM log;
   903      }
   904    } $defaults
   905  } 
   906  do_test triggerC-11.4 {
   907    catchsql { DROP TABLE t2 }
   908    execsql {
   909      DELETE FROM log;
   910      CREATE TABLE t2(a, b);
   911      CREATE VIEW v2 AS SELECT * FROM t2;
   912      CREATE TRIGGER tv2 INSTEAD OF INSERT ON v2 BEGIN
   913        INSERT INTO log VALUES(new.a, new.b);
   914      END;
   915      INSERT INTO v2 DEFAULT VALUES;
   916      SELECT a, b, a IS NULL, b IS NULL FROM log;
   917    }
   918  } {{} {} 1 1}
   919  
   920  do_test triggerC-12.1 {
   921    db close
   922    forcedelete test.db
   923    sqlite3 db test.db
   924  
   925    execsql {
   926      CREATE TABLE t1(a, b);
   927      INSERT INTO t1 VALUES(1, 2);
   928      INSERT INTO t1 VALUES(3, 4);
   929      INSERT INTO t1 VALUES(5, 6);
   930      CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1 ; END ;
   931      SELECT count(*) FROM sqlite_master;
   932    }
   933  } {2}
   934  do_test triggerC-12.2 {
   935    db eval { SELECT * FROM t1 } {
   936      if {$a == 3} { execsql { DROP TRIGGER tr1 } }
   937    }
   938    execsql { SELECT count(*) FROM sqlite_master }
   939  } {1}
   940  
   941  do_execsql_test triggerC-13.1 {
   942    PRAGMA recursive_triggers = ON;
   943    CREATE TABLE t12(a, b);
   944    INSERT INTO t12 VALUES(1, 2);
   945    CREATE TRIGGER tr12 AFTER UPDATE ON t12 BEGIN
   946      UPDATE t12 SET a=new.a+1, b=new.b+1;
   947    END;
   948  } {}
   949  do_catchsql_test triggerC-13.2 {
   950    UPDATE t12 SET a=a+1, b=b+1;
   951  } {1 {too many levels of trigger recursion}}
   952  
   953  #-------------------------------------------------------------------------
   954  # The following tests seek to verify that constant values (i.e. literals)
   955  # are not factored out of loops within trigger programs. SQLite does
   956  # not factor constants out of loops within trigger programs as it may only
   957  # do so in code generated before the first table or index is opened. And
   958  # by the time a trigger program is coded, at least one table or index has
   959  # always been opened.
   960  #
   961  # At one point, due to a bug allowing constant factoring within triggers,
   962  # the following SQL would produce the wrong result.
   963  #
   964  set SQL {
   965    CREATE TABLE t1(a, b, c);
   966    CREATE INDEX i1 ON t1(a, c);
   967    CREATE INDEX i2 ON t1(b, c);
   968    INSERT INTO t1 VALUES(1, 2, 3);
   969  
   970    CREATE TABLE t2(e, f);
   971    CREATE INDEX i3 ON t2(e);
   972    INSERT INTO t2 VALUES(1234567, 3);
   973  
   974    CREATE TABLE empty(x);
   975    CREATE TABLE not_empty(x);
   976    INSERT INTO not_empty VALUES(2);
   977  
   978    CREATE TABLE t4(x);
   979    CREATE TABLE t5(g, h, i);
   980  
   981    CREATE TRIGGER trig BEFORE INSERT ON t4 BEGIN
   982      INSERT INTO t5 SELECT * FROM t1 WHERE 
   983          (a IN (SELECT x FROM empty) OR b IN (SELECT x FROM not_empty)) 
   984          AND c IN (SELECT f FROM t2 WHERE e=1234567);
   985    END;
   986  
   987    INSERT INTO t4 VALUES(0);
   988    SELECT * FROM t5;
   989  }
   990  
   991  reset_db
   992  do_execsql_test triggerC-14.1 $SQL {1 2 3}
   993  reset_db
   994  optimization_control db factor-constants 0
   995  do_execsql_test triggerC-14.2 $SQL {1 2 3}
   996  
   997  #-------------------------------------------------------------------------
   998  # Check that table names used by trigger programs are dequoted exactly
   999  # once.
  1000  #
  1001  do_execsql_test 15.1.1 {
  1002    PRAGMA recursive_triggers = 1;
  1003    CREATE TABLE node(
  1004        id int not null primary key, 
  1005        pid int not null default 0 references node,
  1006        key varchar not null, 
  1007        path varchar default '',
  1008        unique(pid, key)
  1009        );
  1010    CREATE TRIGGER node_delete_referencing AFTER DELETE ON "node"
  1011      BEGIN
  1012      DELETE FROM "node" WHERE pid = old."id";
  1013    END;
  1014  }
  1015  do_execsql_test 15.1.2 {
  1016    INSERT INTO node(id, pid, key) VALUES(9, 0, 'test');
  1017    INSERT INTO node(id, pid, key) VALUES(90, 9, 'test1');
  1018    INSERT INTO node(id, pid, key) VALUES(900, 90, 'test2');
  1019    DELETE FROM node WHERE id=9;
  1020    SELECT * FROM node;
  1021  }
  1022  
  1023  do_execsql_test 15.2.1 {
  1024    CREATE TABLE   x1  (x);
  1025  
  1026    CREATE TABLE   x2  (a, b);
  1027    CREATE TABLE '"x2"'(a, b);
  1028  
  1029    INSERT INTO x2 VALUES(1, 2);
  1030    INSERT INTO x2 VALUES(3, 4);
  1031    INSERT INTO '"x2"' SELECT * FROM x2;
  1032  
  1033    CREATE TRIGGER x1ai AFTER INSERT ON x1 BEGIN
  1034      INSERT INTO """x2""" VALUES('x', 'y');
  1035      DELETE FROM """x2""" WHERE a=1;
  1036      UPDATE """x2""" SET b = 11 WHERE a = 3;
  1037    END;
  1038  
  1039    INSERT INTO x1 VALUES('go!');
  1040  }
  1041  
  1042  do_execsql_test 15.2.2 { SELECT * FROM x2;       } {1 2 3 4}
  1043  do_execsql_test 15.2.3 { SELECT * FROM """x2"""; } {3 11 x y}
  1044  
  1045  #-------------------------------------------------------------------------
  1046  # At one point queries such as the following were causing segfaults.
  1047  #
  1048  do_catchsql_test 16.1 {
  1049    SELECT raise(ABORT, 'msg') FROM sqlite_master 
  1050    UNION SELECT 1 
  1051    ORDER BY raise(IGNORE);
  1052  } {1 {1st ORDER BY term does not match any column in the result set}}
  1053  
  1054  do_catchsql_test 16.2 {
  1055    SELECT count(*) FROM sqlite_master 
  1056    GROUP BY raise(IGNORE) 
  1057    HAVING raise(ABORT, 'msg');
  1058  } {1 {RAISE() may only be used within a trigger-program}}
  1059  
  1060  #-------------------------------------------------------------------------
  1061  # Datatype mismatch on IPK when there are BEFORE triggers.
  1062  #
  1063  do_execsql_test 17.0 {
  1064    CREATE TABLE xyz(x INTEGER PRIMARY KEY, y, z);
  1065    CREATE TRIGGER xyz_tr BEFORE INSERT ON xyz BEGIN
  1066      SELECT new.x;
  1067    END;
  1068  }
  1069  do_catchsql_test 17.1 {
  1070    INSERT INTO xyz VALUES('hello', 2, 3);
  1071  } {1 {datatype mismatch}}
  1072  
  1073  
  1074  finish_test