aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/optimizer/prep/prepjointree.c39
-rw-r--r--src/test/regress/expected/merge.out29
-rw-r--r--src/test/regress/sql/merge.sql21
3 files changed, 89 insertions, 0 deletions
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index ca15994fdc7..4d7f972caf1 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -283,6 +283,45 @@ transform_MERGE_to_join(Query *parse)
bms_make_singleton(joinrti));
/*
+ * If the source relation is on the outer side of the join, mark any
+ * source relation Vars in the join condition, actions, and RETURNING list
+ * as nullable by the join. These Vars will be added to the targetlist by
+ * preprocess_targetlist(), so it's important to mark them correctly here.
+ *
+ * It might seem that this is not necessary for Vars in the join
+ * condition, since it is inside the join, but it is also needed above the
+ * join (in the ModifyTable node) to distinguish between the MATCHED and
+ * NOT MATCHED BY SOURCE cases -- see ExecMergeMatched(). Note that this
+ * creates a modified copy of the join condition, for use above the join,
+ * without modifying the the original join condition, inside the join.
+ */
+ if (jointype == JOIN_LEFT || jointype == JOIN_FULL)
+ {
+ parse->mergeJoinCondition =
+ add_nulling_relids(parse->mergeJoinCondition,
+ bms_make_singleton(sourcerti),
+ bms_make_singleton(joinrti));
+
+ foreach_node(MergeAction, action, parse->mergeActionList)
+ {
+ action->qual =
+ add_nulling_relids(action->qual,
+ bms_make_singleton(sourcerti),
+ bms_make_singleton(joinrti));
+
+ action->targetList = (List *)
+ add_nulling_relids((Node *) action->targetList,
+ bms_make_singleton(sourcerti),
+ bms_make_singleton(joinrti));
+ }
+
+ parse->returningList = (List *)
+ add_nulling_relids((Node *) parse->returningList,
+ bms_make_singleton(sourcerti),
+ bms_make_singleton(joinrti));
+ }
+
+ /*
* If there are any WHEN NOT MATCHED BY SOURCE actions, the executor will
* use the join condition to distinguish between MATCHED and NOT MATCHED
* BY SOURCE cases. Otherwise, it's no longer needed, and we set it to
diff --git a/src/test/regress/expected/merge.out b/src/test/regress/expected/merge.out
index 0e59bae1a7f..c236f155c08 100644
--- a/src/test/regress/expected/merge.out
+++ b/src/test/regress/expected/merge.out
@@ -2711,6 +2711,35 @@ SELECT * FROM tgt;
(0 rows)
DROP TABLE src, tgt;
+
+--
+-- test for bug #18634 (wrong varnullingrels error)
+--
+CREATE TABLE bug18634t (a int, b int, c text);
+INSERT INTO bug18634t VALUES(1, 10, 'tgt1'), (2, 20, 'tgt2');
+CREATE VIEW bug18634v AS
+ SELECT * FROM bug18634t WHERE EXISTS (SELECT 1 FROM bug18634t);
+CREATE TABLE bug18634s (a int, b int, c text);
+INSERT INTO bug18634s VALUES (1, 2, 'src1');
+MERGE INTO bug18634v t USING bug18634s s ON s.a = t.a
+ WHEN MATCHED THEN UPDATE SET b = s.b
+ WHEN NOT MATCHED BY SOURCE THEN DELETE
+ RETURNING merge_action(), s.c, t.*;
+ merge_action | c | a | b | c
+--------------+------+---+----+------
+ UPDATE | src1 | 1 | 2 | tgt1
+ DELETE | | 2 | 20 | tgt2
+(2 rows)
+
+SELECT * FROM bug18634t;
+ a | b | c
+---+---+------
+ 1 | 2 | tgt1
+(1 row)
+
+DROP TABLE bug18634t CASCADE;
+NOTICE: drop cascades to view bug18634v
+DROP TABLE bug18634s;
-- prepare
RESET SESSION AUTHORIZATION;
-- try a system catalog
diff --git a/src/test/regress/sql/merge.sql b/src/test/regress/sql/merge.sql
index 2a7753c65b0..ce9981d70b1 100644
--- a/src/test/regress/sql/merge.sql
+++ b/src/test/regress/sql/merge.sql
@@ -1727,6 +1727,27 @@ MERGE INTO tgt USING src ON tgt.a IS NOT DISTINCT FROM src.a
SELECT * FROM tgt;
DROP TABLE src, tgt;
+
+--
+-- test for bug #18634 (wrong varnullingrels error)
+--
+CREATE TABLE bug18634t (a int, b int, c text);
+INSERT INTO bug18634t VALUES(1, 10, 'tgt1'), (2, 20, 'tgt2');
+CREATE VIEW bug18634v AS
+ SELECT * FROM bug18634t WHERE EXISTS (SELECT 1 FROM bug18634t);
+
+CREATE TABLE bug18634s (a int, b int, c text);
+INSERT INTO bug18634s VALUES (1, 2, 'src1');
+
+MERGE INTO bug18634v t USING bug18634s s ON s.a = t.a
+ WHEN MATCHED THEN UPDATE SET b = s.b
+ WHEN NOT MATCHED BY SOURCE THEN DELETE
+ RETURNING merge_action(), s.c, t.*;
+
+SELECT * FROM bug18634t;
+
+DROP TABLE bug18634t CASCADE;
+DROP TABLE bug18634s;
-- prepare