19ed322d6Sdan# 2020 April 29 29ed322d6Sdan# 39ed322d6Sdan# The author disclaims copyright to this source code. In place of 49ed322d6Sdan# a legal notice, here is a blessing: 59ed322d6Sdan# 69ed322d6Sdan# May you do good and not evil. 79ed322d6Sdan# May you find forgiveness for yourself and forgive others. 89ed322d6Sdan# May you share freely, never taking more than you give. 99ed322d6Sdan# 109ed322d6Sdan#*********************************************************************** 119ed322d6Sdan# 129ed322d6Sdan 139ed322d6Sdanset testdir [file dirname $argv0] 149ed322d6Sdansource $testdir/tester.tcl 159ed322d6Sdanset testprefix upfrom2 169ed322d6Sdan 179ed322d6Sdan# Test cases: 189ed322d6Sdan# 199ed322d6Sdan# 1.*: Test that triggers are fired correctly for UPDATE FROM statements, 20f2972b60Sdan# and only once for each row. Except for INSTEAD OF triggers on 21f2972b60Sdan# views - these are fired once for each row returned by the join, 22f2972b60Sdan# including duplicates. 23f2972b60Sdan# 24f2972b60Sdan# 2.*: Test adding ORDER BY and LIMIT clauses with UPDATE FROM statements. 259ed322d6Sdan# 2607ca7d61Sdan# 5.*: Test that specifying the target table name or alias in the FROM 2707ca7d61Sdan# clause of an UPDATE statement is an error. 2807ca7d61Sdan# 299ed322d6Sdan 309ed322d6Sdanforeach {tn wo} { 319ed322d6Sdan 1 "" 329ed322d6Sdan 2 "WITHOUT ROWID" 339ed322d6Sdan} { 349ed322d6Sdan reset_db 359ed322d6Sdan 369ed322d6Sdan eval [string map [list %WO% $wo %TN% $tn] { 379ed322d6Sdan do_execsql_test 1.%TN%.0 { 389ed322d6Sdan CREATE TABLE log(t TEXT); 399ed322d6Sdan CREATE TABLE t1(x PRIMARY KEY, y, z UNIQUE) %WO%; 409ed322d6Sdan CREATE INDEX t1y ON t1(y); 419ed322d6Sdan 429ed322d6Sdan INSERT INTO t1 VALUES(1, 'i', 'one'); 439ed322d6Sdan INSERT INTO t1 VALUES(2, 'ii', 'two'); 449ed322d6Sdan INSERT INTO t1 VALUES(3, 'iii', 'three'); 459ed322d6Sdan INSERT INTO t1 VALUES(4, 'iv', 'four'); 469ed322d6Sdan 479ed322d6Sdan CREATE TRIGGER tr1 BEFORE UPDATE ON t1 BEGIN 489ed322d6Sdan INSERT INTO log VALUES(old.z || '->' || new.z); 499ed322d6Sdan END; 509ed322d6Sdan CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN 519ed322d6Sdan INSERT INTO log VALUES(old.y || '->' || new.y); 529ed322d6Sdan END; 539ed322d6Sdan } 549ed322d6Sdan 559ed322d6Sdan do_execsql_test 1.%TN%.1 { 569ed322d6Sdan WITH data(k, v) AS ( 579ed322d6Sdan VALUES(3, 'thirty'), (1, 'ten') 589ed322d6Sdan ) 599ed322d6Sdan UPDATE t1 SET z=v FROM data WHERE x=k; 609ed322d6Sdan 619ed322d6Sdan SELECT * FROM t1; 629ed322d6Sdan SELECT * FROM log; 639ed322d6Sdan } { 649ed322d6Sdan 1 i ten 2 ii two 3 iii thirty 4 iv four 659ed322d6Sdan one->ten i->i 669ed322d6Sdan three->thirty iii->iii 679ed322d6Sdan } 689ed322d6Sdan 699ed322d6Sdan do_execsql_test 1.%TN%.2 { 709ed322d6Sdan CREATE TABLE t2(a, b); 719ed322d6Sdan CREATE TABLE t3(k, v); 729ed322d6Sdan 739ed322d6Sdan INSERT INTO t3 VALUES(5, 'v'); 749ed322d6Sdan INSERT INTO t3 VALUES(12, 'xii'); 759ed322d6Sdan 769ed322d6Sdan INSERT INTO t2 VALUES(2, 12); 779ed322d6Sdan INSERT INTO t2 VALUES(3, 5); 789ed322d6Sdan 799ed322d6Sdan DELETE FROM log; 809ed322d6Sdan UPDATE t1 SET y=v FROM t2, t3 WHERE t1.x=t2.a AND t3.k=t2.b; 819ed322d6Sdan 829ed322d6Sdan SELECT * FROM t1; 839ed322d6Sdan SELECT * FROM log; 849ed322d6Sdan } { 859ed322d6Sdan 1 i ten 2 xii two 3 v thirty 4 iv four 869ed322d6Sdan two->two ii->xii 879ed322d6Sdan thirty->thirty iii->v 889ed322d6Sdan } 899ed322d6Sdan 909ed322d6Sdan do_execsql_test 1.%TN%.3 { 919ed322d6Sdan DELETE FROM log; 929ed322d6Sdan WITH data(k, v) AS ( 939ed322d6Sdan VALUES(1, 'seven'), (1, 'eight'), (2, 'eleven'), (2, 'twelve') 949ed322d6Sdan ) 959ed322d6Sdan UPDATE t1 SET z=v FROM data WHERE x=k; 969ed322d6Sdan 979ed322d6Sdan SELECT * FROM t1; 989ed322d6Sdan SELECT * FROM log; 999ed322d6Sdan } { 1009ed322d6Sdan 1 i eight 2 xii twelve 3 v thirty 4 iv four 1019ed322d6Sdan ten->eight i->i 1029ed322d6Sdan two->twelve xii->xii 1039ed322d6Sdan } 104f2972b60Sdan 105f2972b60Sdan do_test 1.%TN%.4 { db changes } {2} 106f2972b60Sdan 107f2972b60Sdan do_execsql_test 1.%TN%.5 { 108f2972b60Sdan CREATE VIEW v1 AS SELECT * FROM t1; 109f2972b60Sdan CREATE TRIGGER v1tr INSTEAD OF UPDATE ON v1 BEGIN 110f2972b60Sdan UPDATE t1 SET y=new.y, z=new.z WHERE x=new.x; 111f2972b60Sdan END; 112f2972b60Sdan 113f2972b60Sdan DELETE FROM log; 114f2972b60Sdan WITH data(k, v) AS ( 115f2972b60Sdan VALUES(3, 'thirteen'), (3, 'fourteen'), (4, 'fifteen'), (4, 'sixteen') 116f2972b60Sdan ) 117f2972b60Sdan UPDATE v1 SET z=v FROM data WHERE x=k; 118f2972b60Sdan } 119f2972b60Sdan 120f2972b60Sdan do_execsql_test 1.%TN%.6 { 121f2972b60Sdan SELECT * FROM v1; 122f2972b60Sdan SELECT * FROM log; 123f2972b60Sdan } { 124f2972b60Sdan 1 i eight 2 xii twelve 3 v fourteen 4 iv sixteen 125f2972b60Sdan thirty->thirteen v->v 126f2972b60Sdan thirteen->fourteen v->v 127f2972b60Sdan four->fifteen iv->iv 128f2972b60Sdan fifteen->sixteen iv->iv 129f2972b60Sdan } 130f2972b60Sdan 1311e113844Sdan #-------------------------------------------------------------- 1321e113844Sdan 1331e113844Sdan do_execsql_test 1.%TN%.7 { 1341e113844Sdan CREATE TABLE o1(w, x, y, z UNIQUE, PRIMARY KEY(w, x)) %WO%; 1351e113844Sdan CREATE INDEX o1y ON t1(y); 1361e113844Sdan 1371e113844Sdan INSERT INTO o1 VALUES(0, 0, 'i', 'one'); 1381e113844Sdan INSERT INTO o1 VALUES(0, 1, 'ii', 'two'); 1391e113844Sdan INSERT INTO o1 VALUES(1, 0, 'iii', 'three'); 1401e113844Sdan INSERT INTO o1 VALUES(1, 1, 'iv', 'four'); 1411e113844Sdan 1421e113844Sdan CREATE TRIGGER tro1 BEFORE UPDATE ON o1 BEGIN 1431e113844Sdan INSERT INTO log VALUES(old.z || '->' || new.z); 1441e113844Sdan END; 1451e113844Sdan CREATE TRIGGER tro2 AFTER UPDATE ON o1 BEGIN 1461e113844Sdan INSERT INTO log VALUES(old.y || '->' || new.y); 1471e113844Sdan END; 1481e113844Sdan } 1491e113844Sdan 1501e113844Sdan do_execsql_test 1.%TN%.8 { 1511e113844Sdan DELETE FROM log; 1521e113844Sdan WITH data(k, v) AS ( 1531e113844Sdan VALUES(3, 'thirty'), (1, 'ten') 1541e113844Sdan ) 1551e113844Sdan UPDATE o1 SET z=v FROM data WHERE (1+x+w*2)=k; 1561e113844Sdan 1571e113844Sdan SELECT * FROM o1; 1581e113844Sdan SELECT * FROM log; 1591e113844Sdan } { 1601e113844Sdan 0 0 i ten 0 1 ii two 1 0 iii thirty 1 1 iv four 1611e113844Sdan one->ten i->i 1621e113844Sdan three->thirty iii->iii 1631e113844Sdan } 1641e113844Sdan 1651e113844Sdan do_execsql_test 1.%TN%.9 { 1661e113844Sdan DELETE FROM log; 1671e113844Sdan UPDATE o1 SET y=v FROM t2, t3 WHERE (1+o1.w*2+o1.x)=t2.a AND t3.k=t2.b; 1681e113844Sdan 1691e113844Sdan SELECT * FROM o1; 1701e113844Sdan SELECT * FROM log; 1711e113844Sdan } { 1721e113844Sdan 0 0 i ten 0 1 xii two 1 0 v thirty 1 1 iv four 1731e113844Sdan two->two ii->xii 1741e113844Sdan thirty->thirty iii->v 1751e113844Sdan } 1761e113844Sdan 1771e113844Sdan do_execsql_test 1.%TN%.10 { 1781e113844Sdan DELETE FROM log; 1791e113844Sdan WITH data(k, v) AS ( 1801e113844Sdan VALUES(1, 'seven'), (1, 'eight'), (2, 'eleven'), (2, 'twelve') 1811e113844Sdan ) 1821e113844Sdan UPDATE o1 SET z=v FROM data WHERE (1+w*2+x)=k; 1831e113844Sdan 1841e113844Sdan SELECT * FROM o1; 1851e113844Sdan SELECT * FROM log; 1861e113844Sdan } { 1871e113844Sdan 0 0 i eight 0 1 xii twelve 1 0 v thirty 1 1 iv four 1881e113844Sdan ten->eight i->i 1891e113844Sdan two->twelve xii->xii 1901e113844Sdan } 1911e113844Sdan 1921e113844Sdan do_test 1.%TN%.11 { db changes } {2} 1931e113844Sdan 1941e113844Sdan do_execsql_test 1.%TN%.12 { 1951e113844Sdan CREATE VIEW w1 AS SELECT * FROM o1; 1961e113844Sdan CREATE TRIGGER w1tr INSTEAD OF UPDATE ON w1 BEGIN 1971e113844Sdan UPDATE o1 SET y=new.y, z=new.z WHERE w=new.w AND x=new.x; 1981e113844Sdan END; 1991e113844Sdan 2001e113844Sdan DELETE FROM log; 2011e113844Sdan WITH data(k, v) AS ( 2021e113844Sdan VALUES(3, 'thirteen'), (3, 'fourteen'), (4, 'fifteen'), (4, 'sixteen') 2031e113844Sdan ) 2041e113844Sdan UPDATE w1 SET z=v FROM data WHERE (1+w*2+x)=k; 2051e113844Sdan } 2061e113844Sdan 2071e113844Sdan do_execsql_test 1.%TN%.13 { 2081e113844Sdan SELECT * FROM w1; 2091e113844Sdan SELECT * FROM log; 2101e113844Sdan } { 2111e113844Sdan 0 0 i eight 0 1 xii twelve 1 0 v fourteen 1 1 iv sixteen 2121e113844Sdan thirty->thirteen v->v 2131e113844Sdan thirteen->fourteen v->v 2141e113844Sdan four->fifteen iv->iv 2151e113844Sdan fifteen->sixteen iv->iv 2161e113844Sdan } 2171e113844Sdan 2189ed322d6Sdan}] 2199ed322d6Sdan} 2209ed322d6Sdan 221f2972b60Sdanifcapable update_delete_limit { 222f2972b60Sdanforeach {tn wo} { 223f2972b60Sdan 1 "" 224f2972b60Sdan 2 "WITHOUT ROWID" 225f2972b60Sdan} { 226f2972b60Sdan reset_db 227f2972b60Sdan 228f2972b60Sdaneval [string map [list %WO% $wo %TN% $tn] { 229f2972b60Sdan do_execsql_test 2.%TN%.1 { 230f2972b60Sdan CREATE TABLE x1(a INTEGER PRIMARY KEY, b) %WO%; 231f2972b60Sdan INSERT INTO x1 VALUES 232f2972b60Sdan (1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), 233f2972b60Sdan (5, 'five'), (6, 'six'), (7, 'seven'), (8, 'eight'); 234f2972b60Sdan } 235f2972b60Sdan 236f2972b60Sdan do_execsql_test 2.%TN%.2 { 237f2972b60Sdan CREATE TABLE data1(x, y); 238f2972b60Sdan INSERT INTO data1 VALUES 239f2972b60Sdan (1, 'eleven'), (1, 'twenty-one'), (2, 'twelve'), (2, 'twenty-two'), 240f2972b60Sdan (3, 'thirteen'), (3, 'twenty-three'), (4, 'fourteen'), (4, 'twenty-four'); 241f2972b60Sdan } 242f2972b60Sdan 243f2972b60Sdan do_execsql_test 2.%TN%.3 { 244f2972b60Sdan UPDATE x1 SET b=y FROM data1 WHERE a=x ORDER BY a LIMIT 3; 245f2972b60Sdan SELECT * FROM x1; 246f2972b60Sdan } { 247f2972b60Sdan 1 eleven 2 twelve 3 thirteen 4 four 5 five 6 six 7 seven 8 eight 248f2972b60Sdan } 249f2972b60Sdan 250f2972b60Sdan do_execsql_test 2.%TN%.4 { 251f2972b60Sdan UPDATE x1 SET b=b||y FROM data1 WHERE a=x ORDER BY b LIMIT 3; 252f2972b60Sdan SELECT * FROM x1; 253f2972b60Sdan } { 254f2972b60Sdan 1 eleveneleven 2 twelve 3 thirteenthirteen 4 fourfourteen 255f2972b60Sdan 5 five 6 six 7 seven 8 eight 256f2972b60Sdan } 257f2972b60Sdan 2581e113844Sdan do_catchsql_test 2.%TN%.5 { 2591e113844Sdan UPDATE x1 SET b=b||b ORDER BY b; 2601e113844Sdan } {1 {ORDER BY without LIMIT on UPDATE}} 2611e113844Sdan do_catchsql_test 2.%TN%.6 { 2621e113844Sdan UPDATE x1 SET b=b||y FROM data1 WHERE a=x ORDER BY b; 2631e113844Sdan } {1 {ORDER BY without LIMIT on UPDATE}} 2641e113844Sdan 2651e113844Sdan #----------------------------------------------------------------------- 2661e113844Sdan 2671e113844Sdan do_execsql_test 2.%TN%.6 { 2681e113844Sdan DROP TABLE x1; 2691e113844Sdan CREATE TABLE x1(u, v, b, PRIMARY KEY(u, v)) %WO%; 2701e113844Sdan INSERT INTO x1 VALUES 2711e113844Sdan (0, 1, 'one'), (1, 0, 'two'), (1, 1, 'three'), (2, 0, 'four'), 2721e113844Sdan (2, 1, 'five'), (3, 0, 'six'), (3, 1, 'seven'), (4, 0, 'eight'); 2731e113844Sdan } 2741e113844Sdan 2751e113844Sdan do_execsql_test 2.%TN%.7 { 2761e113844Sdan UPDATE x1 SET b=y FROM data1 WHERE (u*2+v)=x ORDER BY u, v LIMIT 3; 2771e113844Sdan SELECT * FROM x1; 2781e113844Sdan } { 2791e113844Sdan 0 1 eleven 1 0 twelve 1 1 thirteen 2 0 four 2801e113844Sdan 2 1 five 3 0 six 3 1 seven 4 0 eight 2811e113844Sdan } 2821e113844Sdan 2831e113844Sdan do_execsql_test 2.%TN%.8 { 2841e113844Sdan UPDATE x1 SET b=b||y FROM data1 WHERE (u*2+v)=x ORDER BY b LIMIT 3; 2851e113844Sdan SELECT * FROM x1; 2861e113844Sdan } { 2871e113844Sdan 0 1 eleveneleven 1 0 twelve 1 1 thirteenthirteen 2 0 fourfourteen 2881e113844Sdan 2 1 five 3 0 six 3 1 seven 4 0 eight 2891e113844Sdan } 2901e113844Sdan 2911e113844Sdan 292f2972b60Sdan}] 293f2972b60Sdan}} 2949ed322d6Sdan 2958b023cf5Sdanreset_db 2968b023cf5Sdando_execsql_test 3.0 { 2978b023cf5Sdan CREATE TABLE data(x, y, z); 2988b023cf5Sdan CREATE VIEW t1 AS SELECT * FROM data; 2998b023cf5Sdan CREATE TRIGGER t1_insert INSTEAD OF INSERT ON t1 BEGIN 3008b023cf5Sdan INSERT INTO data VALUES(new.x, new.y, new.z); 3018b023cf5Sdan END; 3028b023cf5Sdan CREATE TRIGGER t1_update INSTEAD OF UPDATE ON t1 BEGIN 3038b023cf5Sdan INSERT INTO log VALUES(old.z || '->' || new.z); 3048b023cf5Sdan END; 3058b023cf5Sdan 3068b023cf5Sdan CREATE TABLE log(t TEXT); 3078b023cf5Sdan 3088b023cf5Sdan INSERT INTO t1 VALUES(1, 'i', 'one'); 3098b023cf5Sdan INSERT INTO t1 VALUES(2, 'ii', 'two'); 3108b023cf5Sdan INSERT INTO t1 VALUES(3, 'iii', 'three'); 3118b023cf5Sdan INSERT INTO t1 VALUES(4, 'iv', 'four'); 3128b023cf5Sdan} 3138b023cf5Sdan 3148b023cf5Sdando_execsql_test 3.1 { 3158b023cf5Sdan WITH input(k, v) AS ( 3168b023cf5Sdan VALUES(3, 'thirty'), (1, 'ten') 3178b023cf5Sdan ) 3188b023cf5Sdan UPDATE t1 SET z=v FROM input WHERE x=k; 3198b023cf5Sdan} 3209ed322d6Sdan 3217465787bSdanforeach {tn sql} { 3227465787bSdan 2 { 3237465787bSdan CREATE TABLE x1(a INT PRIMARY KEY, b, c) WITHOUT ROWID; 3247465787bSdan } 3257465787bSdan 1 { 3267465787bSdan CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c); 3277465787bSdan } 3287465787bSdan 3 { 3297465787bSdan CREATE TABLE x1(a INT PRIMARY KEY, b, c); 3307465787bSdan } 3317465787bSdan} { 3327465787bSdan 3337465787bSdan reset_db 3347465787bSdan execsql $sql 3357465787bSdan 3367465787bSdan do_execsql_test 4.$tn.0 { 3377465787bSdan INSERT INTO x1 VALUES(1, 1, 1); 3387465787bSdan INSERT INTO x1 VALUES(2, 2, 2); 3397465787bSdan INSERT INTO x1 VALUES(3, 3, 3); 3407465787bSdan INSERT INTO x1 VALUES(4, 4, 4); 3417465787bSdan INSERT INTO x1 VALUES(5, 5, 5); 3427465787bSdan CREATE TABLE map(o, t); 3437465787bSdan INSERT INTO map VALUES(3, 30), (4, 40), (1, 10); 3447465787bSdan } 3457465787bSdan 3467465787bSdan do_execsql_test 4.$tn.1 { 3477465787bSdan UPDATE x1 SET a=t FROM map WHERE a=o; 3487465787bSdan SELECT * FROM x1 ORDER BY a; 3497465787bSdan } {2 2 2 5 5 5 10 1 1 30 3 3 40 4 4} 3507465787bSdan} 3517465787bSdan 35207ca7d61Sdanreset_db 35307ca7d61Sdando_execsql_test 5.0 { 35407ca7d61Sdan CREATE TABLE x1(a, b, c); 35507ca7d61Sdan CREATE TABLE x2(a, b, c); 35607ca7d61Sdan} 35707ca7d61Sdan 35807ca7d61Sdanforeach {tn update nm} { 35907ca7d61Sdan 1 "UPDATE x1 SET a=5 FROM x1" x1 36007ca7d61Sdan 2 "UPDATE x1 AS grapes SET a=5 FROM x1 AS grapes" grapes 36107ca7d61Sdan 3 "UPDATE x1 SET a=5 FROM x2, x1" x1 36207ca7d61Sdan 4 "UPDATE x1 AS grapes SET a=5 FROM x2, x1 AS grapes" grapes 36307ca7d61Sdan} { 36407ca7d61Sdan do_catchsql_test 5.$tn $update \ 36507ca7d61Sdan "1 {target object/alias may not appear in FROM clause: $nm}" 36607ca7d61Sdan} 36707ca7d61Sdan 3685daf69e5Sdan#-------------------------------------------------------------------------- 3695daf69e5Sdanreset_db 3705daf69e5Sdando_execsql_test 6.0 { 3715daf69e5Sdan CREATE TABLE t1(a); 3725daf69e5Sdan} 3735daf69e5Sdan 3745daf69e5Sdando_execsql_test 6.1 { 3755daf69e5Sdan UPDATE t1 SET a = 1 FROM ( 3765daf69e5Sdan SELECT * FROM t1 3775daf69e5Sdan ) 3785daf69e5Sdan} {} 3795daf69e5Sdando_execsql_test 6.2 { 3805daf69e5Sdan UPDATE t1 SET a = 1 FROM ( 3815daf69e5Sdan SELECT * FROM t1 UNION ALL SELECT * FROM t1 3825daf69e5Sdan ) 3835daf69e5Sdan} {} 38407ca7d61Sdan 385*75c493f7Sdrh# 2022-03-21 386*75c493f7Sdrh# https://sqlite.org/forum/forumpost/929168fdd6 387*75c493f7Sdrh# 388*75c493f7Sdrhreset_db 389*75c493f7Sdrhdo_execsql_test 7.0 { 390*75c493f7Sdrh CREATE TABLE t1(a); 391*75c493f7Sdrh INSERT INTO t1(a) VALUES(11),(22),(33),(44),(55); 392*75c493f7Sdrh CREATE VIEW t2(b,c) AS SELECT a, COUNT(*) OVER () FROM t1; 393*75c493f7Sdrh CREATE TABLE t3(x,y); 394*75c493f7Sdrh CREATE TRIGGER t2r1 INSTEAD OF UPDATE ON t2 BEGIN 395*75c493f7Sdrh INSERT INTO t3(x,y) VALUES(new.b,new.c); 396*75c493f7Sdrh END; 397*75c493f7Sdrh SELECT * FROM t2; 398*75c493f7Sdrh} {11 5 22 5 33 5 44 5 55 5} 399*75c493f7Sdrhdo_execsql_test 7.1 { 400*75c493f7Sdrh UPDATE t2 SET c=t1.a FROM t1 WHERE t2.b=t1.a; 401*75c493f7Sdrh SELECT * FROM t3; 402*75c493f7Sdrh} {11 11 22 22 33 33 44 44 55 55} 403*75c493f7Sdrh 404*75c493f7Sdrh 4059ed322d6Sdanfinish_test 406