diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 282589dec81..74823e8437a 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -2279,8 +2279,8 @@ pullup_replace_vars_callback(Var *var, * If generating an expansion for a var of a named rowtype (ie, this * is a plain relation RTE), then we must include dummy items for * dropped columns. If the var is RECORD (ie, this is a JOIN), then - * omit dropped columns. Either way, attach column names to the - * RowExpr for use of ruleutils.c. + * omit dropped columns. In the latter case, attach column names to + * the RowExpr for use of the executor and ruleutils.c. * * In order to be able to cache the results, we always generate the * expansion with varlevelsup = 0, and then adjust if needed. @@ -2301,7 +2301,7 @@ pullup_replace_vars_callback(Var *var, rowexpr->args = fields; rowexpr->row_typeid = var->vartype; rowexpr->row_format = COERCE_IMPLICIT_CAST; - rowexpr->colnames = colnames; + rowexpr->colnames = (var->vartype == RECORDOID) ? colnames : NIL; rowexpr->location = var->location; newnode = (Node *) rowexpr; diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index a0543b7f47b..2b44ef3e176 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -809,6 +809,7 @@ flatten_join_alias_vars_mutator(Node *node, rowexpr->args = fields; rowexpr->row_typeid = var->vartype; rowexpr->row_format = COERCE_IMPLICIT_CAST; + /* vartype will always be RECORDOID, so we always need colnames */ rowexpr->colnames = colnames; rowexpr->location = var->location; diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index 708e5453e31..101c39553ae 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -1424,8 +1424,8 @@ ReplaceVarsFromTargetList_callback(Var *var, * If generating an expansion for a var of a named rowtype (ie, this * is a plain relation RTE), then we must include dummy items for * dropped columns. If the var is RECORD (ie, this is a JOIN), then - * omit dropped columns. Either way, attach column names to the - * RowExpr for use of ruleutils.c. + * omit dropped columns. In the latter case, attach column names to + * the RowExpr for use of the executor and ruleutils.c. */ expandRTE(rcon->target_rte, var->varno, var->varlevelsup, var->location, @@ -1438,7 +1438,7 @@ ReplaceVarsFromTargetList_callback(Var *var, rowexpr->args = fields; rowexpr->row_typeid = var->vartype; rowexpr->row_format = COERCE_IMPLICIT_CAST; - rowexpr->colnames = colnames; + rowexpr->colnames = (var->vartype == RECORDOID) ? colnames : NIL; rowexpr->location = var->location; return (Node *) rowexpr; diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index dab5c4ff5de..439e4b4a9db 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -1052,15 +1052,13 @@ typedef struct ArrayExpr * than vice versa.) It is important not to assume that length(args) is * the same as the number of columns logically present in the rowtype. * - * colnames provides field names in cases where the names can't easily be - * obtained otherwise. Names *must* be provided if row_typeid is RECORDOID. - * If row_typeid identifies a known composite type, colnames can be NIL to - * indicate the type's cataloged field names apply. Note that colnames can - * be non-NIL even for a composite type, and typically is when the RowExpr - * was created by expanding a whole-row Var. This is so that we can retain - * the column alias names of the RTE that the Var referenced (which would - * otherwise be very difficult to extract from the parsetree). Like the - * args list, colnames is one-for-one with physical fields of the rowtype. + * colnames provides field names if the ROW() result is of type RECORD. + * Names *must* be provided if row_typeid is RECORDOID; but if it is a + * named composite type, colnames will be ignored in favor of using the + * type's cataloged field names, so colnames should be NIL. Like the + * args list, colnames is defined to be one-for-one with physical fields + * of the rowtype (although dropped columns shouldn't appear in the + * RECORD case, so this fine point is currently moot). */ typedef struct RowExpr {