Remove unused parameter in lookup_var_attr_stats
[pgsql.git] / src / test / regress / expected / merge.out
blob28d855106364a1d019250a33e53ee88b38805193
1 --
2 -- MERGE
3 --
4 CREATE USER regress_merge_privs;
5 CREATE USER regress_merge_no_privs;
6 CREATE USER regress_merge_none;
7 DROP TABLE IF EXISTS target;
8 NOTICE:  table "target" does not exist, skipping
9 DROP TABLE IF EXISTS source;
10 NOTICE:  table "source" does not exist, skipping
11 CREATE TABLE target (tid integer, balance integer)
12   WITH (autovacuum_enabled=off);
13 CREATE TABLE source (sid integer, delta integer) -- no index
14   WITH (autovacuum_enabled=off);
15 INSERT INTO target VALUES (1, 10);
16 INSERT INTO target VALUES (2, 20);
17 INSERT INTO target VALUES (3, 30);
18 SELECT t.ctid is not null as matched, t.*, s.* FROM source s FULL OUTER JOIN target t ON s.sid = t.tid ORDER BY t.tid, s.sid;
19  matched | tid | balance | sid | delta 
20 ---------+-----+---------+-----+-------
21  t       |   1 |      10 |     |      
22  t       |   2 |      20 |     |      
23  t       |   3 |      30 |     |      
24 (3 rows)
26 ALTER TABLE target OWNER TO regress_merge_privs;
27 ALTER TABLE source OWNER TO regress_merge_privs;
28 CREATE TABLE target2 (tid integer, balance integer)
29   WITH (autovacuum_enabled=off);
30 CREATE TABLE source2 (sid integer, delta integer)
31   WITH (autovacuum_enabled=off);
32 ALTER TABLE target2 OWNER TO regress_merge_no_privs;
33 ALTER TABLE source2 OWNER TO regress_merge_no_privs;
34 GRANT INSERT ON target TO regress_merge_no_privs;
35 SET SESSION AUTHORIZATION regress_merge_privs;
36 EXPLAIN (COSTS OFF)
37 MERGE INTO target t
38 USING source AS s
39 ON t.tid = s.sid
40 WHEN MATCHED THEN
41         DELETE;
42                QUERY PLAN               
43 ----------------------------------------
44  Merge on target t
45    ->  Merge Join
46          Merge Cond: (t.tid = s.sid)
47          ->  Sort
48                Sort Key: t.tid
49                ->  Seq Scan on target t
50          ->  Sort
51                Sort Key: s.sid
52                ->  Seq Scan on source s
53 (9 rows)
56 -- Errors
58 MERGE INTO target t RANDOMWORD
59 USING source AS s
60 ON t.tid = s.sid
61 WHEN MATCHED THEN
62         UPDATE SET balance = 0;
63 ERROR:  syntax error at or near "RANDOMWORD"
64 LINE 1: MERGE INTO target t RANDOMWORD
65                             ^
66 -- MATCHED/INSERT error
67 MERGE INTO target t
68 USING source AS s
69 ON t.tid = s.sid
70 WHEN MATCHED THEN
71         INSERT DEFAULT VALUES;
72 ERROR:  syntax error at or near "INSERT"
73 LINE 5:  INSERT DEFAULT VALUES;
74          ^
75 -- NOT MATCHED BY SOURCE/INSERT error
76 MERGE INTO target t
77 USING source AS s
78 ON t.tid = s.sid
79 WHEN NOT MATCHED BY SOURCE THEN
80         INSERT DEFAULT VALUES;
81 ERROR:  syntax error at or near "INSERT"
82 LINE 5:  INSERT DEFAULT VALUES;
83          ^
84 -- incorrectly specifying INTO target
85 MERGE INTO target t
86 USING source AS s
87 ON t.tid = s.sid
88 WHEN NOT MATCHED THEN
89         INSERT INTO target DEFAULT VALUES;
90 ERROR:  syntax error at or near "INTO"
91 LINE 5:  INSERT INTO target DEFAULT VALUES;
92                 ^
93 -- Multiple VALUES clause
94 MERGE INTO target t
95 USING source AS s
96 ON t.tid = s.sid
97 WHEN NOT MATCHED THEN
98         INSERT VALUES (1,1), (2,2);
99 ERROR:  syntax error at or near ","
100 LINE 5:  INSERT VALUES (1,1), (2,2);
101                             ^
102 -- SELECT query for INSERT
103 MERGE INTO target t
104 USING source AS s
105 ON t.tid = s.sid
106 WHEN NOT MATCHED THEN
107         INSERT SELECT (1, 1);
108 ERROR:  syntax error at or near "SELECT"
109 LINE 5:  INSERT SELECT (1, 1);
110                 ^
111 -- NOT MATCHED/UPDATE
112 MERGE INTO target t
113 USING source AS s
114 ON t.tid = s.sid
115 WHEN NOT MATCHED THEN
116         UPDATE SET balance = 0;
117 ERROR:  syntax error at or near "UPDATE"
118 LINE 5:  UPDATE SET balance = 0;
119          ^
120 -- NOT MATCHED BY TARGET/UPDATE
121 MERGE INTO target t
122 USING source AS s
123 ON t.tid = s.sid
124 WHEN NOT MATCHED BY TARGET THEN
125         UPDATE SET balance = 0;
126 ERROR:  syntax error at or near "UPDATE"
127 LINE 5:  UPDATE SET balance = 0;
128          ^
129 -- UPDATE tablename
130 MERGE INTO target t
131 USING source AS s
132 ON t.tid = s.sid
133 WHEN MATCHED THEN
134         UPDATE target SET balance = 0;
135 ERROR:  syntax error at or near "target"
136 LINE 5:  UPDATE target SET balance = 0;
137                 ^
138 -- source and target names the same
139 MERGE INTO target
140 USING target
141 ON tid = tid
142 WHEN MATCHED THEN DO NOTHING;
143 ERROR:  name "target" specified more than once
144 DETAIL:  The name is used both as MERGE target table and data source.
145 -- used in a CTE without RETURNING
146 WITH foo AS (
147   MERGE INTO target USING source ON (true)
148   WHEN MATCHED THEN DELETE
149 ) SELECT * FROM foo;
150 ERROR:  WITH query "foo" does not have a RETURNING clause
151 LINE 4: ) SELECT * FROM foo;
152                         ^
153 -- used in COPY without RETURNING
154 COPY (
155   MERGE INTO target USING source ON (true)
156   WHEN MATCHED THEN DELETE
157 ) TO stdout;
158 ERROR:  COPY query must have a RETURNING clause
159 -- unsupported relation types
160 -- materialized view
161 CREATE MATERIALIZED VIEW mv AS SELECT * FROM target;
162 MERGE INTO mv t
163 USING source s
164 ON t.tid = s.sid
165 WHEN NOT MATCHED THEN
166         INSERT DEFAULT VALUES;
167 ERROR:  cannot execute MERGE on relation "mv"
168 DETAIL:  This operation is not supported for materialized views.
169 DROP MATERIALIZED VIEW mv;
170 -- permissions
171 SET SESSION AUTHORIZATION regress_merge_none;
172 MERGE INTO target
173 USING (SELECT 1)
174 ON true
175 WHEN MATCHED THEN
176         DO NOTHING;
177 ERROR:  permission denied for table target
178 SET SESSION AUTHORIZATION regress_merge_privs;
179 MERGE INTO target
180 USING source2
181 ON target.tid = source2.sid
182 WHEN MATCHED THEN
183         UPDATE SET balance = 0;
184 ERROR:  permission denied for table source2
185 GRANT INSERT ON target TO regress_merge_no_privs;
186 SET SESSION AUTHORIZATION regress_merge_no_privs;
187 MERGE INTO target
188 USING source2
189 ON target.tid = source2.sid
190 WHEN MATCHED THEN
191         UPDATE SET balance = 0;
192 ERROR:  permission denied for table target
193 GRANT UPDATE ON target2 TO regress_merge_privs;
194 SET SESSION AUTHORIZATION regress_merge_privs;
195 MERGE INTO target2
196 USING source
197 ON target2.tid = source.sid
198 WHEN MATCHED THEN
199         DELETE;
200 ERROR:  permission denied for table target2
201 MERGE INTO target2
202 USING source
203 ON target2.tid = source.sid
204 WHEN NOT MATCHED THEN
205         INSERT DEFAULT VALUES;
206 ERROR:  permission denied for table target2
207 -- check if the target can be accessed from source relation subquery; we should
208 -- not be able to do so
209 MERGE INTO target t
210 USING (SELECT * FROM source WHERE t.tid > sid) s
211 ON t.tid = s.sid
212 WHEN NOT MATCHED THEN
213         INSERT DEFAULT VALUES;
214 ERROR:  invalid reference to FROM-clause entry for table "t"
215 LINE 2: USING (SELECT * FROM source WHERE t.tid > sid) s
216                                           ^
217 DETAIL:  There is an entry for table "t", but it cannot be referenced from this part of the query.
219 -- initial tests
221 -- zero rows in source has no effect
222 MERGE INTO target
223 USING source
224 ON target.tid = source.sid
225 WHEN MATCHED THEN
226         UPDATE SET balance = 0;
227 MERGE INTO target t
228 USING source AS s
229 ON t.tid = s.sid
230 WHEN MATCHED THEN
231         UPDATE SET balance = 0;
232 MERGE INTO target t
233 USING source AS s
234 ON t.tid = s.sid
235 WHEN MATCHED THEN
236         DELETE;
237 BEGIN;
238 MERGE INTO target t
239 USING source AS s
240 ON t.tid = s.sid
241 WHEN NOT MATCHED THEN
242         INSERT DEFAULT VALUES;
243 ROLLBACK;
244 -- insert some non-matching source rows to work from
245 INSERT INTO source VALUES (4, 40);
246 SELECT * FROM source ORDER BY sid;
247  sid | delta 
248 -----+-------
249    4 |    40
250 (1 row)
252 SELECT * FROM target ORDER BY tid;
253  tid | balance 
254 -----+---------
255    1 |      10
256    2 |      20
257    3 |      30
258 (3 rows)
260 MERGE INTO target t
261 USING source AS s
262 ON t.tid = s.sid
263 WHEN NOT MATCHED THEN
264         DO NOTHING;
265 MERGE INTO target t
266 USING source AS s
267 ON t.tid = s.sid
268 WHEN MATCHED THEN
269         UPDATE SET balance = 0;
270 MERGE INTO target t
271 USING source AS s
272 ON t.tid = s.sid
273 WHEN MATCHED THEN
274         DELETE;
275 BEGIN;
276 MERGE INTO target t
277 USING source AS s
278 ON t.tid = s.sid
279 WHEN NOT MATCHED THEN
280         INSERT DEFAULT VALUES;
281 SELECT * FROM target ORDER BY tid;
282  tid | balance 
283 -----+---------
284    1 |      10
285    2 |      20
286    3 |      30
287      |        
288 (4 rows)
290 ROLLBACK;
291 -- DELETE/INSERT not matched by source/target
292 BEGIN;
293 MERGE INTO target t
294 USING source AS s
295 ON t.tid = s.sid
296 WHEN NOT MATCHED BY SOURCE THEN
297         DELETE
298 WHEN NOT MATCHED BY TARGET THEN
299         INSERT VALUES (s.sid, s.delta)
300 RETURNING merge_action(), t.*;
301  merge_action | tid | balance 
302 --------------+-----+---------
303  DELETE       |   1 |      10
304  DELETE       |   2 |      20
305  DELETE       |   3 |      30
306  INSERT       |   4 |      40
307 (4 rows)
309 SELECT * FROM target ORDER BY tid;
310  tid | balance 
311 -----+---------
312    4 |      40
313 (1 row)
315 ROLLBACK;
316 -- index plans
317 INSERT INTO target SELECT generate_series(1000,2500), 0;
318 ALTER TABLE target ADD PRIMARY KEY (tid);
319 ANALYZE target;
320 EXPLAIN (COSTS OFF)
321 MERGE INTO target t
322 USING source AS s
323 ON t.tid = s.sid
324 WHEN MATCHED THEN
325         UPDATE SET balance = 0;
326                QUERY PLAN               
327 ----------------------------------------
328  Merge on target t
329    ->  Hash Join
330          Hash Cond: (s.sid = t.tid)
331          ->  Seq Scan on source s
332          ->  Hash
333                ->  Seq Scan on target t
334 (6 rows)
336 EXPLAIN (COSTS OFF)
337 MERGE INTO target t
338 USING source AS s
339 ON t.tid = s.sid
340 WHEN MATCHED THEN
341         DELETE;
342                QUERY PLAN               
343 ----------------------------------------
344  Merge on target t
345    ->  Hash Join
346          Hash Cond: (s.sid = t.tid)
347          ->  Seq Scan on source s
348          ->  Hash
349                ->  Seq Scan on target t
350 (6 rows)
352 EXPLAIN (COSTS OFF)
353 MERGE INTO target t
354 USING source AS s
355 ON t.tid = s.sid
356 WHEN NOT MATCHED THEN
357         INSERT VALUES (4, NULL);
358                QUERY PLAN               
359 ----------------------------------------
360  Merge on target t
361    ->  Hash Left Join
362          Hash Cond: (s.sid = t.tid)
363          ->  Seq Scan on source s
364          ->  Hash
365                ->  Seq Scan on target t
366 (6 rows)
368 DELETE FROM target WHERE tid > 100;
369 ANALYZE target;
370 -- insert some matching source rows to work from
371 INSERT INTO source VALUES (2, 5);
372 INSERT INTO source VALUES (3, 20);
373 SELECT * FROM source ORDER BY sid;
374  sid | delta 
375 -----+-------
376    2 |     5
377    3 |    20
378    4 |    40
379 (3 rows)
381 SELECT * FROM target ORDER BY tid;
382  tid | balance 
383 -----+---------
384    1 |      10
385    2 |      20
386    3 |      30
387 (3 rows)
389 -- equivalent of an UPDATE join
390 BEGIN;
391 MERGE INTO target t
392 USING source AS s
393 ON t.tid = s.sid
394 WHEN MATCHED THEN
395         UPDATE SET balance = 0;
396 SELECT * FROM target ORDER BY tid;
397  tid | balance 
398 -----+---------
399    1 |      10
400    2 |       0
401    3 |       0
402 (3 rows)
404 ROLLBACK;
405 -- equivalent of a DELETE join
406 BEGIN;
407 MERGE INTO target t
408 USING source AS s
409 ON t.tid = s.sid
410 WHEN MATCHED THEN
411         DELETE;
412 SELECT * FROM target ORDER BY tid;
413  tid | balance 
414 -----+---------
415    1 |      10
416 (1 row)
418 ROLLBACK;
419 BEGIN;
420 MERGE INTO target t
421 USING source AS s
422 ON t.tid = s.sid
423 WHEN MATCHED THEN
424         DO NOTHING;
425 SELECT * FROM target ORDER BY tid;
426  tid | balance 
427 -----+---------
428    1 |      10
429    2 |      20
430    3 |      30
431 (3 rows)
433 ROLLBACK;
434 BEGIN;
435 MERGE INTO target t
436 USING source AS s
437 ON t.tid = s.sid
438 WHEN NOT MATCHED THEN
439         INSERT VALUES (4, NULL);
440 SELECT * FROM target ORDER BY tid;
441  tid | balance 
442 -----+---------
443    1 |      10
444    2 |      20
445    3 |      30
446    4 |        
447 (4 rows)
449 ROLLBACK;
450 -- duplicate source row causes multiple target row update ERROR
451 INSERT INTO source VALUES (2, 5);
452 SELECT * FROM source ORDER BY sid;
453  sid | delta 
454 -----+-------
455    2 |     5
456    2 |     5
457    3 |    20
458    4 |    40
459 (4 rows)
461 SELECT * FROM target ORDER BY tid;
462  tid | balance 
463 -----+---------
464    1 |      10
465    2 |      20
466    3 |      30
467 (3 rows)
469 BEGIN;
470 MERGE INTO target t
471 USING source AS s
472 ON t.tid = s.sid
473 WHEN MATCHED THEN
474         UPDATE SET balance = 0;
475 ERROR:  MERGE command cannot affect row a second time
476 HINT:  Ensure that not more than one source row matches any one target row.
477 ROLLBACK;
478 BEGIN;
479 MERGE INTO target t
480 USING source AS s
481 ON t.tid = s.sid
482 WHEN MATCHED THEN
483         DELETE;
484 ERROR:  MERGE command cannot affect row a second time
485 HINT:  Ensure that not more than one source row matches any one target row.
486 ROLLBACK;
487 -- remove duplicate MATCHED data from source data
488 DELETE FROM source WHERE sid = 2;
489 INSERT INTO source VALUES (2, 5);
490 SELECT * FROM source ORDER BY sid;
491  sid | delta 
492 -----+-------
493    2 |     5
494    3 |    20
495    4 |    40
496 (3 rows)
498 SELECT * FROM target ORDER BY tid;
499  tid | balance 
500 -----+---------
501    1 |      10
502    2 |      20
503    3 |      30
504 (3 rows)
506 -- duplicate source row on INSERT should fail because of target_pkey
507 INSERT INTO source VALUES (4, 40);
508 BEGIN;
509 MERGE INTO target t
510 USING source AS s
511 ON t.tid = s.sid
512 WHEN NOT MATCHED THEN
513   INSERT VALUES (4, NULL);
514 ERROR:  duplicate key value violates unique constraint "target_pkey"
515 DETAIL:  Key (tid)=(4) already exists.
516 SELECT * FROM target ORDER BY tid;
517 ERROR:  current transaction is aborted, commands ignored until end of transaction block
518 ROLLBACK;
519 -- remove duplicate NOT MATCHED data from source data
520 DELETE FROM source WHERE sid = 4;
521 INSERT INTO source VALUES (4, 40);
522 SELECT * FROM source ORDER BY sid;
523  sid | delta 
524 -----+-------
525    2 |     5
526    3 |    20
527    4 |    40
528 (3 rows)
530 SELECT * FROM target ORDER BY tid;
531  tid | balance 
532 -----+---------
533    1 |      10
534    2 |      20
535    3 |      30
536 (3 rows)
538 -- remove constraints
539 alter table target drop CONSTRAINT target_pkey;
540 alter table target alter column tid drop not null;
541 -- multiple actions
542 BEGIN;
543 MERGE INTO target t
544 USING source AS s
545 ON t.tid = s.sid
546 WHEN NOT MATCHED THEN
547         INSERT VALUES (4, 4)
548 WHEN MATCHED THEN
549         UPDATE SET balance = 0;
550 SELECT * FROM target ORDER BY tid;
551  tid | balance 
552 -----+---------
553    1 |      10
554    2 |       0
555    3 |       0
556    4 |       4
557 (4 rows)
559 ROLLBACK;
560 -- should be equivalent
561 BEGIN;
562 MERGE INTO target t
563 USING source AS s
564 ON t.tid = s.sid
565 WHEN MATCHED THEN
566         UPDATE SET balance = 0
567 WHEN NOT MATCHED THEN
568         INSERT VALUES (4, 4);
569 SELECT * FROM target ORDER BY tid;
570  tid | balance 
571 -----+---------
572    1 |      10
573    2 |       0
574    3 |       0
575    4 |       4
576 (4 rows)
578 ROLLBACK;
579 -- column references
580 -- do a simple equivalent of an UPDATE join
581 BEGIN;
582 MERGE INTO target t
583 USING source AS s
584 ON t.tid = s.sid
585 WHEN MATCHED THEN
586         UPDATE SET balance = t.balance + s.delta;
587 SELECT * FROM target ORDER BY tid;
588  tid | balance 
589 -----+---------
590    1 |      10
591    2 |      25
592    3 |      50
593 (3 rows)
595 ROLLBACK;
596 -- do a simple equivalent of an INSERT SELECT
597 BEGIN;
598 MERGE INTO target t
599 USING source AS s
600 ON t.tid = s.sid
601 WHEN NOT MATCHED THEN
602         INSERT VALUES (s.sid, s.delta);
603 SELECT * FROM target ORDER BY tid;
604  tid | balance 
605 -----+---------
606    1 |      10
607    2 |      20
608    3 |      30
609    4 |      40
610 (4 rows)
612 ROLLBACK;
613 -- and again with duplicate source rows
614 INSERT INTO source VALUES (5, 50);
615 INSERT INTO source VALUES (5, 50);
616 -- do a simple equivalent of an INSERT SELECT
617 BEGIN;
618 MERGE INTO target t
619 USING source AS s
620 ON t.tid = s.sid
621 WHEN NOT MATCHED THEN
622   INSERT VALUES (s.sid, s.delta);
623 SELECT * FROM target ORDER BY tid;
624  tid | balance 
625 -----+---------
626    1 |      10
627    2 |      20
628    3 |      30
629    4 |      40
630    5 |      50
631    5 |      50
632 (6 rows)
634 ROLLBACK;
635 -- removing duplicate source rows
636 DELETE FROM source WHERE sid = 5;
637 -- and again with explicitly identified column list
638 BEGIN;
639 MERGE INTO target t
640 USING source AS s
641 ON t.tid = s.sid
642 WHEN NOT MATCHED THEN
643         INSERT (tid, balance) VALUES (s.sid, s.delta);
644 SELECT * FROM target ORDER BY tid;
645  tid | balance 
646 -----+---------
647    1 |      10
648    2 |      20
649    3 |      30
650    4 |      40
651 (4 rows)
653 ROLLBACK;
654 -- and again with a subtle error: referring to non-existent target row for NOT MATCHED
655 MERGE INTO target t
656 USING source AS s
657 ON t.tid = s.sid
658 WHEN NOT MATCHED THEN
659         INSERT (tid, balance) VALUES (t.tid, s.delta);
660 ERROR:  invalid reference to FROM-clause entry for table "t"
661 LINE 5:  INSERT (tid, balance) VALUES (t.tid, s.delta);
662                                        ^
663 DETAIL:  There is an entry for table "t", but it cannot be referenced from this part of the query.
664 -- and again with a constant ON clause
665 BEGIN;
666 MERGE INTO target t
667 USING source AS s
668 ON (SELECT true)
669 WHEN NOT MATCHED THEN
670         INSERT (tid, balance) VALUES (t.tid, s.delta);
671 ERROR:  invalid reference to FROM-clause entry for table "t"
672 LINE 5:  INSERT (tid, balance) VALUES (t.tid, s.delta);
673                                        ^
674 DETAIL:  There is an entry for table "t", but it cannot be referenced from this part of the query.
675 SELECT * FROM target ORDER BY tid;
676 ERROR:  current transaction is aborted, commands ignored until end of transaction block
677 ROLLBACK;
678 -- now the classic UPSERT
679 BEGIN;
680 MERGE INTO target t
681 USING source AS s
682 ON t.tid = s.sid
683 WHEN MATCHED THEN
684         UPDATE SET balance = t.balance + s.delta
685 WHEN NOT MATCHED THEN
686         INSERT VALUES (s.sid, s.delta);
687 SELECT * FROM target ORDER BY tid;
688  tid | balance 
689 -----+---------
690    1 |      10
691    2 |      25
692    3 |      50
693    4 |      40
694 (4 rows)
696 ROLLBACK;
697 -- unreachable WHEN clause should ERROR
698 BEGIN;
699 MERGE INTO target t
700 USING source AS s
701 ON t.tid = s.sid
702 WHEN MATCHED THEN /* Terminal WHEN clause for MATCHED */
703         DELETE
704 WHEN MATCHED THEN
705         UPDATE SET balance = t.balance - s.delta;
706 ERROR:  unreachable WHEN clause specified after unconditional WHEN clause
707 ROLLBACK;
708 -- conditional WHEN clause
709 CREATE TABLE wq_target (tid integer not null, balance integer DEFAULT -1)
710   WITH (autovacuum_enabled=off);
711 CREATE TABLE wq_source (balance integer, sid integer)
712   WITH (autovacuum_enabled=off);
713 INSERT INTO wq_source (sid, balance) VALUES (1, 100);
714 BEGIN;
715 -- try a simple INSERT with default values first
716 MERGE INTO wq_target t
717 USING wq_source s ON t.tid = s.sid
718 WHEN NOT MATCHED THEN
719         INSERT (tid) VALUES (s.sid);
720 SELECT * FROM wq_target;
721  tid | balance 
722 -----+---------
723    1 |      -1
724 (1 row)
726 ROLLBACK;
727 -- this time with a FALSE condition
728 MERGE INTO wq_target t
729 USING wq_source s ON t.tid = s.sid
730 WHEN NOT MATCHED AND FALSE THEN
731         INSERT (tid) VALUES (s.sid);
732 SELECT * FROM wq_target;
733  tid | balance 
734 -----+---------
735 (0 rows)
737 -- this time with an actual condition which returns false
738 MERGE INTO wq_target t
739 USING wq_source s ON t.tid = s.sid
740 WHEN NOT MATCHED AND s.balance <> 100 THEN
741         INSERT (tid) VALUES (s.sid);
742 SELECT * FROM wq_target;
743  tid | balance 
744 -----+---------
745 (0 rows)
747 BEGIN;
748 -- and now with a condition which returns true
749 MERGE INTO wq_target t
750 USING wq_source s ON t.tid = s.sid
751 WHEN NOT MATCHED AND s.balance = 100 THEN
752         INSERT (tid) VALUES (s.sid);
753 SELECT * FROM wq_target;
754  tid | balance 
755 -----+---------
756    1 |      -1
757 (1 row)
759 ROLLBACK;
760 -- conditions in the NOT MATCHED clause can only refer to source columns
761 BEGIN;
762 MERGE INTO wq_target t
763 USING wq_source s ON t.tid = s.sid
764 WHEN NOT MATCHED AND t.balance = 100 THEN
765         INSERT (tid) VALUES (s.sid);
766 ERROR:  invalid reference to FROM-clause entry for table "t"
767 LINE 3: WHEN NOT MATCHED AND t.balance = 100 THEN
768                              ^
769 DETAIL:  There is an entry for table "t", but it cannot be referenced from this part of the query.
770 SELECT * FROM wq_target;
771 ERROR:  current transaction is aborted, commands ignored until end of transaction block
772 ROLLBACK;
773 MERGE INTO wq_target t
774 USING wq_source s ON t.tid = s.sid
775 WHEN NOT MATCHED AND s.balance = 100 THEN
776         INSERT (tid) VALUES (s.sid);
777 SELECT * FROM wq_target;
778  tid | balance 
779 -----+---------
780    1 |      -1
781 (1 row)
783 -- conditions in NOT MATCHED BY SOURCE clause can only refer to target columns
784 MERGE INTO wq_target t
785 USING wq_source s ON t.tid = s.sid
786 WHEN NOT MATCHED BY SOURCE AND s.balance = 100 THEN
787         DELETE;
788 ERROR:  invalid reference to FROM-clause entry for table "s"
789 LINE 3: WHEN NOT MATCHED BY SOURCE AND s.balance = 100 THEN
790                                        ^
791 DETAIL:  There is an entry for table "s", but it cannot be referenced from this part of the query.
792 MERGE INTO wq_target t
793 USING wq_source s ON t.tid = s.sid
794 WHEN NOT MATCHED BY SOURCE AND t.balance = 100 THEN
795     DELETE;
796 -- conditions in MATCHED clause can refer to both source and target
797 SELECT * FROM wq_source;
798  balance | sid 
799 ---------+-----
800      100 |   1
801 (1 row)
803 MERGE INTO wq_target t
804 USING wq_source s ON t.tid = s.sid
805 WHEN MATCHED AND s.balance = 100 THEN
806         UPDATE SET balance = t.balance + s.balance;
807 SELECT * FROM wq_target;
808  tid | balance 
809 -----+---------
810    1 |      99
811 (1 row)
813 MERGE INTO wq_target t
814 USING wq_source s ON t.tid = s.sid
815 WHEN MATCHED AND t.balance = 100 THEN
816         UPDATE SET balance = t.balance + s.balance;
817 SELECT * FROM wq_target;
818  tid | balance 
819 -----+---------
820    1 |      99
821 (1 row)
823 -- check if AND works
824 MERGE INTO wq_target t
825 USING wq_source s ON t.tid = s.sid
826 WHEN MATCHED AND t.balance = 99 AND s.balance > 100 THEN
827         UPDATE SET balance = t.balance + s.balance;
828 SELECT * FROM wq_target;
829  tid | balance 
830 -----+---------
831    1 |      99
832 (1 row)
834 MERGE INTO wq_target t
835 USING wq_source s ON t.tid = s.sid
836 WHEN MATCHED AND t.balance = 99 AND s.balance = 100 THEN
837         UPDATE SET balance = t.balance + s.balance;
838 SELECT * FROM wq_target;
839  tid | balance 
840 -----+---------
841    1 |     199
842 (1 row)
844 -- check if OR works
845 MERGE INTO wq_target t
846 USING wq_source s ON t.tid = s.sid
847 WHEN MATCHED AND t.balance = 99 OR s.balance > 100 THEN
848         UPDATE SET balance = t.balance + s.balance;
849 SELECT * FROM wq_target;
850  tid | balance 
851 -----+---------
852    1 |     199
853 (1 row)
855 MERGE INTO wq_target t
856 USING wq_source s ON t.tid = s.sid
857 WHEN MATCHED AND t.balance = 199 OR s.balance > 100 THEN
858         UPDATE SET balance = t.balance + s.balance;
859 SELECT * FROM wq_target;
860  tid | balance 
861 -----+---------
862    1 |     299
863 (1 row)
865 -- check source-side whole-row references
866 BEGIN;
867 MERGE INTO wq_target t
868 USING wq_source s ON (t.tid = s.sid)
869 WHEN matched and t = s or t.tid = s.sid THEN
870         UPDATE SET balance = t.balance + s.balance;
871 SELECT * FROM wq_target;
872  tid | balance 
873 -----+---------
874    1 |     399
875 (1 row)
877 ROLLBACK;
878 -- check if subqueries work in the conditions?
879 MERGE INTO wq_target t
880 USING wq_source s ON t.tid = s.sid
881 WHEN MATCHED AND t.balance > (SELECT max(balance) FROM target) THEN
882         UPDATE SET balance = t.balance + s.balance;
883 -- check if we can access system columns in the conditions
884 MERGE INTO wq_target t
885 USING wq_source s ON t.tid = s.sid
886 WHEN MATCHED AND t.xmin = t.xmax THEN
887         UPDATE SET balance = t.balance + s.balance;
888 ERROR:  cannot use system column "xmin" in MERGE WHEN condition
889 LINE 3: WHEN MATCHED AND t.xmin = t.xmax THEN
890                          ^
891 MERGE INTO wq_target t
892 USING wq_source s ON t.tid = s.sid
893 WHEN MATCHED AND t.tableoid >= 0 THEN
894         UPDATE SET balance = t.balance + s.balance;
895 SELECT * FROM wq_target;
896  tid | balance 
897 -----+---------
898    1 |     499
899 (1 row)
901 DROP TABLE wq_target, wq_source;
902 -- test triggers
903 create or replace function merge_trigfunc () returns trigger
904 language plpgsql as
906 DECLARE
907         line text;
908 BEGIN
909         SELECT INTO line format('%s %s %s trigger%s',
910                 TG_WHEN, TG_OP, TG_LEVEL, CASE
911                 WHEN TG_OP = 'INSERT' AND TG_LEVEL = 'ROW'
912                         THEN format(' row: %s', NEW)
913                 WHEN TG_OP = 'UPDATE' AND TG_LEVEL = 'ROW'
914                         THEN format(' row: %s -> %s', OLD, NEW)
915                 WHEN TG_OP = 'DELETE' AND TG_LEVEL = 'ROW'
916                         THEN format(' row: %s', OLD)
917                 END);
919         RAISE NOTICE '%', line;
920         IF (TG_WHEN = 'BEFORE' AND TG_LEVEL = 'ROW') THEN
921                 IF (TG_OP = 'DELETE') THEN
922                         RETURN OLD;
923                 ELSE
924                         RETURN NEW;
925                 END IF;
926         ELSE
927                 RETURN NULL;
928         END IF;
929 END;
931 CREATE TRIGGER merge_bsi BEFORE INSERT ON target FOR EACH STATEMENT EXECUTE PROCEDURE merge_trigfunc ();
932 CREATE TRIGGER merge_bsu BEFORE UPDATE ON target FOR EACH STATEMENT EXECUTE PROCEDURE merge_trigfunc ();
933 CREATE TRIGGER merge_bsd BEFORE DELETE ON target FOR EACH STATEMENT EXECUTE PROCEDURE merge_trigfunc ();
934 CREATE TRIGGER merge_asi AFTER INSERT ON target FOR EACH STATEMENT EXECUTE PROCEDURE merge_trigfunc ();
935 CREATE TRIGGER merge_asu AFTER UPDATE ON target FOR EACH STATEMENT EXECUTE PROCEDURE merge_trigfunc ();
936 CREATE TRIGGER merge_asd AFTER DELETE ON target FOR EACH STATEMENT EXECUTE PROCEDURE merge_trigfunc ();
937 CREATE TRIGGER merge_bri BEFORE INSERT ON target FOR EACH ROW EXECUTE PROCEDURE merge_trigfunc ();
938 CREATE TRIGGER merge_bru BEFORE UPDATE ON target FOR EACH ROW EXECUTE PROCEDURE merge_trigfunc ();
939 CREATE TRIGGER merge_brd BEFORE DELETE ON target FOR EACH ROW EXECUTE PROCEDURE merge_trigfunc ();
940 CREATE TRIGGER merge_ari AFTER INSERT ON target FOR EACH ROW EXECUTE PROCEDURE merge_trigfunc ();
941 CREATE TRIGGER merge_aru AFTER UPDATE ON target FOR EACH ROW EXECUTE PROCEDURE merge_trigfunc ();
942 CREATE TRIGGER merge_ard AFTER DELETE ON target FOR EACH ROW EXECUTE PROCEDURE merge_trigfunc ();
943 -- now the classic UPSERT, with a DELETE
944 BEGIN;
945 UPDATE target SET balance = 0 WHERE tid = 3;
946 NOTICE:  BEFORE UPDATE STATEMENT trigger
947 NOTICE:  BEFORE UPDATE ROW trigger row: (3,30) -> (3,0)
948 NOTICE:  AFTER UPDATE ROW trigger row: (3,30) -> (3,0)
949 NOTICE:  AFTER UPDATE STATEMENT trigger
950 --EXPLAIN (ANALYZE ON, COSTS OFF, SUMMARY OFF, TIMING OFF)
951 MERGE INTO target t
952 USING source AS s
953 ON t.tid = s.sid
954 WHEN MATCHED AND t.balance > s.delta THEN
955         UPDATE SET balance = t.balance - s.delta
956 WHEN MATCHED THEN
957         DELETE
958 WHEN NOT MATCHED THEN
959         INSERT VALUES (s.sid, s.delta);
960 NOTICE:  BEFORE INSERT STATEMENT trigger
961 NOTICE:  BEFORE UPDATE STATEMENT trigger
962 NOTICE:  BEFORE DELETE STATEMENT trigger
963 NOTICE:  BEFORE DELETE ROW trigger row: (3,0)
964 NOTICE:  BEFORE UPDATE ROW trigger row: (2,20) -> (2,15)
965 NOTICE:  BEFORE INSERT ROW trigger row: (4,40)
966 NOTICE:  AFTER DELETE ROW trigger row: (3,0)
967 NOTICE:  AFTER UPDATE ROW trigger row: (2,20) -> (2,15)
968 NOTICE:  AFTER INSERT ROW trigger row: (4,40)
969 NOTICE:  AFTER DELETE STATEMENT trigger
970 NOTICE:  AFTER UPDATE STATEMENT trigger
971 NOTICE:  AFTER INSERT STATEMENT trigger
972 SELECT * FROM target ORDER BY tid;
973  tid | balance 
974 -----+---------
975    1 |      10
976    2 |      15
977    4 |      40
978 (3 rows)
980 ROLLBACK;
981 -- UPSERT with UPDATE/DELETE when not matched by source
982 BEGIN;
983 DELETE FROM SOURCE WHERE sid = 2;
984 MERGE INTO target t
985 USING source AS s
986 ON t.tid = s.sid
987 WHEN MATCHED AND t.balance > s.delta THEN
988     UPDATE SET balance = t.balance - s.delta
989 WHEN MATCHED THEN
990         UPDATE SET balance = 0
991 WHEN NOT MATCHED THEN
992     INSERT VALUES (s.sid, s.delta)
993 WHEN NOT MATCHED BY SOURCE AND tid = 1 THEN
994         UPDATE SET balance = 0
995 WHEN NOT MATCHED BY SOURCE THEN
996         DELETE
997 RETURNING merge_action(), t.*;
998 NOTICE:  BEFORE INSERT STATEMENT trigger
999 NOTICE:  BEFORE UPDATE STATEMENT trigger
1000 NOTICE:  BEFORE DELETE STATEMENT trigger
1001 NOTICE:  BEFORE UPDATE ROW trigger row: (3,30) -> (3,10)
1002 NOTICE:  BEFORE INSERT ROW trigger row: (4,40)
1003 NOTICE:  BEFORE DELETE ROW trigger row: (2,20)
1004 NOTICE:  BEFORE UPDATE ROW trigger row: (1,10) -> (1,0)
1005 NOTICE:  AFTER UPDATE ROW trigger row: (3,30) -> (3,10)
1006 NOTICE:  AFTER INSERT ROW trigger row: (4,40)
1007 NOTICE:  AFTER DELETE ROW trigger row: (2,20)
1008 NOTICE:  AFTER UPDATE ROW trigger row: (1,10) -> (1,0)
1009 NOTICE:  AFTER DELETE STATEMENT trigger
1010 NOTICE:  AFTER UPDATE STATEMENT trigger
1011 NOTICE:  AFTER INSERT STATEMENT trigger
1012  merge_action | tid | balance 
1013 --------------+-----+---------
1014  UPDATE       |   3 |      10
1015  INSERT       |   4 |      40
1016  DELETE       |   2 |      20
1017  UPDATE       |   1 |       0
1018 (4 rows)
1020 SELECT * FROM target ORDER BY tid;
1021  tid | balance 
1022 -----+---------
1023    1 |       0
1024    3 |      10
1025    4 |      40
1026 (3 rows)
1028 ROLLBACK;
1029 -- Test behavior of triggers that turn UPDATE/DELETE into no-ops
1030 create or replace function skip_merge_op() returns trigger
1031 language plpgsql as
1033 BEGIN
1034         RETURN NULL;
1035 END;
1037 SELECT * FROM target full outer join source on (sid = tid);
1038  tid | balance | sid | delta 
1039 -----+---------+-----+-------
1040    3 |      30 |   3 |    20
1041    2 |      20 |   2 |     5
1042      |         |   4 |    40
1043    1 |      10 |     |      
1044 (4 rows)
1046 create trigger merge_skip BEFORE INSERT OR UPDATE or DELETE
1047   ON target FOR EACH ROW EXECUTE FUNCTION skip_merge_op();
1048 DO $$
1049 DECLARE
1050   result integer;
1051 BEGIN
1052 MERGE INTO target t
1053 USING source AS s
1054 ON t.tid = s.sid
1055 WHEN MATCHED AND s.sid = 3 THEN UPDATE SET balance = t.balance + s.delta
1056 WHEN MATCHED THEN DELETE
1057 WHEN NOT MATCHED THEN INSERT VALUES (sid, delta);
1058 IF FOUND THEN
1059   RAISE NOTICE 'Found';
1060 ELSE
1061   RAISE NOTICE 'Not found';
1062 END IF;
1063 GET DIAGNOSTICS result := ROW_COUNT;
1064 RAISE NOTICE 'ROW_COUNT = %', result;
1065 END;
1067 NOTICE:  BEFORE INSERT STATEMENT trigger
1068 NOTICE:  BEFORE UPDATE STATEMENT trigger
1069 NOTICE:  BEFORE DELETE STATEMENT trigger
1070 NOTICE:  BEFORE UPDATE ROW trigger row: (3,30) -> (3,50)
1071 NOTICE:  BEFORE DELETE ROW trigger row: (2,20)
1072 NOTICE:  BEFORE INSERT ROW trigger row: (4,40)
1073 NOTICE:  AFTER DELETE STATEMENT trigger
1074 NOTICE:  AFTER UPDATE STATEMENT trigger
1075 NOTICE:  AFTER INSERT STATEMENT trigger
1076 NOTICE:  Not found
1077 NOTICE:  ROW_COUNT = 0
1078 SELECT * FROM target FULL OUTER JOIN source ON (sid = tid);
1079  tid | balance | sid | delta 
1080 -----+---------+-----+-------
1081    3 |      30 |   3 |    20
1082    2 |      20 |   2 |     5
1083      |         |   4 |    40
1084    1 |      10 |     |      
1085 (4 rows)
1087 DROP TRIGGER merge_skip ON target;
1088 DROP FUNCTION skip_merge_op();
1089 -- test from PL/pgSQL
1090 -- make sure MERGE INTO isn't interpreted to mean returning variables like SELECT INTO
1091 BEGIN;
1092 DO LANGUAGE plpgsql $$
1093 BEGIN
1094 MERGE INTO target t
1095 USING source AS s
1096 ON t.tid = s.sid
1097 WHEN MATCHED AND t.balance > s.delta THEN
1098         UPDATE SET balance = t.balance - s.delta;
1099 END;
1101 NOTICE:  BEFORE UPDATE STATEMENT trigger
1102 NOTICE:  BEFORE UPDATE ROW trigger row: (3,30) -> (3,10)
1103 NOTICE:  BEFORE UPDATE ROW trigger row: (2,20) -> (2,15)
1104 NOTICE:  AFTER UPDATE ROW trigger row: (3,30) -> (3,10)
1105 NOTICE:  AFTER UPDATE ROW trigger row: (2,20) -> (2,15)
1106 NOTICE:  AFTER UPDATE STATEMENT trigger
1107 ROLLBACK;
1108 --source constants
1109 BEGIN;
1110 MERGE INTO target t
1111 USING (SELECT 9 AS sid, 57 AS delta) AS s
1112 ON t.tid = s.sid
1113 WHEN NOT MATCHED THEN
1114         INSERT (tid, balance) VALUES (s.sid, s.delta);
1115 NOTICE:  BEFORE INSERT STATEMENT trigger
1116 NOTICE:  BEFORE INSERT ROW trigger row: (9,57)
1117 NOTICE:  AFTER INSERT ROW trigger row: (9,57)
1118 NOTICE:  AFTER INSERT STATEMENT trigger
1119 SELECT * FROM target ORDER BY tid;
1120  tid | balance 
1121 -----+---------
1122    1 |      10
1123    2 |      20
1124    3 |      30
1125    9 |      57
1126 (4 rows)
1128 ROLLBACK;
1129 --source query
1130 BEGIN;
1131 MERGE INTO target t
1132 USING (SELECT sid, delta FROM source WHERE delta > 0) AS s
1133 ON t.tid = s.sid
1134 WHEN NOT MATCHED THEN
1135         INSERT (tid, balance) VALUES (s.sid, s.delta);
1136 NOTICE:  BEFORE INSERT STATEMENT trigger
1137 NOTICE:  BEFORE INSERT ROW trigger row: (4,40)
1138 NOTICE:  AFTER INSERT ROW trigger row: (4,40)
1139 NOTICE:  AFTER INSERT STATEMENT trigger
1140 SELECT * FROM target ORDER BY tid;
1141  tid | balance 
1142 -----+---------
1143    1 |      10
1144    2 |      20
1145    3 |      30
1146    4 |      40
1147 (4 rows)
1149 ROLLBACK;
1150 BEGIN;
1151 MERGE INTO target t
1152 USING (SELECT sid, delta as newname FROM source WHERE delta > 0) AS s
1153 ON t.tid = s.sid
1154 WHEN NOT MATCHED THEN
1155         INSERT (tid, balance) VALUES (s.sid, s.newname);
1156 NOTICE:  BEFORE INSERT STATEMENT trigger
1157 NOTICE:  BEFORE INSERT ROW trigger row: (4,40)
1158 NOTICE:  AFTER INSERT ROW trigger row: (4,40)
1159 NOTICE:  AFTER INSERT STATEMENT trigger
1160 SELECT * FROM target ORDER BY tid;
1161  tid | balance 
1162 -----+---------
1163    1 |      10
1164    2 |      20
1165    3 |      30
1166    4 |      40
1167 (4 rows)
1169 ROLLBACK;
1170 --self-merge
1171 BEGIN;
1172 MERGE INTO target t1
1173 USING target t2
1174 ON t1.tid = t2.tid
1175 WHEN MATCHED THEN
1176         UPDATE SET balance = t1.balance + t2.balance
1177 WHEN NOT MATCHED THEN
1178         INSERT VALUES (t2.tid, t2.balance);
1179 NOTICE:  BEFORE INSERT STATEMENT trigger
1180 NOTICE:  BEFORE UPDATE STATEMENT trigger
1181 NOTICE:  BEFORE UPDATE ROW trigger row: (1,10) -> (1,20)
1182 NOTICE:  BEFORE UPDATE ROW trigger row: (2,20) -> (2,40)
1183 NOTICE:  BEFORE UPDATE ROW trigger row: (3,30) -> (3,60)
1184 NOTICE:  AFTER UPDATE ROW trigger row: (1,10) -> (1,20)
1185 NOTICE:  AFTER UPDATE ROW trigger row: (2,20) -> (2,40)
1186 NOTICE:  AFTER UPDATE ROW trigger row: (3,30) -> (3,60)
1187 NOTICE:  AFTER UPDATE STATEMENT trigger
1188 NOTICE:  AFTER INSERT STATEMENT trigger
1189 SELECT * FROM target ORDER BY tid;
1190  tid | balance 
1191 -----+---------
1192    1 |      20
1193    2 |      40
1194    3 |      60
1195 (3 rows)
1197 ROLLBACK;
1198 BEGIN;
1199 MERGE INTO target t
1200 USING (SELECT tid as sid, balance as delta FROM target WHERE balance > 0) AS s
1201 ON t.tid = s.sid
1202 WHEN NOT MATCHED THEN
1203         INSERT (tid, balance) VALUES (s.sid, s.delta);
1204 NOTICE:  BEFORE INSERT STATEMENT trigger
1205 NOTICE:  AFTER INSERT STATEMENT trigger
1206 SELECT * FROM target ORDER BY tid;
1207  tid | balance 
1208 -----+---------
1209    1 |      10
1210    2 |      20
1211    3 |      30
1212 (3 rows)
1214 ROLLBACK;
1215 BEGIN;
1216 MERGE INTO target t
1217 USING
1218 (SELECT sid, max(delta) AS delta
1219  FROM source
1220  GROUP BY sid
1221  HAVING count(*) = 1
1222  ORDER BY sid ASC) AS s
1223 ON t.tid = s.sid
1224 WHEN NOT MATCHED THEN
1225         INSERT (tid, balance) VALUES (s.sid, s.delta);
1226 NOTICE:  BEFORE INSERT STATEMENT trigger
1227 NOTICE:  BEFORE INSERT ROW trigger row: (4,40)
1228 NOTICE:  AFTER INSERT ROW trigger row: (4,40)
1229 NOTICE:  AFTER INSERT STATEMENT trigger
1230 SELECT * FROM target ORDER BY tid;
1231  tid | balance 
1232 -----+---------
1233    1 |      10
1234    2 |      20
1235    3 |      30
1236    4 |      40
1237 (4 rows)
1239 ROLLBACK;
1240 -- plpgsql parameters and results
1241 BEGIN;
1242 CREATE FUNCTION merge_func (p_id integer, p_bal integer)
1243 RETURNS INTEGER
1244 LANGUAGE plpgsql
1245 AS $$
1246 DECLARE
1247  result integer;
1248 BEGIN
1249 MERGE INTO target t
1250 USING (SELECT p_id AS sid) AS s
1251 ON t.tid = s.sid
1252 WHEN MATCHED THEN
1253         UPDATE SET balance = t.balance - p_bal;
1254 IF FOUND THEN
1255         GET DIAGNOSTICS result := ROW_COUNT;
1256 END IF;
1257 RETURN result;
1258 END;
1260 SELECT merge_func(3, 4);
1261 NOTICE:  BEFORE UPDATE STATEMENT trigger
1262 NOTICE:  BEFORE UPDATE ROW trigger row: (3,30) -> (3,26)
1263 NOTICE:  AFTER UPDATE ROW trigger row: (3,30) -> (3,26)
1264 NOTICE:  AFTER UPDATE STATEMENT trigger
1265  merge_func 
1266 ------------
1267           1
1268 (1 row)
1270 SELECT * FROM target ORDER BY tid;
1271  tid | balance 
1272 -----+---------
1273    1 |      10
1274    2 |      20
1275    3 |      26
1276 (3 rows)
1278 ROLLBACK;
1279 -- PREPARE
1280 BEGIN;
1281 prepare foom as merge into target t using (select 1 as sid) s on (t.tid = s.sid) when matched then update set balance = 1;
1282 execute foom;
1283 NOTICE:  BEFORE UPDATE STATEMENT trigger
1284 NOTICE:  BEFORE UPDATE ROW trigger row: (1,10) -> (1,1)
1285 NOTICE:  AFTER UPDATE ROW trigger row: (1,10) -> (1,1)
1286 NOTICE:  AFTER UPDATE STATEMENT trigger
1287 SELECT * FROM target ORDER BY tid;
1288  tid | balance 
1289 -----+---------
1290    1 |       1
1291    2 |      20
1292    3 |      30
1293 (3 rows)
1295 ROLLBACK;
1296 BEGIN;
1297 PREPARE foom2 (integer, integer) AS
1298 MERGE INTO target t
1299 USING (SELECT 1) s
1300 ON t.tid = $1
1301 WHEN MATCHED THEN
1302 UPDATE SET balance = $2;
1303 --EXPLAIN (ANALYZE ON, COSTS OFF, SUMMARY OFF, TIMING OFF)
1304 execute foom2 (1, 1);
1305 NOTICE:  BEFORE UPDATE STATEMENT trigger
1306 NOTICE:  BEFORE UPDATE ROW trigger row: (1,10) -> (1,1)
1307 NOTICE:  AFTER UPDATE ROW trigger row: (1,10) -> (1,1)
1308 NOTICE:  AFTER UPDATE STATEMENT trigger
1309 SELECT * FROM target ORDER BY tid;
1310  tid | balance 
1311 -----+---------
1312    1 |       1
1313    2 |      20
1314    3 |      30
1315 (3 rows)
1317 ROLLBACK;
1318 -- subqueries in source relation
1319 CREATE TABLE sq_target (tid integer NOT NULL, balance integer)
1320   WITH (autovacuum_enabled=off);
1321 CREATE TABLE sq_source (delta integer, sid integer, balance integer DEFAULT 0)
1322   WITH (autovacuum_enabled=off);
1323 INSERT INTO sq_target(tid, balance) VALUES (1,100), (2,200), (3,300);
1324 INSERT INTO sq_source(sid, delta) VALUES (1,10), (2,20), (4,40);
1325 BEGIN;
1326 MERGE INTO sq_target t
1327 USING (SELECT * FROM sq_source) s
1328 ON tid = sid
1329 WHEN MATCHED AND t.balance > delta THEN
1330         UPDATE SET balance = t.balance + delta;
1331 SELECT * FROM sq_target;
1332  tid | balance 
1333 -----+---------
1334    3 |     300
1335    1 |     110
1336    2 |     220
1337 (3 rows)
1339 ROLLBACK;
1340 -- try a view
1341 CREATE VIEW v AS SELECT * FROM sq_source WHERE sid < 2;
1342 BEGIN;
1343 MERGE INTO sq_target
1344 USING v
1345 ON tid = sid
1346 WHEN MATCHED THEN
1347     UPDATE SET balance = v.balance + delta;
1348 SELECT * FROM sq_target;
1349  tid | balance 
1350 -----+---------
1351    2 |     200
1352    3 |     300
1353    1 |      10
1354 (3 rows)
1356 ROLLBACK;
1357 -- ambiguous reference to a column
1358 BEGIN;
1359 MERGE INTO sq_target
1360 USING v
1361 ON tid = sid
1362 WHEN MATCHED AND tid >= 2 THEN
1363     UPDATE SET balance = balance + delta
1364 WHEN NOT MATCHED THEN
1365         INSERT (balance, tid) VALUES (balance + delta, sid)
1366 WHEN MATCHED AND tid < 2 THEN
1367         DELETE;
1368 ERROR:  column reference "balance" is ambiguous
1369 LINE 5:     UPDATE SET balance = balance + delta
1370                                  ^
1371 ROLLBACK;
1372 BEGIN;
1373 INSERT INTO sq_source (sid, balance, delta) VALUES (-1, -1, -10);
1374 MERGE INTO sq_target t
1375 USING v
1376 ON tid = sid
1377 WHEN MATCHED AND tid >= 2 THEN
1378     UPDATE SET balance = t.balance + delta
1379 WHEN NOT MATCHED THEN
1380         INSERT (balance, tid) VALUES (balance + delta, sid)
1381 WHEN MATCHED AND tid < 2 THEN
1382         DELETE;
1383 SELECT * FROM sq_target;
1384  tid | balance 
1385 -----+---------
1386    2 |     200
1387    3 |     300
1388   -1 |     -11
1389 (3 rows)
1391 ROLLBACK;
1392 -- CTEs
1393 BEGIN;
1394 INSERT INTO sq_source (sid, balance, delta) VALUES (-1, -1, -10);
1395 WITH targq AS (
1396         SELECT * FROM v
1398 MERGE INTO sq_target t
1399 USING v
1400 ON tid = sid
1401 WHEN MATCHED AND tid >= 2 THEN
1402     UPDATE SET balance = t.balance + delta
1403 WHEN NOT MATCHED THEN
1404         INSERT (balance, tid) VALUES (balance + delta, sid)
1405 WHEN MATCHED AND tid < 2 THEN
1406         DELETE;
1407 ROLLBACK;
1408 -- RETURNING
1409 SELECT * FROM sq_source ORDER BY sid;
1410  delta | sid | balance 
1411 -------+-----+---------
1412     10 |   1 |       0
1413     20 |   2 |       0
1414     40 |   4 |       0
1415 (3 rows)
1417 SELECT * FROM sq_target ORDER BY tid;
1418  tid | balance 
1419 -----+---------
1420    1 |     100
1421    2 |     200
1422    3 |     300
1423 (3 rows)
1425 BEGIN;
1426 CREATE TABLE merge_actions(action text, abbrev text);
1427 INSERT INTO merge_actions VALUES ('INSERT', 'ins'), ('UPDATE', 'upd'), ('DELETE', 'del');
1428 MERGE INTO sq_target t
1429 USING sq_source s
1430 ON tid = sid
1431 WHEN MATCHED AND tid >= 2 THEN
1432     UPDATE SET balance = t.balance + delta
1433 WHEN NOT MATCHED THEN
1434     INSERT (balance, tid) VALUES (balance + delta, sid)
1435 WHEN MATCHED AND tid < 2 THEN
1436     DELETE
1437 RETURNING (SELECT abbrev FROM merge_actions
1438             WHERE action = merge_action()) AS action,
1439           t.*,
1440           CASE merge_action()
1441               WHEN 'INSERT' THEN 'Inserted '||t
1442               WHEN 'UPDATE' THEN 'Added '||delta||' to balance'
1443               WHEN 'DELETE' THEN 'Removed '||t
1444           END AS description;
1445  action | tid | balance |     description     
1446 --------+-----+---------+---------------------
1447  del    |   1 |     100 | Removed (1,100)
1448  upd    |   2 |     220 | Added 20 to balance
1449  ins    |   4 |      40 | Inserted (4,40)
1450 (3 rows)
1452 ROLLBACK;
1453 -- error when using merge_action() outside MERGE
1454 SELECT merge_action() FROM sq_target;
1455 ERROR:  MERGE_ACTION() can only be used in the RETURNING list of a MERGE command
1456 LINE 1: SELECT merge_action() FROM sq_target;
1457                ^
1458 UPDATE sq_target SET balance = balance + 1 RETURNING merge_action();
1459 ERROR:  MERGE_ACTION() can only be used in the RETURNING list of a MERGE command
1460 LINE 1: ...ATE sq_target SET balance = balance + 1 RETURNING merge_acti...
1461                                                              ^
1462 -- RETURNING in CTEs
1463 CREATE TABLE sq_target_merge_log (tid integer NOT NULL, last_change text);
1464 INSERT INTO sq_target_merge_log VALUES (1, 'Original value');
1465 BEGIN;
1466 WITH m AS (
1467     MERGE INTO sq_target t
1468     USING sq_source s
1469     ON tid = sid
1470     WHEN MATCHED AND tid >= 2 THEN
1471         UPDATE SET balance = t.balance + delta
1472     WHEN NOT MATCHED THEN
1473         INSERT (balance, tid) VALUES (balance + delta, sid)
1474     WHEN MATCHED AND tid < 2 THEN
1475         DELETE
1476     RETURNING merge_action() AS action, t.*,
1477               CASE merge_action()
1478                   WHEN 'INSERT' THEN 'Inserted '||t
1479                   WHEN 'UPDATE' THEN 'Added '||delta||' to balance'
1480                   WHEN 'DELETE' THEN 'Removed '||t
1481               END AS description
1482 ), m2 AS (
1483     MERGE INTO sq_target_merge_log l
1484     USING m
1485     ON l.tid = m.tid
1486     WHEN MATCHED THEN
1487         UPDATE SET last_change = description
1488     WHEN NOT MATCHED THEN
1489         INSERT VALUES (m.tid, description)
1490     RETURNING action, merge_action() AS log_action, l.*
1492 SELECT * FROM m2;
1493  action | log_action | tid |     last_change     
1494 --------+------------+-----+---------------------
1495  DELETE | UPDATE     |   1 | Removed (1,100)
1496  UPDATE | INSERT     |   2 | Added 20 to balance
1497  INSERT | INSERT     |   4 | Inserted (4,40)
1498 (3 rows)
1500 SELECT * FROM sq_target_merge_log ORDER BY tid;
1501  tid |     last_change     
1502 -----+---------------------
1503    1 | Removed (1,100)
1504    2 | Added 20 to balance
1505    4 | Inserted (4,40)
1506 (3 rows)
1508 ROLLBACK;
1509 -- COPY (MERGE ... RETURNING) TO ...
1510 BEGIN;
1511 COPY (
1512     MERGE INTO sq_target t
1513     USING sq_source s
1514     ON tid = sid
1515     WHEN MATCHED AND tid >= 2 THEN
1516         UPDATE SET balance = t.balance + delta
1517     WHEN NOT MATCHED THEN
1518         INSERT (balance, tid) VALUES (balance + delta, sid)
1519     WHEN MATCHED AND tid < 2 THEN
1520         DELETE
1521     RETURNING merge_action(), t.*
1522 ) TO stdout;
1523 DELETE  1       100
1524 UPDATE  2       220
1525 INSERT  4       40
1526 ROLLBACK;
1527 -- SQL function with MERGE ... RETURNING
1528 BEGIN;
1529 CREATE FUNCTION merge_into_sq_target(sid int, balance int, delta int,
1530                                      OUT action text, OUT tid int, OUT new_balance int)
1531 LANGUAGE sql AS
1533     MERGE INTO sq_target t
1534     USING (VALUES ($1, $2, $3)) AS v(sid, balance, delta)
1535     ON tid = v.sid
1536     WHEN MATCHED AND tid >= 2 THEN
1537         UPDATE SET balance = t.balance + v.delta
1538     WHEN NOT MATCHED THEN
1539         INSERT (balance, tid) VALUES (v.balance + v.delta, v.sid)
1540     WHEN MATCHED AND tid < 2 THEN
1541         DELETE
1542     RETURNING merge_action(), t.*;
1544 SELECT m.*
1545 FROM (VALUES (1, 0, 0), (3, 0, 20), (4, 100, 10)) AS v(sid, balance, delta),
1546 LATERAL (SELECT action, tid, new_balance FROM merge_into_sq_target(sid, balance, delta)) m;
1547  action | tid | new_balance 
1548 --------+-----+-------------
1549  DELETE |   1 |         100
1550  UPDATE |   3 |         320
1551  INSERT |   4 |         110
1552 (3 rows)
1554 ROLLBACK;
1555 -- SQL SRF with MERGE ... RETURNING
1556 BEGIN;
1557 CREATE FUNCTION merge_sq_source_into_sq_target()
1558 RETURNS TABLE (action text, tid int, balance int)
1559 LANGUAGE sql AS
1561     MERGE INTO sq_target t
1562     USING sq_source s
1563     ON tid = sid
1564     WHEN MATCHED AND tid >= 2 THEN
1565         UPDATE SET balance = t.balance + delta
1566     WHEN NOT MATCHED THEN
1567         INSERT (balance, tid) VALUES (balance + delta, sid)
1568     WHEN MATCHED AND tid < 2 THEN
1569         DELETE
1570     RETURNING merge_action(), t.*;
1572 SELECT * FROM merge_sq_source_into_sq_target();
1573  action | tid | balance 
1574 --------+-----+---------
1575  DELETE |   1 |     100
1576  UPDATE |   2 |     220
1577  INSERT |   4 |      40
1578 (3 rows)
1580 ROLLBACK;
1581 -- PL/pgSQL function with MERGE ... RETURNING ... INTO
1582 BEGIN;
1583 CREATE FUNCTION merge_into_sq_target(sid int, balance int, delta int,
1584                                      OUT r_action text, OUT r_tid int, OUT r_balance int)
1585 LANGUAGE plpgsql AS
1587 BEGIN
1588     MERGE INTO sq_target t
1589     USING (VALUES ($1, $2, $3)) AS v(sid, balance, delta)
1590     ON tid = v.sid
1591     WHEN MATCHED AND tid >= 2 THEN
1592         UPDATE SET balance = t.balance + v.delta
1593     WHEN NOT MATCHED THEN
1594         INSERT (balance, tid) VALUES (v.balance + v.delta, v.sid)
1595     WHEN MATCHED AND tid < 2 THEN
1596         DELETE
1597     RETURNING merge_action(), t.* INTO r_action, r_tid, r_balance;
1598 END;
1600 SELECT m.*
1601 FROM (VALUES (1, 0, 0), (3, 0, 20), (4, 100, 10)) AS v(sid, balance, delta),
1602 LATERAL (SELECT r_action, r_tid, r_balance FROM merge_into_sq_target(sid, balance, delta)) m;
1603  r_action | r_tid | r_balance 
1604 ----------+-------+-----------
1605  DELETE   |     1 |       100
1606  UPDATE   |     3 |       320
1607  INSERT   |     4 |       110
1608 (3 rows)
1610 ROLLBACK;
1611 -- EXPLAIN
1612 CREATE TABLE ex_mtarget (a int, b int)
1613   WITH (autovacuum_enabled=off);
1614 CREATE TABLE ex_msource (a int, b int)
1615   WITH (autovacuum_enabled=off);
1616 INSERT INTO ex_mtarget SELECT i, i*10 FROM generate_series(1,100,2) i;
1617 INSERT INTO ex_msource SELECT i, i*10 FROM generate_series(1,100,1) i;
1618 CREATE FUNCTION explain_merge(query text) RETURNS SETOF text
1619 LANGUAGE plpgsql AS
1621 DECLARE ln text;
1622 BEGIN
1623     FOR ln IN
1624         EXECUTE 'explain (analyze, timing off, summary off, costs off, buffers off) ' ||
1625                   query
1626     LOOP
1627         ln := regexp_replace(ln, '(Memory( Usage)?|Buckets|Batches): \S*',  '\1: xxx', 'g');
1628         RETURN NEXT ln;
1629     END LOOP;
1630 END;
1632 -- only updates
1633 SELECT explain_merge('
1634 MERGE INTO ex_mtarget t USING ex_msource s ON t.a = s.a
1635 WHEN MATCHED THEN
1636         UPDATE SET b = t.b + 1');
1637                             explain_merge                             
1638 ----------------------------------------------------------------------
1639  Merge on ex_mtarget t (actual rows=0 loops=1)
1640    Tuples: updated=50
1641    ->  Merge Join (actual rows=50 loops=1)
1642          Merge Cond: (t.a = s.a)
1643          ->  Sort (actual rows=50 loops=1)
1644                Sort Key: t.a
1645                Sort Method: quicksort  Memory: xxx
1646                ->  Seq Scan on ex_mtarget t (actual rows=50 loops=1)
1647          ->  Sort (actual rows=100 loops=1)
1648                Sort Key: s.a
1649                Sort Method: quicksort  Memory: xxx
1650                ->  Seq Scan on ex_msource s (actual rows=100 loops=1)
1651 (12 rows)
1653 -- only updates to selected tuples
1654 SELECT explain_merge('
1655 MERGE INTO ex_mtarget t USING ex_msource s ON t.a = s.a
1656 WHEN MATCHED AND t.a < 10 THEN
1657         UPDATE SET b = t.b + 1');
1658                             explain_merge                             
1659 ----------------------------------------------------------------------
1660  Merge on ex_mtarget t (actual rows=0 loops=1)
1661    Tuples: updated=5 skipped=45
1662    ->  Merge Join (actual rows=50 loops=1)
1663          Merge Cond: (t.a = s.a)
1664          ->  Sort (actual rows=50 loops=1)
1665                Sort Key: t.a
1666                Sort Method: quicksort  Memory: xxx
1667                ->  Seq Scan on ex_mtarget t (actual rows=50 loops=1)
1668          ->  Sort (actual rows=100 loops=1)
1669                Sort Key: s.a
1670                Sort Method: quicksort  Memory: xxx
1671                ->  Seq Scan on ex_msource s (actual rows=100 loops=1)
1672 (12 rows)
1674 -- updates + deletes
1675 SELECT explain_merge('
1676 MERGE INTO ex_mtarget t USING ex_msource s ON t.a = s.a
1677 WHEN MATCHED AND t.a < 10 THEN
1678         UPDATE SET b = t.b + 1
1679 WHEN MATCHED AND t.a >= 10 AND t.a <= 20 THEN
1680         DELETE');
1681                             explain_merge                             
1682 ----------------------------------------------------------------------
1683  Merge on ex_mtarget t (actual rows=0 loops=1)
1684    Tuples: updated=5 deleted=5 skipped=40
1685    ->  Merge Join (actual rows=50 loops=1)
1686          Merge Cond: (t.a = s.a)
1687          ->  Sort (actual rows=50 loops=1)
1688                Sort Key: t.a
1689                Sort Method: quicksort  Memory: xxx
1690                ->  Seq Scan on ex_mtarget t (actual rows=50 loops=1)
1691          ->  Sort (actual rows=100 loops=1)
1692                Sort Key: s.a
1693                Sort Method: quicksort  Memory: xxx
1694                ->  Seq Scan on ex_msource s (actual rows=100 loops=1)
1695 (12 rows)
1697 -- only inserts
1698 SELECT explain_merge('
1699 MERGE INTO ex_mtarget t USING ex_msource s ON t.a = s.a
1700 WHEN NOT MATCHED AND s.a < 10 THEN
1701         INSERT VALUES (a, b)');
1702                             explain_merge                             
1703 ----------------------------------------------------------------------
1704  Merge on ex_mtarget t (actual rows=0 loops=1)
1705    Tuples: inserted=4 skipped=96
1706    ->  Merge Left Join (actual rows=100 loops=1)
1707          Merge Cond: (s.a = t.a)
1708          ->  Sort (actual rows=100 loops=1)
1709                Sort Key: s.a
1710                Sort Method: quicksort  Memory: xxx
1711                ->  Seq Scan on ex_msource s (actual rows=100 loops=1)
1712          ->  Sort (actual rows=45 loops=1)
1713                Sort Key: t.a
1714                Sort Method: quicksort  Memory: xxx
1715                ->  Seq Scan on ex_mtarget t (actual rows=45 loops=1)
1716 (12 rows)
1718 -- all three
1719 SELECT explain_merge('
1720 MERGE INTO ex_mtarget t USING ex_msource s ON t.a = s.a
1721 WHEN MATCHED AND t.a < 10 THEN
1722         UPDATE SET b = t.b + 1
1723 WHEN MATCHED AND t.a >= 30 AND t.a <= 40 THEN
1724         DELETE
1725 WHEN NOT MATCHED AND s.a < 20 THEN
1726         INSERT VALUES (a, b)');
1727                             explain_merge                             
1728 ----------------------------------------------------------------------
1729  Merge on ex_mtarget t (actual rows=0 loops=1)
1730    Tuples: inserted=10 updated=9 deleted=5 skipped=76
1731    ->  Merge Left Join (actual rows=100 loops=1)
1732          Merge Cond: (s.a = t.a)
1733          ->  Sort (actual rows=100 loops=1)
1734                Sort Key: s.a
1735                Sort Method: quicksort  Memory: xxx
1736                ->  Seq Scan on ex_msource s (actual rows=100 loops=1)
1737          ->  Sort (actual rows=49 loops=1)
1738                Sort Key: t.a
1739                Sort Method: quicksort  Memory: xxx
1740                ->  Seq Scan on ex_mtarget t (actual rows=49 loops=1)
1741 (12 rows)
1743 -- not matched by source
1744 SELECT explain_merge('
1745 MERGE INTO ex_mtarget t USING ex_msource s ON t.a = s.a
1746 WHEN NOT MATCHED BY SOURCE and t.a < 10 THEN
1747         DELETE');
1748                             explain_merge                             
1749 ----------------------------------------------------------------------
1750  Merge on ex_mtarget t (actual rows=0 loops=1)
1751    Tuples: skipped=54
1752    ->  Merge Left Join (actual rows=54 loops=1)
1753          Merge Cond: (t.a = s.a)
1754          ->  Sort (actual rows=54 loops=1)
1755                Sort Key: t.a
1756                Sort Method: quicksort  Memory: xxx
1757                ->  Seq Scan on ex_mtarget t (actual rows=54 loops=1)
1758          ->  Sort (actual rows=100 loops=1)
1759                Sort Key: s.a
1760                Sort Method: quicksort  Memory: xxx
1761                ->  Seq Scan on ex_msource s (actual rows=100 loops=1)
1762 (12 rows)
1764 -- not matched by source and target
1765 SELECT explain_merge('
1766 MERGE INTO ex_mtarget t USING ex_msource s ON t.a = s.a
1767 WHEN NOT MATCHED BY SOURCE AND t.a < 10 THEN
1768         DELETE
1769 WHEN NOT MATCHED BY TARGET AND s.a < 20 THEN
1770         INSERT VALUES (a, b)');
1771                             explain_merge                             
1772 ----------------------------------------------------------------------
1773  Merge on ex_mtarget t (actual rows=0 loops=1)
1774    Tuples: skipped=100
1775    ->  Merge Full Join (actual rows=100 loops=1)
1776          Merge Cond: (t.a = s.a)
1777          ->  Sort (actual rows=54 loops=1)
1778                Sort Key: t.a
1779                Sort Method: quicksort  Memory: xxx
1780                ->  Seq Scan on ex_mtarget t (actual rows=54 loops=1)
1781          ->  Sort (actual rows=100 loops=1)
1782                Sort Key: s.a
1783                Sort Method: quicksort  Memory: xxx
1784                ->  Seq Scan on ex_msource s (actual rows=100 loops=1)
1785 (12 rows)
1787 -- nothing
1788 SELECT explain_merge('
1789 MERGE INTO ex_mtarget t USING ex_msource s ON t.a = s.a AND t.a < -1000
1790 WHEN MATCHED AND t.a < 10 THEN
1791         DO NOTHING');
1792                            explain_merge                            
1793 --------------------------------------------------------------------
1794  Merge on ex_mtarget t (actual rows=0 loops=1)
1795    ->  Merge Join (actual rows=0 loops=1)
1796          Merge Cond: (t.a = s.a)
1797          ->  Sort (actual rows=0 loops=1)
1798                Sort Key: t.a
1799                Sort Method: quicksort  Memory: xxx
1800                ->  Seq Scan on ex_mtarget t (actual rows=0 loops=1)
1801                      Filter: (a < '-1000'::integer)
1802                      Rows Removed by Filter: 54
1803          ->  Sort (never executed)
1804                Sort Key: s.a
1805                ->  Seq Scan on ex_msource s (never executed)
1806 (12 rows)
1808 DROP TABLE ex_msource, ex_mtarget;
1809 DROP FUNCTION explain_merge(text);
1810 -- EXPLAIN SubPlans and InitPlans
1811 CREATE TABLE src (a int, b int, c int, d int);
1812 CREATE TABLE tgt (a int, b int, c int, d int);
1813 CREATE TABLE ref (ab int, cd int);
1814 EXPLAIN (verbose, costs off)
1815 MERGE INTO tgt t
1816 USING (SELECT *, (SELECT count(*) FROM ref r
1817                    WHERE r.ab = s.a + s.b
1818                      AND r.cd = s.c - s.d) cnt
1819          FROM src s) s
1820 ON t.a = s.a AND t.b < s.cnt
1821 WHEN MATCHED AND t.c > s.cnt THEN
1822   UPDATE SET (b, c) = (SELECT s.b, s.cnt);
1823                                      QUERY PLAN                                      
1824 -------------------------------------------------------------------------------------
1825  Merge on public.tgt t
1826    ->  Hash Join
1827          Output: t.ctid, s.a, s.b, s.c, s.d, s.ctid
1828          Hash Cond: (t.a = s.a)
1829          Join Filter: (t.b < (SubPlan 1))
1830          ->  Seq Scan on public.tgt t
1831                Output: t.ctid, t.a, t.b
1832          ->  Hash
1833                Output: s.a, s.b, s.c, s.d, s.ctid
1834                ->  Seq Scan on public.src s
1835                      Output: s.a, s.b, s.c, s.d, s.ctid
1836          SubPlan 1
1837            ->  Aggregate
1838                  Output: count(*)
1839                  ->  Seq Scan on public.ref r
1840                        Output: r.ab, r.cd
1841                        Filter: ((r.ab = (s.a + s.b)) AND (r.cd = (s.c - s.d)))
1842    SubPlan 4
1843      ->  Aggregate
1844            Output: count(*)
1845            ->  Seq Scan on public.ref r_2
1846                  Output: r_2.ab, r_2.cd
1847                  Filter: ((r_2.ab = (s.a + s.b)) AND (r_2.cd = (s.c - s.d)))
1848    SubPlan 3
1849      ->  Result
1850            Output: s.b, (InitPlan 2).col1
1851            InitPlan 2
1852              ->  Aggregate
1853                    Output: count(*)
1854                    ->  Seq Scan on public.ref r_1
1855                          Output: r_1.ab, r_1.cd
1856                          Filter: ((r_1.ab = (s.a + s.b)) AND (r_1.cd = (s.c - s.d)))
1857 (32 rows)
1859 DROP TABLE src, tgt, ref;
1860 -- Subqueries
1861 BEGIN;
1862 MERGE INTO sq_target t
1863 USING v
1864 ON tid = sid
1865 WHEN MATCHED THEN
1866     UPDATE SET balance = (SELECT count(*) FROM sq_target);
1867 SELECT * FROM sq_target WHERE tid = 1;
1868  tid | balance 
1869 -----+---------
1870    1 |       3
1871 (1 row)
1873 ROLLBACK;
1874 BEGIN;
1875 MERGE INTO sq_target t
1876 USING v
1877 ON tid = sid
1878 WHEN MATCHED AND (SELECT count(*) > 0 FROM sq_target) THEN
1879     UPDATE SET balance = 42;
1880 SELECT * FROM sq_target WHERE tid = 1;
1881  tid | balance 
1882 -----+---------
1883    1 |      42
1884 (1 row)
1886 ROLLBACK;
1887 BEGIN;
1888 MERGE INTO sq_target t
1889 USING v
1890 ON tid = sid AND (SELECT count(*) > 0 FROM sq_target)
1891 WHEN MATCHED THEN
1892     UPDATE SET balance = 42;
1893 SELECT * FROM sq_target WHERE tid = 1;
1894  tid | balance 
1895 -----+---------
1896    1 |      42
1897 (1 row)
1899 ROLLBACK;
1900 DROP TABLE sq_target, sq_target_merge_log, sq_source CASCADE;
1901 NOTICE:  drop cascades to view v
1902 CREATE TABLE pa_target (tid integer, balance float, val text)
1903         PARTITION BY LIST (tid);
1904 CREATE TABLE part1 PARTITION OF pa_target FOR VALUES IN (1,4)
1905   WITH (autovacuum_enabled=off);
1906 CREATE TABLE part2 PARTITION OF pa_target FOR VALUES IN (2,5,6)
1907   WITH (autovacuum_enabled=off);
1908 CREATE TABLE part3 PARTITION OF pa_target FOR VALUES IN (3,8,9)
1909   WITH (autovacuum_enabled=off);
1910 CREATE TABLE part4 PARTITION OF pa_target DEFAULT
1911   WITH (autovacuum_enabled=off);
1912 CREATE TABLE pa_source (sid integer, delta float);
1913 -- insert many rows to the source table
1914 INSERT INTO pa_source SELECT id, id * 10  FROM generate_series(1,14) AS id;
1915 -- insert a few rows in the target table (odd numbered tid)
1916 INSERT INTO pa_target SELECT id, id * 100, 'initial' FROM generate_series(1,15,2) AS id;
1917 -- try simple MERGE
1918 BEGIN;
1919 MERGE INTO pa_target t
1920   USING pa_source s
1921   ON t.tid = s.sid
1922   WHEN MATCHED THEN
1923     UPDATE SET balance = balance + delta, val = val || ' updated by merge'
1924   WHEN NOT MATCHED THEN
1925     INSERT VALUES (sid, delta, 'inserted by merge')
1926   WHEN NOT MATCHED BY SOURCE THEN
1927     UPDATE SET val = val || ' not matched by source';
1928 SELECT * FROM pa_target ORDER BY tid, val;
1929  tid | balance |              val              
1930 -----+---------+-------------------------------
1931    1 |     110 | initial updated by merge
1932    2 |      20 | inserted by merge
1933    3 |     330 | initial updated by merge
1934    4 |      40 | inserted by merge
1935    5 |     550 | initial updated by merge
1936    6 |      60 | inserted by merge
1937    7 |     770 | initial updated by merge
1938    8 |      80 | inserted by merge
1939    9 |     990 | initial updated by merge
1940   10 |     100 | inserted by merge
1941   11 |    1210 | initial updated by merge
1942   12 |     120 | inserted by merge
1943   13 |    1430 | initial updated by merge
1944   14 |     140 | inserted by merge
1945   15 |    1500 | initial not matched by source
1946 (15 rows)
1948 ROLLBACK;
1949 -- same with a constant qual
1950 BEGIN;
1951 MERGE INTO pa_target t
1952   USING pa_source s
1953   ON t.tid = s.sid AND tid = 1
1954   WHEN MATCHED THEN
1955     UPDATE SET balance = balance + delta, val = val || ' updated by merge'
1956   WHEN NOT MATCHED THEN
1957     INSERT VALUES (sid, delta, 'inserted by merge')
1958   WHEN NOT MATCHED BY SOURCE THEN
1959     UPDATE SET val = val || ' not matched by source';
1960 SELECT * FROM pa_target ORDER BY tid, val;
1961  tid | balance |              val              
1962 -----+---------+-------------------------------
1963    1 |     110 | initial updated by merge
1964    2 |      20 | inserted by merge
1965    3 |     300 | initial not matched by source
1966    3 |      30 | inserted by merge
1967    4 |      40 | inserted by merge
1968    5 |     500 | initial not matched by source
1969    5 |      50 | inserted by merge
1970    6 |      60 | inserted by merge
1971    7 |     700 | initial not matched by source
1972    7 |      70 | inserted by merge
1973    8 |      80 | inserted by merge
1974    9 |     900 | initial not matched by source
1975    9 |      90 | inserted by merge
1976   10 |     100 | inserted by merge
1977   11 |    1100 | initial not matched by source
1978   11 |     110 | inserted by merge
1979   12 |     120 | inserted by merge
1980   13 |    1300 | initial not matched by source
1981   13 |     130 | inserted by merge
1982   14 |     140 | inserted by merge
1983   15 |    1500 | initial not matched by source
1984 (21 rows)
1986 ROLLBACK;
1987 -- try updating the partition key column
1988 BEGIN;
1989 CREATE FUNCTION merge_func() RETURNS integer LANGUAGE plpgsql AS $$
1990 DECLARE
1991   result integer;
1992 BEGIN
1993 MERGE INTO pa_target t
1994   USING pa_source s
1995   ON t.tid = s.sid
1996   WHEN MATCHED THEN
1997     UPDATE SET tid = tid + 1, balance = balance + delta, val = val || ' updated by merge'
1998   WHEN NOT MATCHED THEN
1999     INSERT VALUES (sid, delta, 'inserted by merge')
2000   WHEN NOT MATCHED BY SOURCE THEN
2001     UPDATE SET tid = 1, val = val || ' not matched by source';
2002 IF FOUND THEN
2003   GET DIAGNOSTICS result := ROW_COUNT;
2004 END IF;
2005 RETURN result;
2006 END;
2008 SELECT merge_func();
2009  merge_func 
2010 ------------
2011          15
2012 (1 row)
2014 SELECT * FROM pa_target ORDER BY tid, val;
2015  tid | balance |              val              
2016 -----+---------+-------------------------------
2017    1 |    1500 | initial not matched by source
2018    2 |     110 | initial updated by merge
2019    2 |      20 | inserted by merge
2020    4 |     330 | initial updated by merge
2021    4 |      40 | inserted by merge
2022    6 |     550 | initial updated by merge
2023    6 |      60 | inserted by merge
2024    8 |     770 | initial updated by merge
2025    8 |      80 | inserted by merge
2026   10 |     990 | initial updated by merge
2027   10 |     100 | inserted by merge
2028   12 |    1210 | initial updated by merge
2029   12 |     120 | inserted by merge
2030   14 |    1430 | initial updated by merge
2031   14 |     140 | inserted by merge
2032 (15 rows)
2034 ROLLBACK;
2035 -- update partition key to partition not initially scanned
2036 BEGIN;
2037 MERGE INTO pa_target t
2038   USING pa_source s
2039   ON t.tid = s.sid AND t.tid = 1
2040   WHEN MATCHED THEN
2041     UPDATE SET tid = tid + 1, balance = balance + delta, val = val || ' updated by merge'
2042   RETURNING merge_action(), t.*;
2043  merge_action | tid | balance |           val            
2044 --------------+-----+---------+--------------------------
2045  UPDATE       |   2 |     110 | initial updated by merge
2046 (1 row)
2048 SELECT * FROM pa_target ORDER BY tid;
2049  tid | balance |           val            
2050 -----+---------+--------------------------
2051    2 |     110 | initial updated by merge
2052    3 |     300 | initial
2053    5 |     500 | initial
2054    7 |     700 | initial
2055    9 |     900 | initial
2056   11 |    1100 | initial
2057   13 |    1300 | initial
2058   15 |    1500 | initial
2059 (8 rows)
2061 ROLLBACK;
2062 DROP TABLE pa_target CASCADE;
2063 -- The target table is partitioned in the same way, but this time by attaching
2064 -- partitions which have columns in different order, dropped columns etc.
2065 CREATE TABLE pa_target (tid integer, balance float, val text)
2066         PARTITION BY LIST (tid);
2067 CREATE TABLE part1 (tid integer, balance float, val text)
2068   WITH (autovacuum_enabled=off);
2069 CREATE TABLE part2 (balance float, tid integer, val text)
2070   WITH (autovacuum_enabled=off);
2071 CREATE TABLE part3 (tid integer, balance float, val text)
2072   WITH (autovacuum_enabled=off);
2073 CREATE TABLE part4 (extraid text, tid integer, balance float, val text)
2074   WITH (autovacuum_enabled=off);
2075 ALTER TABLE part4 DROP COLUMN extraid;
2076 ALTER TABLE pa_target ATTACH PARTITION part1 FOR VALUES IN (1,4);
2077 ALTER TABLE pa_target ATTACH PARTITION part2 FOR VALUES IN (2,5,6);
2078 ALTER TABLE pa_target ATTACH PARTITION part3 FOR VALUES IN (3,8,9);
2079 ALTER TABLE pa_target ATTACH PARTITION part4 DEFAULT;
2080 -- insert a few rows in the target table (odd numbered tid)
2081 INSERT INTO pa_target SELECT id, id * 100, 'initial' FROM generate_series(1,15,2) AS id;
2082 -- try simple MERGE
2083 BEGIN;
2084 DO $$
2085 DECLARE
2086   result integer;
2087 BEGIN
2088 MERGE INTO pa_target t
2089   USING pa_source s
2090   ON t.tid = s.sid
2091   WHEN MATCHED THEN
2092     UPDATE SET balance = balance + delta, val = val || ' updated by merge'
2093   WHEN NOT MATCHED THEN
2094     INSERT VALUES (sid, delta, 'inserted by merge')
2095   WHEN NOT MATCHED BY SOURCE THEN
2096     UPDATE SET val = val || ' not matched by source';
2097 GET DIAGNOSTICS result := ROW_COUNT;
2098 RAISE NOTICE 'ROW_COUNT = %', result;
2099 END;
2101 NOTICE:  ROW_COUNT = 15
2102 SELECT * FROM pa_target ORDER BY tid, val;
2103  tid | balance |              val              
2104 -----+---------+-------------------------------
2105    1 |     110 | initial updated by merge
2106    2 |      20 | inserted by merge
2107    3 |     330 | initial updated by merge
2108    4 |      40 | inserted by merge
2109    5 |     550 | initial updated by merge
2110    6 |      60 | inserted by merge
2111    7 |     770 | initial updated by merge
2112    8 |      80 | inserted by merge
2113    9 |     990 | initial updated by merge
2114   10 |     100 | inserted by merge
2115   11 |    1210 | initial updated by merge
2116   12 |     120 | inserted by merge
2117   13 |    1430 | initial updated by merge
2118   14 |     140 | inserted by merge
2119   15 |    1500 | initial not matched by source
2120 (15 rows)
2122 ROLLBACK;
2123 -- same with a constant qual
2124 BEGIN;
2125 MERGE INTO pa_target t
2126   USING pa_source s
2127   ON t.tid = s.sid AND tid IN (1, 5)
2128   WHEN MATCHED AND tid % 5 = 0 THEN DELETE
2129   WHEN MATCHED THEN
2130     UPDATE SET balance = balance + delta, val = val || ' updated by merge'
2131   WHEN NOT MATCHED THEN
2132     INSERT VALUES (sid, delta, 'inserted by merge')
2133   WHEN NOT MATCHED BY SOURCE THEN
2134     UPDATE SET val = val || ' not matched by source';
2135 SELECT * FROM pa_target ORDER BY tid, val;
2136  tid | balance |              val              
2137 -----+---------+-------------------------------
2138    1 |     110 | initial updated by merge
2139    2 |      20 | inserted by merge
2140    3 |     300 | initial not matched by source
2141    3 |      30 | inserted by merge
2142    4 |      40 | inserted by merge
2143    6 |      60 | inserted by merge
2144    7 |     700 | initial not matched by source
2145    7 |      70 | inserted by merge
2146    8 |      80 | inserted by merge
2147    9 |     900 | initial not matched by source
2148    9 |      90 | inserted by merge
2149   10 |     100 | inserted by merge
2150   11 |    1100 | initial not matched by source
2151   11 |     110 | inserted by merge
2152   12 |     120 | inserted by merge
2153   13 |    1300 | initial not matched by source
2154   13 |     130 | inserted by merge
2155   14 |     140 | inserted by merge
2156   15 |    1500 | initial not matched by source
2157 (19 rows)
2159 ROLLBACK;
2160 -- try updating the partition key column
2161 BEGIN;
2162 DO $$
2163 DECLARE
2164   result integer;
2165 BEGIN
2166 MERGE INTO pa_target t
2167   USING pa_source s
2168   ON t.tid = s.sid
2169   WHEN MATCHED THEN
2170     UPDATE SET tid = tid + 1, balance = balance + delta, val = val || ' updated by merge'
2171   WHEN NOT MATCHED THEN
2172     INSERT VALUES (sid, delta, 'inserted by merge')
2173   WHEN NOT MATCHED BY SOURCE THEN
2174     UPDATE SET tid = 1, val = val || ' not matched by source';
2175 GET DIAGNOSTICS result := ROW_COUNT;
2176 RAISE NOTICE 'ROW_COUNT = %', result;
2177 END;
2179 NOTICE:  ROW_COUNT = 15
2180 SELECT * FROM pa_target ORDER BY tid, val;
2181  tid | balance |              val              
2182 -----+---------+-------------------------------
2183    1 |    1500 | initial not matched by source
2184    2 |     110 | initial updated by merge
2185    2 |      20 | inserted by merge
2186    4 |     330 | initial updated by merge
2187    4 |      40 | inserted by merge
2188    6 |     550 | initial updated by merge
2189    6 |      60 | inserted by merge
2190    8 |     770 | initial updated by merge
2191    8 |      80 | inserted by merge
2192   10 |     990 | initial updated by merge
2193   10 |     100 | inserted by merge
2194   12 |    1210 | initial updated by merge
2195   12 |     120 | inserted by merge
2196   14 |    1430 | initial updated by merge
2197   14 |     140 | inserted by merge
2198 (15 rows)
2200 ROLLBACK;
2201 -- as above, but blocked by BEFORE DELETE ROW trigger
2202 BEGIN;
2203 CREATE FUNCTION trig_fn() RETURNS trigger LANGUAGE plpgsql AS
2204   $$ BEGIN RETURN NULL; END; $$;
2205 CREATE TRIGGER del_trig BEFORE DELETE ON pa_target
2206   FOR EACH ROW EXECUTE PROCEDURE trig_fn();
2207 DO $$
2208 DECLARE
2209   result integer;
2210 BEGIN
2211 MERGE INTO pa_target t
2212   USING pa_source s
2213   ON t.tid = s.sid
2214   WHEN MATCHED THEN
2215     UPDATE SET tid = tid + 1, balance = balance + delta, val = val || ' updated by merge'
2216   WHEN NOT MATCHED THEN
2217     INSERT VALUES (sid, delta, 'inserted by merge')
2218   WHEN NOT MATCHED BY SOURCE THEN
2219     UPDATE SET val = val || ' not matched by source';
2220 GET DIAGNOSTICS result := ROW_COUNT;
2221 RAISE NOTICE 'ROW_COUNT = %', result;
2222 END;
2224 NOTICE:  ROW_COUNT = 11
2225 SELECT * FROM pa_target ORDER BY tid, val;
2226  tid | balance |              val              
2227 -----+---------+-------------------------------
2228    1 |     100 | initial
2229    2 |      20 | inserted by merge
2230    3 |     300 | initial
2231    4 |      40 | inserted by merge
2232    6 |     550 | initial updated by merge
2233    6 |      60 | inserted by merge
2234    7 |     700 | initial
2235    8 |      80 | inserted by merge
2236    9 |     900 | initial
2237   10 |     100 | inserted by merge
2238   12 |    1210 | initial updated by merge
2239   12 |     120 | inserted by merge
2240   14 |    1430 | initial updated by merge
2241   14 |     140 | inserted by merge
2242   15 |    1500 | initial not matched by source
2243 (15 rows)
2245 ROLLBACK;
2246 -- as above, but blocked by BEFORE INSERT ROW trigger
2247 BEGIN;
2248 CREATE FUNCTION trig_fn() RETURNS trigger LANGUAGE plpgsql AS
2249   $$ BEGIN RETURN NULL; END; $$;
2250 CREATE TRIGGER ins_trig BEFORE INSERT ON pa_target
2251   FOR EACH ROW EXECUTE PROCEDURE trig_fn();
2252 DO $$
2253 DECLARE
2254   result integer;
2255 BEGIN
2256 MERGE INTO pa_target t
2257   USING pa_source s
2258   ON t.tid = s.sid
2259   WHEN MATCHED THEN
2260     UPDATE SET tid = tid + 1, balance = balance + delta, val = val || ' updated by merge'
2261   WHEN NOT MATCHED THEN
2262     INSERT VALUES (sid, delta, 'inserted by merge')
2263   WHEN NOT MATCHED BY SOURCE THEN
2264     UPDATE SET val = val || ' not matched by source';
2265 GET DIAGNOSTICS result := ROW_COUNT;
2266 RAISE NOTICE 'ROW_COUNT = %', result;
2267 END;
2269 NOTICE:  ROW_COUNT = 4
2270 SELECT * FROM pa_target ORDER BY tid, val;
2271  tid | balance |              val              
2272 -----+---------+-------------------------------
2273    6 |     550 | initial updated by merge
2274   12 |    1210 | initial updated by merge
2275   14 |    1430 | initial updated by merge
2276   15 |    1500 | initial not matched by source
2277 (4 rows)
2279 ROLLBACK;
2280 -- test RLS enforcement
2281 BEGIN;
2282 ALTER TABLE pa_target ENABLE ROW LEVEL SECURITY;
2283 ALTER TABLE pa_target FORCE ROW LEVEL SECURITY;
2284 CREATE POLICY pa_target_pol ON pa_target USING (tid != 0);
2285 MERGE INTO pa_target t
2286   USING pa_source s
2287   ON t.tid = s.sid AND t.tid IN (1,2,3,4)
2288   WHEN MATCHED THEN
2289     UPDATE SET tid = tid - 1;
2290 ERROR:  new row violates row-level security policy for table "pa_target"
2291 ROLLBACK;
2292 DROP TABLE pa_source;
2293 DROP TABLE pa_target CASCADE;
2294 -- Sub-partitioning
2295 CREATE TABLE pa_target (logts timestamp, tid integer, balance float, val text)
2296         PARTITION BY RANGE (logts);
2297 CREATE TABLE part_m01 PARTITION OF pa_target
2298         FOR VALUES FROM ('2017-01-01') TO ('2017-02-01')
2299         PARTITION BY LIST (tid);
2300 CREATE TABLE part_m01_odd PARTITION OF part_m01
2301         FOR VALUES IN (1,3,5,7,9) WITH (autovacuum_enabled=off);
2302 CREATE TABLE part_m01_even PARTITION OF part_m01
2303         FOR VALUES IN (2,4,6,8) WITH (autovacuum_enabled=off);
2304 CREATE TABLE part_m02 PARTITION OF pa_target
2305         FOR VALUES FROM ('2017-02-01') TO ('2017-03-01')
2306         PARTITION BY LIST (tid);
2307 CREATE TABLE part_m02_odd PARTITION OF part_m02
2308         FOR VALUES IN (1,3,5,7,9) WITH (autovacuum_enabled=off);
2309 CREATE TABLE part_m02_even PARTITION OF part_m02
2310         FOR VALUES IN (2,4,6,8) WITH (autovacuum_enabled=off);
2311 CREATE TABLE pa_source (sid integer, delta float)
2312   WITH (autovacuum_enabled=off);
2313 -- insert many rows to the source table
2314 INSERT INTO pa_source SELECT id, id * 10  FROM generate_series(1,14) AS id;
2315 -- insert a few rows in the target table (odd numbered tid)
2316 INSERT INTO pa_target SELECT '2017-01-31', id, id * 100, 'initial' FROM generate_series(1,9,3) AS id;
2317 INSERT INTO pa_target SELECT '2017-02-28', id, id * 100, 'initial' FROM generate_series(2,9,3) AS id;
2318 -- try simple MERGE
2319 BEGIN;
2320 MERGE INTO pa_target t
2321   USING (SELECT '2017-01-15' AS slogts, * FROM pa_source WHERE sid < 10) s
2322   ON t.tid = s.sid
2323   WHEN MATCHED THEN
2324     UPDATE SET balance = balance + delta, val = val || ' updated by merge'
2325   WHEN NOT MATCHED THEN
2326     INSERT VALUES (slogts::timestamp, sid, delta, 'inserted by merge')
2327   RETURNING merge_action(), t.*;
2328  merge_action |          logts           | tid | balance |           val            
2329 --------------+--------------------------+-----+---------+--------------------------
2330  UPDATE       | Tue Jan 31 00:00:00 2017 |   1 |     110 | initial updated by merge
2331  UPDATE       | Tue Feb 28 00:00:00 2017 |   2 |     220 | initial updated by merge
2332  INSERT       | Sun Jan 15 00:00:00 2017 |   3 |      30 | inserted by merge
2333  UPDATE       | Tue Jan 31 00:00:00 2017 |   4 |     440 | initial updated by merge
2334  UPDATE       | Tue Feb 28 00:00:00 2017 |   5 |     550 | initial updated by merge
2335  INSERT       | Sun Jan 15 00:00:00 2017 |   6 |      60 | inserted by merge
2336  UPDATE       | Tue Jan 31 00:00:00 2017 |   7 |     770 | initial updated by merge
2337  UPDATE       | Tue Feb 28 00:00:00 2017 |   8 |     880 | initial updated by merge
2338  INSERT       | Sun Jan 15 00:00:00 2017 |   9 |      90 | inserted by merge
2339 (9 rows)
2341 SELECT * FROM pa_target ORDER BY tid;
2342           logts           | tid | balance |           val            
2343 --------------------------+-----+---------+--------------------------
2344  Tue Jan 31 00:00:00 2017 |   1 |     110 | initial updated by merge
2345  Tue Feb 28 00:00:00 2017 |   2 |     220 | initial updated by merge
2346  Sun Jan 15 00:00:00 2017 |   3 |      30 | inserted by merge
2347  Tue Jan 31 00:00:00 2017 |   4 |     440 | initial updated by merge
2348  Tue Feb 28 00:00:00 2017 |   5 |     550 | initial updated by merge
2349  Sun Jan 15 00:00:00 2017 |   6 |      60 | inserted by merge
2350  Tue Jan 31 00:00:00 2017 |   7 |     770 | initial updated by merge
2351  Tue Feb 28 00:00:00 2017 |   8 |     880 | initial updated by merge
2352  Sun Jan 15 00:00:00 2017 |   9 |      90 | inserted by merge
2353 (9 rows)
2355 ROLLBACK;
2356 DROP TABLE pa_source;
2357 DROP TABLE pa_target CASCADE;
2358 -- Partitioned table with primary key
2359 CREATE TABLE pa_target (tid integer PRIMARY KEY) PARTITION BY LIST (tid);
2360 CREATE TABLE pa_targetp PARTITION OF pa_target DEFAULT;
2361 CREATE TABLE pa_source (sid integer);
2362 INSERT INTO pa_source VALUES (1), (2);
2363 EXPLAIN (VERBOSE, COSTS OFF)
2364 MERGE INTO pa_target t USING pa_source s ON t.tid = s.sid
2365   WHEN NOT MATCHED THEN INSERT VALUES (s.sid);
2366                          QUERY PLAN                          
2367 -------------------------------------------------------------
2368  Merge on public.pa_target t
2369    Merge on public.pa_targetp t_1
2370    ->  Hash Left Join
2371          Output: s.sid, s.ctid, t_1.tableoid, t_1.ctid
2372          Inner Unique: true
2373          Hash Cond: (s.sid = t_1.tid)
2374          ->  Seq Scan on public.pa_source s
2375                Output: s.sid, s.ctid
2376          ->  Hash
2377                Output: t_1.tid, t_1.tableoid, t_1.ctid
2378                ->  Seq Scan on public.pa_targetp t_1
2379                      Output: t_1.tid, t_1.tableoid, t_1.ctid
2380 (12 rows)
2382 MERGE INTO pa_target t USING pa_source s ON t.tid = s.sid
2383   WHEN NOT MATCHED THEN INSERT VALUES (s.sid);
2384 TABLE pa_target;
2385  tid 
2386 -----
2387    1
2388    2
2389 (2 rows)
2391 -- Partition-less partitioned table
2392 -- (the bug we are checking for appeared only if table had partitions before)
2393 DROP TABLE pa_targetp;
2394 EXPLAIN (VERBOSE, COSTS OFF)
2395 MERGE INTO pa_target t USING pa_source s ON t.tid = s.sid
2396   WHEN NOT MATCHED THEN INSERT VALUES (s.sid);
2397                  QUERY PLAN                 
2398 --------------------------------------------
2399  Merge on public.pa_target t
2400    ->  Hash Left Join
2401          Output: s.sid, s.ctid, t.ctid
2402          Inner Unique: true
2403          Hash Cond: (s.sid = t.tid)
2404          ->  Seq Scan on public.pa_source s
2405                Output: s.sid, s.ctid
2406          ->  Hash
2407                Output: t.tid, t.ctid
2408                ->  Result
2409                      Output: t.tid, t.ctid
2410                      One-Time Filter: false
2411 (12 rows)
2413 MERGE INTO pa_target t USING pa_source s ON t.tid = s.sid
2414   WHEN NOT MATCHED THEN INSERT VALUES (s.sid);
2415 ERROR:  no partition of relation "pa_target" found for row
2416 DETAIL:  Partition key of the failing row contains (tid) = (1).
2417 DROP TABLE pa_source;
2418 DROP TABLE pa_target CASCADE;
2419 -- some complex joins on the source side
2420 CREATE TABLE cj_target (tid integer, balance float, val text)
2421   WITH (autovacuum_enabled=off);
2422 CREATE TABLE cj_source1 (sid1 integer, scat integer, delta integer)
2423   WITH (autovacuum_enabled=off);
2424 CREATE TABLE cj_source2 (sid2 integer, sval text)
2425   WITH (autovacuum_enabled=off);
2426 INSERT INTO cj_source1 VALUES (1, 10, 100);
2427 INSERT INTO cj_source1 VALUES (1, 20, 200);
2428 INSERT INTO cj_source1 VALUES (2, 20, 300);
2429 INSERT INTO cj_source1 VALUES (3, 10, 400);
2430 INSERT INTO cj_source2 VALUES (1, 'initial source2');
2431 INSERT INTO cj_source2 VALUES (2, 'initial source2');
2432 INSERT INTO cj_source2 VALUES (3, 'initial source2');
2433 -- source relation is an unaliased join
2434 MERGE INTO cj_target t
2435 USING cj_source1 s1
2436         INNER JOIN cj_source2 s2 ON sid1 = sid2
2437 ON t.tid = sid1
2438 WHEN NOT MATCHED THEN
2439         INSERT VALUES (sid1, delta, sval);
2440 -- try accessing columns from either side of the source join
2441 MERGE INTO cj_target t
2442 USING cj_source2 s2
2443         INNER JOIN cj_source1 s1 ON sid1 = sid2 AND scat = 20
2444 ON t.tid = sid1
2445 WHEN NOT MATCHED THEN
2446         INSERT VALUES (sid2, delta, sval)
2447 WHEN MATCHED THEN
2448         DELETE;
2449 -- some simple expressions in INSERT targetlist
2450 MERGE INTO cj_target t
2451 USING cj_source2 s2
2452         INNER JOIN cj_source1 s1 ON sid1 = sid2
2453 ON t.tid = sid1
2454 WHEN NOT MATCHED THEN
2455         INSERT VALUES (sid2, delta + scat, sval)
2456 WHEN MATCHED THEN
2457         UPDATE SET val = val || ' updated by merge';
2458 MERGE INTO cj_target t
2459 USING cj_source2 s2
2460         INNER JOIN cj_source1 s1 ON sid1 = sid2 AND scat = 20
2461 ON t.tid = sid1
2462 WHEN MATCHED THEN
2463         UPDATE SET val = val || ' ' || delta::text;
2464 SELECT * FROM cj_target;
2465  tid | balance |               val                
2466 -----+---------+----------------------------------
2467    3 |     400 | initial source2 updated by merge
2468    1 |     220 | initial source2 200
2469    1 |     110 | initial source2 200
2470    2 |     320 | initial source2 300
2471 (4 rows)
2473 -- try it with an outer join and PlaceHolderVar
2474 MERGE INTO cj_target t
2475 USING (SELECT *, 'join input'::text AS phv FROM cj_source1) fj
2476         FULL JOIN cj_source2 fj2 ON fj.scat = fj2.sid2 * 10
2477 ON t.tid = fj.scat
2478 WHEN NOT MATCHED THEN
2479         INSERT (tid, balance, val) VALUES (fj.scat, fj.delta, fj.phv);
2480 SELECT * FROM cj_target;
2481  tid | balance |               val                
2482 -----+---------+----------------------------------
2483    3 |     400 | initial source2 updated by merge
2484    1 |     220 | initial source2 200
2485    1 |     110 | initial source2 200
2486    2 |     320 | initial source2 300
2487   10 |     100 | join input
2488   10 |     400 | join input
2489   20 |     200 | join input
2490   20 |     300 | join input
2491      |         | 
2492 (9 rows)
2494 ALTER TABLE cj_source1 RENAME COLUMN sid1 TO sid;
2495 ALTER TABLE cj_source2 RENAME COLUMN sid2 TO sid;
2496 TRUNCATE cj_target;
2497 MERGE INTO cj_target t
2498 USING cj_source1 s1
2499         INNER JOIN cj_source2 s2 ON s1.sid = s2.sid
2500 ON t.tid = s1.sid
2501 WHEN NOT MATCHED THEN
2502         INSERT VALUES (s2.sid, delta, sval);
2503 DROP TABLE cj_source2, cj_source1, cj_target;
2504 -- Function scans
2505 CREATE TABLE fs_target (a int, b int, c text)
2506   WITH (autovacuum_enabled=off);
2507 MERGE INTO fs_target t
2508 USING generate_series(1,100,1) AS id
2509 ON t.a = id
2510 WHEN MATCHED THEN
2511         UPDATE SET b = b + id
2512 WHEN NOT MATCHED THEN
2513         INSERT VALUES (id, -1);
2514 MERGE INTO fs_target t
2515 USING generate_series(1,100,2) AS id
2516 ON t.a = id
2517 WHEN MATCHED THEN
2518         UPDATE SET b = b + id, c = 'updated '|| id.*::text
2519 WHEN NOT MATCHED THEN
2520         INSERT VALUES (id, -1, 'inserted ' || id.*::text);
2521 SELECT count(*) FROM fs_target;
2522  count 
2523 -------
2524    100
2525 (1 row)
2527 DROP TABLE fs_target;
2528 -- SERIALIZABLE test
2529 -- handled in isolation tests
2530 -- Inheritance-based partitioning
2531 CREATE TABLE measurement (
2532     city_id         int not null,
2533     logdate         date not null,
2534     peaktemp        int,
2535     unitsales       int
2536 ) WITH (autovacuum_enabled=off);
2537 CREATE TABLE measurement_y2006m02 (
2538     CHECK ( logdate >= DATE '2006-02-01' AND logdate < DATE '2006-03-01' )
2539 ) INHERITS (measurement) WITH (autovacuum_enabled=off);
2540 CREATE TABLE measurement_y2006m03 (
2541     CHECK ( logdate >= DATE '2006-03-01' AND logdate < DATE '2006-04-01' )
2542 ) INHERITS (measurement) WITH (autovacuum_enabled=off);
2543 CREATE TABLE measurement_y2007m01 (
2544     filler          text,
2545     peaktemp        int,
2546     logdate         date not null,
2547     city_id         int not null,
2548     unitsales       int
2549     CHECK ( logdate >= DATE '2007-01-01' AND logdate < DATE '2007-02-01')
2550 ) WITH (autovacuum_enabled=off);
2551 ALTER TABLE measurement_y2007m01 DROP COLUMN filler;
2552 ALTER TABLE measurement_y2007m01 INHERIT measurement;
2553 INSERT INTO measurement VALUES (0, '2005-07-21', 5, 15);
2554 CREATE OR REPLACE FUNCTION measurement_insert_trigger()
2555 RETURNS TRIGGER AS $$
2556 BEGIN
2557     IF ( NEW.logdate >= DATE '2006-02-01' AND
2558          NEW.logdate < DATE '2006-03-01' ) THEN
2559         INSERT INTO measurement_y2006m02 VALUES (NEW.*);
2560     ELSIF ( NEW.logdate >= DATE '2006-03-01' AND
2561             NEW.logdate < DATE '2006-04-01' ) THEN
2562         INSERT INTO measurement_y2006m03 VALUES (NEW.*);
2563     ELSIF ( NEW.logdate >= DATE '2007-01-01' AND
2564             NEW.logdate < DATE '2007-02-01' ) THEN
2565         INSERT INTO measurement_y2007m01 (city_id, logdate, peaktemp, unitsales)
2566             VALUES (NEW.*);
2567     ELSE
2568         RAISE EXCEPTION 'Date out of range.  Fix the measurement_insert_trigger() function!';
2569     END IF;
2570     RETURN NULL;
2571 END;
2572 $$ LANGUAGE plpgsql ;
2573 CREATE TRIGGER insert_measurement_trigger
2574     BEFORE INSERT ON measurement
2575     FOR EACH ROW EXECUTE PROCEDURE measurement_insert_trigger();
2576 INSERT INTO measurement VALUES (1, '2006-02-10', 35, 10);
2577 INSERT INTO measurement VALUES (1, '2006-02-16', 45, 20);
2578 INSERT INTO measurement VALUES (1, '2006-03-17', 25, 10);
2579 INSERT INTO measurement VALUES (1, '2006-03-27', 15, 40);
2580 INSERT INTO measurement VALUES (1, '2007-01-15', 10, 10);
2581 INSERT INTO measurement VALUES (1, '2007-01-17', 10, 10);
2582 SELECT tableoid::regclass, * FROM measurement ORDER BY city_id, logdate;
2583        tableoid       | city_id |  logdate   | peaktemp | unitsales 
2584 ----------------------+---------+------------+----------+-----------
2585  measurement          |       0 | 07-21-2005 |        5 |        15
2586  measurement_y2006m02 |       1 | 02-10-2006 |       35 |        10
2587  measurement_y2006m02 |       1 | 02-16-2006 |       45 |        20
2588  measurement_y2006m03 |       1 | 03-17-2006 |       25 |        10
2589  measurement_y2006m03 |       1 | 03-27-2006 |       15 |        40
2590  measurement_y2007m01 |       1 | 01-15-2007 |       10 |        10
2591  measurement_y2007m01 |       1 | 01-17-2007 |       10 |        10
2592 (7 rows)
2594 CREATE TABLE new_measurement (LIKE measurement) WITH (autovacuum_enabled=off);
2595 INSERT INTO new_measurement VALUES (0, '2005-07-21', 25, 20);
2596 INSERT INTO new_measurement VALUES (1, '2006-03-01', 20, 10);
2597 INSERT INTO new_measurement VALUES (1, '2006-02-16', 50, 10);
2598 INSERT INTO new_measurement VALUES (2, '2006-02-10', 20, 20);
2599 INSERT INTO new_measurement VALUES (1, '2006-03-27', NULL, NULL);
2600 INSERT INTO new_measurement VALUES (1, '2007-01-17', NULL, NULL);
2601 INSERT INTO new_measurement VALUES (1, '2007-01-15', 5, NULL);
2602 INSERT INTO new_measurement VALUES (1, '2007-01-16', 10, 10);
2603 BEGIN;
2604 MERGE INTO ONLY measurement m
2605  USING new_measurement nm ON
2606       (m.city_id = nm.city_id and m.logdate=nm.logdate)
2607 WHEN MATCHED AND nm.peaktemp IS NULL THEN DELETE
2608 WHEN MATCHED THEN UPDATE
2609      SET peaktemp = greatest(m.peaktemp, nm.peaktemp),
2610         unitsales = m.unitsales + coalesce(nm.unitsales, 0)
2611 WHEN NOT MATCHED THEN INSERT
2612      (city_id, logdate, peaktemp, unitsales)
2613    VALUES (city_id, logdate, peaktemp, unitsales);
2614 SELECT tableoid::regclass, * FROM measurement ORDER BY city_id, logdate, peaktemp;
2615        tableoid       | city_id |  logdate   | peaktemp | unitsales 
2616 ----------------------+---------+------------+----------+-----------
2617  measurement          |       0 | 07-21-2005 |       25 |        35
2618  measurement_y2006m02 |       1 | 02-10-2006 |       35 |        10
2619  measurement_y2006m02 |       1 | 02-16-2006 |       45 |        20
2620  measurement_y2006m02 |       1 | 02-16-2006 |       50 |        10
2621  measurement_y2006m03 |       1 | 03-01-2006 |       20 |        10
2622  measurement_y2006m03 |       1 | 03-17-2006 |       25 |        10
2623  measurement_y2006m03 |       1 | 03-27-2006 |       15 |        40
2624  measurement_y2006m03 |       1 | 03-27-2006 |          |          
2625  measurement_y2007m01 |       1 | 01-15-2007 |        5 |          
2626  measurement_y2007m01 |       1 | 01-15-2007 |       10 |        10
2627  measurement_y2007m01 |       1 | 01-16-2007 |       10 |        10
2628  measurement_y2007m01 |       1 | 01-17-2007 |       10 |        10
2629  measurement_y2007m01 |       1 | 01-17-2007 |          |          
2630  measurement_y2006m02 |       2 | 02-10-2006 |       20 |        20
2631 (14 rows)
2633 ROLLBACK;
2634 MERGE into measurement m
2635  USING new_measurement nm ON
2636       (m.city_id = nm.city_id and m.logdate=nm.logdate)
2637 WHEN MATCHED AND nm.peaktemp IS NULL THEN DELETE
2638 WHEN MATCHED THEN UPDATE
2639      SET peaktemp = greatest(m.peaktemp, nm.peaktemp),
2640         unitsales = m.unitsales + coalesce(nm.unitsales, 0)
2641 WHEN NOT MATCHED THEN INSERT
2642      (city_id, logdate, peaktemp, unitsales)
2643    VALUES (city_id, logdate, peaktemp, unitsales);
2644 SELECT tableoid::regclass, * FROM measurement ORDER BY city_id, logdate;
2645        tableoid       | city_id |  logdate   | peaktemp | unitsales 
2646 ----------------------+---------+------------+----------+-----------
2647  measurement          |       0 | 07-21-2005 |       25 |        35
2648  measurement_y2006m02 |       1 | 02-10-2006 |       35 |        10
2649  measurement_y2006m02 |       1 | 02-16-2006 |       50 |        30
2650  measurement_y2006m03 |       1 | 03-01-2006 |       20 |        10
2651  measurement_y2006m03 |       1 | 03-17-2006 |       25 |        10
2652  measurement_y2007m01 |       1 | 01-15-2007 |       10 |        10
2653  measurement_y2007m01 |       1 | 01-16-2007 |       10 |        10
2654  measurement_y2006m02 |       2 | 02-10-2006 |       20 |        20
2655 (8 rows)
2657 BEGIN;
2658 MERGE INTO new_measurement nm
2659  USING ONLY measurement m ON
2660       (nm.city_id = m.city_id and nm.logdate=m.logdate)
2661 WHEN MATCHED THEN DELETE;
2662 SELECT * FROM new_measurement ORDER BY city_id, logdate;
2663  city_id |  logdate   | peaktemp | unitsales 
2664 ---------+------------+----------+-----------
2665        1 | 02-16-2006 |       50 |        10
2666        1 | 03-01-2006 |       20 |        10
2667        1 | 03-27-2006 |          |          
2668        1 | 01-15-2007 |        5 |          
2669        1 | 01-16-2007 |       10 |        10
2670        1 | 01-17-2007 |          |          
2671        2 | 02-10-2006 |       20 |        20
2672 (7 rows)
2674 ROLLBACK;
2675 MERGE INTO new_measurement nm
2676  USING measurement m ON
2677       (nm.city_id = m.city_id and nm.logdate=m.logdate)
2678 WHEN MATCHED THEN DELETE;
2679 SELECT * FROM new_measurement ORDER BY city_id, logdate;
2680  city_id |  logdate   | peaktemp | unitsales 
2681 ---------+------------+----------+-----------
2682        1 | 03-27-2006 |          |          
2683        1 | 01-17-2007 |          |          
2684 (2 rows)
2686 DROP TABLE measurement, new_measurement CASCADE;
2687 NOTICE:  drop cascades to 3 other objects
2688 DETAIL:  drop cascades to table measurement_y2006m02
2689 drop cascades to table measurement_y2006m03
2690 drop cascades to table measurement_y2007m01
2691 DROP FUNCTION measurement_insert_trigger();
2693 -- test non-strict join clause
2695 CREATE TABLE src (a int, b text);
2696 INSERT INTO src VALUES (1, 'src row');
2697 CREATE TABLE tgt (a int, b text);
2698 INSERT INTO tgt VALUES (NULL, 'tgt row');
2699 MERGE INTO tgt USING src ON tgt.a IS NOT DISTINCT FROM src.a
2700   WHEN MATCHED THEN UPDATE SET a = src.a, b = src.b
2701   WHEN NOT MATCHED BY SOURCE THEN DELETE
2702   RETURNING merge_action(), src.*, tgt.*;
2703  merge_action | a | b | a |    b    
2704 --------------+---+---+---+---------
2705  DELETE       |   |   |   | tgt row
2706 (1 row)
2708 SELECT * FROM tgt;
2709  a | b 
2710 ---+---
2711 (0 rows)
2713 DROP TABLE src, tgt;
2715 -- test for bug #18634 (wrong varnullingrels error)
2717 CREATE TABLE bug18634t (a int, b int, c text);
2718 INSERT INTO bug18634t VALUES(1, 10, 'tgt1'), (2, 20, 'tgt2');
2719 CREATE VIEW bug18634v AS
2720   SELECT * FROM bug18634t WHERE EXISTS (SELECT 1 FROM bug18634t);
2721 CREATE TABLE bug18634s (a int, b int, c text);
2722 INSERT INTO bug18634s VALUES (1, 2, 'src1');
2723 MERGE INTO bug18634v t USING bug18634s s ON s.a = t.a
2724   WHEN MATCHED THEN UPDATE SET b = s.b
2725   WHEN NOT MATCHED BY SOURCE THEN DELETE
2726   RETURNING merge_action(), s.c, t.*;
2727  merge_action |  c   | a | b  |  c   
2728 --------------+------+---+----+------
2729  UPDATE       | src1 | 1 |  2 | tgt1
2730  DELETE       |      | 2 | 20 | tgt2
2731 (2 rows)
2733 SELECT * FROM bug18634t;
2734  a | b |  c   
2735 ---+---+------
2736  1 | 2 | tgt1
2737 (1 row)
2739 DROP TABLE bug18634t CASCADE;
2740 NOTICE:  drop cascades to view bug18634v
2741 DROP TABLE bug18634s;
2742 -- prepare
2743 RESET SESSION AUTHORIZATION;
2744 -- try a system catalog
2745 MERGE INTO pg_class c
2746 USING (SELECT 'pg_depend'::regclass AS oid) AS j
2747 ON j.oid = c.oid
2748 WHEN MATCHED THEN
2749         UPDATE SET reltuples = reltuples + 1
2750 RETURNING j.oid;
2751     oid    
2752 -----------
2753  pg_depend
2754 (1 row)
2756 CREATE VIEW classv AS SELECT * FROM pg_class;
2757 MERGE INTO classv c
2758 USING pg_namespace n
2759 ON n.oid = c.relnamespace
2760 WHEN MATCHED AND c.oid = 'pg_depend'::regclass THEN
2761         UPDATE SET reltuples = reltuples - 1
2762 RETURNING c.oid;
2763  oid  
2764 ------
2765  2608
2766 (1 row)
2768 DROP TABLE target, target2;
2769 DROP TABLE source, source2;
2770 DROP FUNCTION merge_trigfunc();
2771 DROP USER regress_merge_privs;
2772 DROP USER regress_merge_no_privs;
2773 DROP USER regress_merge_none;