xref: /sqlite-3.40.0/test/upfrom2.test (revision aeb4e6ee)
1# 2020 April 29
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
13set testdir [file dirname $argv0]
14source $testdir/tester.tcl
15set testprefix upfrom2
16
17# Test cases:
18#
19#   1.*: Test that triggers are fired correctly for UPDATE FROM statements,
20#        and only once for each row. Except for INSTEAD OF triggers on
21#        views - these are fired once for each row returned by the join,
22#        including duplicates.
23#
24#   2.*: Test adding ORDER BY and LIMIT clauses with UPDATE FROM statements.
25#
26#   5.*: Test that specifying the target table name or alias in the FROM
27#        clause of an UPDATE statement is an error.
28#
29
30foreach {tn wo} {
31  1 ""
32  2 "WITHOUT ROWID"
33} {
34  reset_db
35
36  eval [string map [list %WO% $wo %TN% $tn] {
37  do_execsql_test 1.%TN%.0 {
38    CREATE TABLE log(t TEXT);
39    CREATE TABLE t1(x PRIMARY KEY, y, z UNIQUE) %WO%;
40    CREATE INDEX t1y ON t1(y);
41
42    INSERT INTO t1 VALUES(1, 'i',   'one');
43    INSERT INTO t1 VALUES(2, 'ii',  'two');
44    INSERT INTO t1 VALUES(3, 'iii', 'three');
45    INSERT INTO t1 VALUES(4, 'iv',  'four');
46
47    CREATE TRIGGER tr1 BEFORE UPDATE ON t1 BEGIN
48      INSERT INTO log VALUES(old.z || '->' || new.z);
49    END;
50    CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
51      INSERT INTO log VALUES(old.y || '->' || new.y);
52    END;
53  }
54
55  do_execsql_test 1.%TN%.1 {
56    WITH data(k, v) AS (
57      VALUES(3, 'thirty'), (1, 'ten')
58    )
59    UPDATE t1 SET z=v FROM data WHERE x=k;
60
61    SELECT * FROM t1;
62    SELECT * FROM log;
63  } {
64    1 i ten   2 ii two   3 iii thirty   4 iv four
65    one->ten        i->i
66    three->thirty   iii->iii
67  }
68
69  do_execsql_test 1.%TN%.2 {
70    CREATE TABLE t2(a, b);
71    CREATE TABLE t3(k, v);
72
73    INSERT INTO t3 VALUES(5,   'v');
74    INSERT INTO t3 VALUES(12, 'xii');
75
76    INSERT INTO t2 VALUES(2, 12);
77    INSERT INTO t2 VALUES(3, 5);
78
79    DELETE FROM log;
80    UPDATE t1 SET y=v FROM t2, t3 WHERE t1.x=t2.a AND t3.k=t2.b;
81
82    SELECT * FROM t1;
83    SELECT * FROM log;
84  } {
85    1 i ten   2 xii two   3 v thirty   4 iv four
86    two->two         ii->xii
87    thirty->thirty   iii->v
88  }
89
90  do_execsql_test 1.%TN%.3 {
91    DELETE FROM log;
92    WITH data(k, v) AS (
93      VALUES(1, 'seven'), (1, 'eight'), (2, 'eleven'), (2, 'twelve')
94    )
95    UPDATE t1 SET z=v FROM data WHERE x=k;
96
97    SELECT * FROM t1;
98    SELECT * FROM log;
99  } {
100    1 i eight   2 xii twelve   3 v thirty   4 iv four
101    ten->eight        i->i
102    two->twelve       xii->xii
103  }
104
105  do_test 1.%TN%.4 { db changes } {2}
106
107  do_execsql_test 1.%TN%.5 {
108    CREATE VIEW v1 AS SELECT * FROM t1;
109    CREATE TRIGGER v1tr INSTEAD OF UPDATE ON v1 BEGIN
110      UPDATE t1 SET y=new.y, z=new.z WHERE x=new.x;
111    END;
112
113    DELETE FROM log;
114    WITH data(k, v) AS (
115      VALUES(3, 'thirteen'), (3, 'fourteen'), (4, 'fifteen'), (4, 'sixteen')
116    )
117    UPDATE v1 SET z=v FROM data WHERE x=k;
118  }
119
120  do_execsql_test 1.%TN%.6 {
121    SELECT * FROM v1;
122    SELECT * FROM log;
123  } {
124    1 i eight   2 xii twelve   3 v fourteen   4 iv sixteen
125    thirty->thirteen  v->v
126    thirteen->fourteen  v->v
127    four->fifteen  iv->iv
128    fifteen->sixteen  iv->iv
129  }
130
131  #--------------------------------------------------------------
132
133  do_execsql_test 1.%TN%.7 {
134    CREATE TABLE o1(w, x, y, z UNIQUE, PRIMARY KEY(w, x)) %WO%;
135    CREATE INDEX o1y ON t1(y);
136
137    INSERT INTO o1 VALUES(0, 0, 'i', 'one');
138    INSERT INTO o1 VALUES(0, 1, 'ii', 'two');
139    INSERT INTO o1 VALUES(1, 0, 'iii', 'three');
140    INSERT INTO o1 VALUES(1, 1, 'iv', 'four');
141
142    CREATE TRIGGER tro1 BEFORE UPDATE ON o1 BEGIN
143      INSERT INTO log VALUES(old.z || '->' || new.z);
144    END;
145    CREATE TRIGGER tro2 AFTER UPDATE ON o1 BEGIN
146      INSERT INTO log VALUES(old.y || '->' || new.y);
147    END;
148  }
149
150  do_execsql_test 1.%TN%.8 {
151    DELETE FROM log;
152    WITH data(k, v) AS (
153      VALUES(3, 'thirty'), (1, 'ten')
154    )
155    UPDATE o1 SET z=v FROM data WHERE (1+x+w*2)=k;
156
157    SELECT * FROM o1;
158    SELECT * FROM log;
159  } {
160    0 0 i ten   0 1 ii two   1 0 iii thirty   1 1 iv four
161    one->ten        i->i
162    three->thirty   iii->iii
163  }
164
165  do_execsql_test 1.%TN%.9 {
166    DELETE FROM log;
167    UPDATE o1 SET y=v FROM t2, t3 WHERE (1+o1.w*2+o1.x)=t2.a AND t3.k=t2.b;
168
169    SELECT * FROM o1;
170    SELECT * FROM log;
171  } {
172    0 0 i ten   0 1 xii two   1 0 v thirty   1 1 iv four
173    two->two         ii->xii
174    thirty->thirty   iii->v
175  }
176
177  do_execsql_test 1.%TN%.10 {
178    DELETE FROM log;
179    WITH data(k, v) AS (
180      VALUES(1, 'seven'), (1, 'eight'), (2, 'eleven'), (2, 'twelve')
181    )
182    UPDATE o1 SET z=v FROM data WHERE (1+w*2+x)=k;
183
184    SELECT * FROM o1;
185    SELECT * FROM log;
186  } {
187    0 0 i eight   0 1 xii twelve   1 0 v thirty   1 1 iv four
188    ten->eight        i->i
189    two->twelve       xii->xii
190  }
191
192  do_test 1.%TN%.11 { db changes } {2}
193
194  do_execsql_test 1.%TN%.12 {
195    CREATE VIEW w1 AS SELECT * FROM o1;
196    CREATE TRIGGER w1tr INSTEAD OF UPDATE ON w1 BEGIN
197      UPDATE o1 SET y=new.y, z=new.z WHERE w=new.w AND x=new.x;
198    END;
199
200    DELETE FROM log;
201    WITH data(k, v) AS (
202      VALUES(3, 'thirteen'), (3, 'fourteen'), (4, 'fifteen'), (4, 'sixteen')
203    )
204    UPDATE w1 SET z=v FROM data WHERE (1+w*2+x)=k;
205  }
206
207  do_execsql_test 1.%TN%.13 {
208    SELECT * FROM w1;
209    SELECT * FROM log;
210  } {
211    0 0 i eight   0 1 xii twelve   1 0 v fourteen   1 1 iv sixteen
212    thirty->thirteen  v->v
213    thirteen->fourteen  v->v
214    four->fifteen  iv->iv
215    fifteen->sixteen  iv->iv
216  }
217
218}]
219}
220
221ifcapable update_delete_limit {
222foreach {tn wo} {
223  1 ""
224  2 "WITHOUT ROWID"
225} {
226  reset_db
227
228eval [string map [list %WO% $wo %TN% $tn] {
229  do_execsql_test 2.%TN%.1 {
230    CREATE TABLE x1(a INTEGER PRIMARY KEY, b) %WO%;
231    INSERT INTO x1 VALUES
232        (1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'),
233        (5, 'five'), (6, 'six'), (7, 'seven'), (8, 'eight');
234  }
235
236  do_execsql_test 2.%TN%.2 {
237    CREATE TABLE data1(x, y);
238    INSERT INTO data1 VALUES
239    (1, 'eleven'), (1, 'twenty-one'), (2, 'twelve'), (2, 'twenty-two'),
240    (3, 'thirteen'), (3, 'twenty-three'), (4, 'fourteen'), (4, 'twenty-four');
241  }
242
243  do_execsql_test 2.%TN%.3 {
244    UPDATE x1 SET b=y FROM data1 WHERE a=x ORDER BY a LIMIT 3;
245    SELECT * FROM x1;
246  } {
247    1 eleven 2 twelve 3 thirteen 4 four 5 five 6 six 7 seven 8 eight
248  }
249
250  do_execsql_test 2.%TN%.4 {
251    UPDATE x1 SET b=b||y FROM data1 WHERE a=x ORDER BY b LIMIT 3;
252    SELECT * FROM x1;
253  } {
254    1 eleveneleven 2 twelve 3 thirteenthirteen 4 fourfourteen
255    5 five 6 six 7 seven 8 eight
256  }
257
258  do_catchsql_test 2.%TN%.5 {
259    UPDATE x1 SET b=b||b ORDER BY b;
260  } {1 {ORDER BY without LIMIT on UPDATE}}
261  do_catchsql_test 2.%TN%.6 {
262    UPDATE x1 SET b=b||y FROM data1 WHERE a=x ORDER BY b;
263  } {1 {ORDER BY without LIMIT on UPDATE}}
264
265  #-----------------------------------------------------------------------
266
267  do_execsql_test 2.%TN%.6 {
268    DROP TABLE x1;
269    CREATE TABLE x1(u, v, b, PRIMARY KEY(u, v)) %WO%;
270    INSERT INTO x1 VALUES
271        (0, 1, 'one'), (1, 0, 'two'), (1, 1, 'three'), (2, 0, 'four'),
272        (2, 1, 'five'), (3, 0, 'six'), (3, 1, 'seven'), (4, 0, 'eight');
273  }
274
275  do_execsql_test 2.%TN%.7 {
276    UPDATE x1 SET b=y FROM data1 WHERE (u*2+v)=x ORDER BY u, v LIMIT 3;
277    SELECT * FROM x1;
278  } {
279    0 1 eleven 1 0 twelve 1 1 thirteen 2 0 four
280    2 1 five 3 0 six 3 1 seven 4 0 eight
281  }
282
283  do_execsql_test 2.%TN%.8 {
284    UPDATE x1 SET b=b||y FROM data1 WHERE (u*2+v)=x ORDER BY b LIMIT 3;
285    SELECT * FROM x1;
286  } {
287    0 1 eleveneleven 1 0 twelve 1 1 thirteenthirteen 2 0 fourfourteen
288    2 1 five  3 0 six 3 1 seven 4 0 eight
289  }
290
291
292}]
293}}
294
295reset_db
296do_execsql_test 3.0 {
297  CREATE TABLE data(x, y, z);
298  CREATE VIEW t1 AS SELECT * FROM data;
299  CREATE TRIGGER t1_insert INSTEAD OF INSERT ON t1 BEGIN
300    INSERT INTO data VALUES(new.x, new.y, new.z);
301  END;
302  CREATE TRIGGER t1_update INSTEAD OF UPDATE ON t1 BEGIN
303    INSERT INTO log VALUES(old.z || '->' || new.z);
304  END;
305
306  CREATE TABLE log(t TEXT);
307
308  INSERT INTO t1 VALUES(1, 'i',   'one');
309  INSERT INTO t1 VALUES(2, 'ii',  'two');
310  INSERT INTO t1 VALUES(3, 'iii', 'three');
311  INSERT INTO t1 VALUES(4, 'iv',  'four');
312}
313
314do_execsql_test 3.1 {
315  WITH input(k, v) AS (
316      VALUES(3, 'thirty'), (1, 'ten')
317  )
318  UPDATE t1 SET z=v FROM input WHERE x=k;
319}
320
321foreach {tn sql} {
322  2 {
323    CREATE TABLE x1(a INT PRIMARY KEY, b, c) WITHOUT ROWID;
324  }
325  1 {
326    CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c);
327  }
328  3 {
329    CREATE TABLE x1(a INT PRIMARY KEY, b, c);
330  }
331} {
332
333  reset_db
334  execsql $sql
335
336  do_execsql_test 4.$tn.0 {
337    INSERT INTO x1 VALUES(1, 1, 1);
338    INSERT INTO x1 VALUES(2, 2, 2);
339    INSERT INTO x1 VALUES(3, 3, 3);
340    INSERT INTO x1 VALUES(4, 4, 4);
341    INSERT INTO x1 VALUES(5, 5, 5);
342    CREATE TABLE map(o, t);
343    INSERT INTO map VALUES(3, 30), (4, 40), (1, 10);
344  }
345
346  do_execsql_test 4.$tn.1 {
347    UPDATE x1 SET a=t FROM map WHERE a=o;
348    SELECT * FROM x1 ORDER BY a;
349  } {2 2 2   5 5 5   10 1 1  30 3 3  40 4 4}
350}
351
352reset_db
353do_execsql_test 5.0 {
354  CREATE TABLE x1(a, b, c);
355  CREATE TABLE x2(a, b, c);
356}
357
358foreach {tn update nm} {
359  1 "UPDATE x1 SET a=5 FROM x1" x1
360  2 "UPDATE x1 AS grapes SET a=5 FROM x1 AS grapes" grapes
361  3 "UPDATE x1 SET a=5 FROM x2, x1" x1
362  4 "UPDATE x1 AS grapes SET a=5 FROM x2, x1 AS grapes" grapes
363} {
364  do_catchsql_test 5.$tn $update \
365    "1 {target object/alias may not appear in FROM clause: $nm}"
366}
367
368
369finish_test
370
371
372