From 3b2db22fe287d17ecb0ba4cd828dc7900dddd03f Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Mon, 24 Oct 2022 12:52:43 +0200 Subject: [PATCH] Update some comments that should've covered MERGE Oversight in 7103ebb7aae8. Backpatch to 15. Author: Richard Guo Discussion: https://postgr.es/m/CAMbWs48gnDjZXq3-b56dVpQCNUJ5hD9kdtWN4QFwKCEapspNsA@mail.gmail.com --- src/backend/optimizer/path/indxpath.c | 13 +++++++------ src/backend/optimizer/plan/planmain.c | 2 +- src/backend/optimizer/plan/planner.c | 4 ++-- src/backend/optimizer/util/appendinfo.c | 6 +++--- src/backend/optimizer/util/inherit.c | 2 +- src/backend/optimizer/util/pathnode.c | 3 ++- src/backend/optimizer/util/relnode.c | 2 +- src/backend/parser/parse_clause.c | 6 ++++-- src/backend/parser/parse_expr.c | 4 ++-- src/backend/parser/parse_merge.c | 6 +++++- src/include/nodes/parsenodes.h | 4 ++-- src/include/nodes/pathnodes.h | 16 ++++++++-------- src/include/nodes/plannodes.h | 4 ++-- src/include/nodes/primnodes.h | 4 ++-- 14 files changed, 42 insertions(+), 34 deletions(-) diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index c31fcc917d..77f3f81bcb 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -3393,12 +3393,13 @@ check_index_predicates(PlannerInfo *root, RelOptInfo *rel) * Normally we remove quals that are implied by a partial index's * predicate from indrestrictinfo, indicating that they need not be * checked explicitly by an indexscan plan using this index. However, if - * the rel is a target relation of UPDATE/DELETE/SELECT FOR UPDATE, we - * cannot remove such quals from the plan, because they need to be in the - * plan so that they will be properly rechecked by EvalPlanQual testing. - * Some day we might want to remove such quals from the main plan anyway - * and pass them through to EvalPlanQual via a side channel; but for now, - * we just don't remove implied quals at all for target relations. + * the rel is a target relation of UPDATE/DELETE/MERGE/SELECT FOR UPDATE, + * we cannot remove such quals from the plan, because they need to be in + * the plan so that they will be properly rechecked by EvalPlanQual + * testing. Some day we might want to remove such quals from the main + * plan anyway and pass them through to EvalPlanQual via a side channel; + * but for now, we just don't remove implied quals at all for target + * relations. */ is_target_rel = (bms_is_member(rel->relid, root->all_result_relids) || get_plan_rowmark(root->rowMarks, rel->relid) != NULL); diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 248cde4d9b..63deed27c9 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -266,7 +266,7 @@ query_planner(PlannerInfo *root, add_other_rels_to_query(root); /* - * Distribute any UPDATE/DELETE row identity variables to the target + * Distribute any UPDATE/DELETE/MERGE row identity variables to the target * relations. This can't be done till we've finished expansion of * appendrels. */ diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 5d0fd6e072..78a8174534 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -1749,7 +1749,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) if (bms_membership(root->all_result_relids) == BMS_MULTIPLE) { - /* Inherited UPDATE/DELETE */ + /* Inherited UPDATE/DELETE/MERGE */ RelOptInfo *top_result_rel = find_base_rel(root, parse->resultRelation); int resultRelation = -1; @@ -1876,7 +1876,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) } else { - /* Single-relation INSERT/UPDATE/DELETE. */ + /* Single-relation INSERT/UPDATE/DELETE/MERGE. */ resultRelations = list_make1_int(parse->resultRelation); if (parse->commandType == CMD_UPDATE) updateColnosLists = list_make1(root->update_colnos); diff --git a/src/backend/optimizer/util/appendinfo.c b/src/backend/optimizer/util/appendinfo.c index 62cccf9d87..f6fc62aa5d 100644 --- a/src/backend/optimizer/util/appendinfo.c +++ b/src/backend/optimizer/util/appendinfo.c @@ -730,7 +730,7 @@ find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos) /* * add_row_identity_var - * Register a row-identity column to be used in UPDATE/DELETE. + * Register a row-identity column to be used in UPDATE/DELETE/MERGE. * * The Var must be equal(), aside from varno, to any other row-identity * column with the same rowid_name. Thus, for example, "wholerow" @@ -909,8 +909,8 @@ add_row_identity_columns(PlannerInfo *root, Index rtindex, * distribute_row_identity_vars * * After we have finished identifying all the row identity columns - * needed by an inherited UPDATE/DELETE query, make sure that these - * columns will be generated by all the target relations. + * needed by an inherited UPDATE/DELETE/MERGE query, make sure that + * these columns will be generated by all the target relations. * * This is more or less like what build_base_rel_tlists() does, * except that it would not understand what to do with ROWID_VAR Vars. diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c index cf7691a474..3d270e91d6 100644 --- a/src/backend/optimizer/util/inherit.c +++ b/src/backend/optimizer/util/inherit.c @@ -609,7 +609,7 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, /* * If we are creating a child of the query target relation (only possible - * in UPDATE/DELETE), add it to all_result_relids, as well as + * in UPDATE/DELETE/MERGE), add it to all_result_relids, as well as * leaf_result_relids if appropriate, and make sure that we generate * required row-identity data. */ diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 70f61ae7b1..6dd11329fb 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -3630,7 +3630,8 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel, /* * create_modifytable_path - * Creates a pathnode that represents performing INSERT/UPDATE/DELETE mods + * Creates a pathnode that represents performing INSERT/UPDATE/DELETE/MERGE + * mods * * 'rel' is the parent relation associated with the result * 'subpath' is a Path producing source data diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index edcdd0a360..1786a3dadd 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -1013,7 +1013,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, if (var->varno == ROWID_VAR) { - /* UPDATE/DELETE row identity vars are always needed */ + /* UPDATE/DELETE/MERGE row identity vars are always needed */ RowIdentityVarInfo *ridinfo = (RowIdentityVarInfo *) list_nth(root->row_identity_vars, var->varattno - 1); diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index c2b5474f5f..e01c0734d1 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -153,7 +153,7 @@ transformFromClause(ParseState *pstate, List *frmList) /* * setTargetTable - * Add the target relation of INSERT/UPDATE/DELETE to the range table, + * Add the target relation of INSERT/UPDATE/DELETE/MERGE to the range table, * and make the special links to it in the ParseState. * * We also open the target relation and acquire a write lock on it. @@ -163,7 +163,9 @@ transformFromClause(ParseState *pstate, List *frmList) * * If alsoSource is true, add the target to the query's joinlist and * namespace. For INSERT, we don't want the target to be joined to; - * it's a destination of tuples, not a source. For UPDATE/DELETE, + * it's a destination of tuples, not a source. MERGE is actually + * both, but we'll add it separately to joinlist and namespace, so + * doing nothing (like INSERT) is correct here. For UPDATE/DELETE, * we do need to scan or join the target. (NOTE: we do not bother * to check for namespace conflict; we assume that the namespace was * initially empty in these cases.) diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 7aaf1c673f..e5fc708c8a 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -1679,8 +1679,8 @@ transformSubLink(ParseState *pstate, SubLink *sublink) /* * Check to see if the sublink is in an invalid place within the query. We - * allow sublinks everywhere in SELECT/INSERT/UPDATE/DELETE, but generally - * not in utility statements. + * allow sublinks everywhere in SELECT/INSERT/UPDATE/DELETE/MERGE, but + * generally not in utility statements. */ err = NULL; switch (pstate->p_expr_kind) diff --git a/src/backend/parser/parse_merge.c b/src/backend/parser/parse_merge.c index bb9d76306b..7913523b1c 100644 --- a/src/backend/parser/parse_merge.c +++ b/src/backend/parser/parse_merge.c @@ -163,7 +163,11 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt) errmsg("unreachable WHEN clause specified after unconditional WHEN clause"))); } - /* Set up the MERGE target table. */ + /* + * Set up the MERGE target table. The target table is added to the + * namespace below and to joinlist in transform_MERGE_to_join, so don't + * do it here. + */ qry->resultRelation = setTargetTable(pstate, stmt->relation, stmt->relation->inh, false, targetPerms); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 633e7671b3..7e7ad3f7e4 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1043,8 +1043,8 @@ typedef struct RangeTblEntry * * rellockmode is really LOCKMODE, but it's declared int to avoid having * to include lock-related headers here. It must be RowExclusiveLock if - * the RTE is an INSERT/UPDATE/DELETE target, else RowShareLock if the RTE - * is a SELECT FOR UPDATE/FOR SHARE target, else AccessShareLock. + * the RTE is an INSERT/UPDATE/DELETE/MERGE target, else RowShareLock if + * the RTE is a SELECT FOR UPDATE/FOR SHARE target, else AccessShareLock. * * Note: in some cases, rule expansion may result in RTEs that are marked * with RowExclusiveLock even though they are not the target of the diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index 6bda383bea..09342d128d 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -328,11 +328,11 @@ struct PlannerInfo /* * all_result_relids is empty for SELECT, otherwise it contains at least - * parse->resultRelation. For UPDATE/DELETE across an inheritance or - * partitioning tree, the result rel's child relids are added. When using - * multi-level partitioning, intermediate partitioned rels are included. - * leaf_result_relids is similar except that only actual result tables, - * not partitioned tables, are included in it. + * parse->resultRelation. For UPDATE/DELETE/MERGE across an inheritance + * or partitioning tree, the result rel's child relids are added. When + * using multi-level partitioning, intermediate partitioned rels are + * included. leaf_result_relids is similar except that only actual result + * tables, not partitioned tables, are included in it. */ /* set of all result relids */ Relids all_result_relids; @@ -2792,10 +2792,10 @@ typedef struct AppendRelInfo } AppendRelInfo; /* - * Information about a row-identity "resjunk" column in UPDATE/DELETE. + * Information about a row-identity "resjunk" column in UPDATE/DELETE/MERGE. * - * In partitioned UPDATE/DELETE it's important for child partitions to share - * row-identity columns whenever possible, so as not to chew up too many + * In partitioned UPDATE/DELETE/MERGE it's important for child partitions to + * share row-identity columns whenever possible, so as not to chew up too many * targetlist columns. We use these structs to track which identity columns * have been requested. In the finished plan, each of these will give rise * to one resjunk entry in the targetlist of the ModifyTable's subplan node. diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 21e642a64c..5c2ab1b379 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -72,7 +72,7 @@ typedef struct PlannedStmt List *rtable; /* list of RangeTblEntry nodes */ - /* rtable indexes of target relations for INSERT/UPDATE/DELETE */ + /* rtable indexes of target relations for INSERT/UPDATE/DELETE/MERGE */ List *resultRelations; /* integer list of RT indexes, or NIL */ List *appendRelations; /* list of AppendRelInfo nodes */ @@ -217,7 +217,7 @@ typedef struct ProjectSet * nominalRelation and rootRelation contain the RT index of the partition * root, which is not otherwise mentioned in the plan. Otherwise rootRelation * is zero. However, nominalRelation will always be set, as it's the rel that - * EXPLAIN should claim is the INSERT/UPDATE/DELETE target. + * EXPLAIN should claim is the INSERT/UPDATE/DELETE/MERGE target. * * Note that rowMarks and epqParam are presumed to be valid for all the * table(s); they can't contain any info that varies across tables. diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 40661334bb..f71f551782 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -177,8 +177,8 @@ typedef struct Expr * is abused to signify references to columns of a custom scan tuple type.) * * ROWID_VAR is used in the planner to identify nonce variables that carry - * row identity information during UPDATE/DELETE. This value should never - * be seen outside the planner. + * row identity information during UPDATE/DELETE/MERGE. This value should + * never be seen outside the planner. * * In the parser, varnosyn and varattnosyn are either identical to * varno/varattno, or they specify the column's position in an aliased JOIN