aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/setrefs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/setrefs.c')
-rw-r--r--src/backend/optimizer/plan/setrefs.c58
1 files changed, 54 insertions, 4 deletions
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index dee4414cec2..1382b679748 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -41,6 +41,9 @@ typedef struct
int num_vars; /* number of plain Var tlist entries */
bool has_ph_vars; /* are there PlaceHolderVar entries? */
bool has_non_vars; /* are there other entries? */
+ bool has_conv_whole_rows; /* are there ConvertRowtypeExpr
+ * entries encapsulating a whole-row
+ * Var? */
tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER]; /* has num_vars entries */
} indexed_tlist;
@@ -139,6 +142,7 @@ static List *set_returning_clause_references(PlannerInfo *root,
int rtoffset);
static bool extract_query_dependencies_walker(Node *node,
PlannerInfo *context);
+static bool is_converted_whole_row_reference(Node *node);
/*****************************************************************************
*
@@ -1944,6 +1948,7 @@ build_tlist_index(List *tlist)
itlist->tlist = tlist;
itlist->has_ph_vars = false;
itlist->has_non_vars = false;
+ itlist->has_conv_whole_rows = false;
/* Find the Vars and fill in the index array */
vinfo = itlist->vars;
@@ -1962,6 +1967,8 @@ build_tlist_index(List *tlist)
}
else if (tle->expr && IsA(tle->expr, PlaceHolderVar))
itlist->has_ph_vars = true;
+ else if (is_converted_whole_row_reference((Node *) tle->expr))
+ itlist->has_conv_whole_rows = true;
else
itlist->has_non_vars = true;
}
@@ -1977,7 +1984,10 @@ build_tlist_index(List *tlist)
* This is like build_tlist_index, but we only index tlist entries that
* are Vars belonging to some rel other than the one specified. We will set
* has_ph_vars (allowing PlaceHolderVars to be matched), but not has_non_vars
- * (so nothing other than Vars and PlaceHolderVars can be matched).
+ * (so nothing other than Vars and PlaceHolderVars can be matched). In case of
+ * DML, where this function will be used, returning lists from child relations
+ * will be appended similar to a simple append relation. That does not require
+ * fixing ConvertRowtypeExpr references. So, those are not considered here.
*/
static indexed_tlist *
build_tlist_index_other_vars(List *tlist, Index ignore_rel)
@@ -1994,6 +2004,7 @@ build_tlist_index_other_vars(List *tlist, Index ignore_rel)
itlist->tlist = tlist;
itlist->has_ph_vars = false;
itlist->has_non_vars = false;
+ itlist->has_conv_whole_rows = false;
/* Find the desired Vars and fill in the index array */
vinfo = itlist->vars;
@@ -2197,6 +2208,7 @@ static Node *
fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
{
Var *newvar;
+ bool converted_whole_row;
if (node == NULL)
return NULL;
@@ -2266,8 +2278,12 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
}
if (IsA(node, Param))
return fix_param_node(context->root, (Param *) node);
+
/* Try matching more complex expressions too, if tlists have any */
- if (context->outer_itlist && context->outer_itlist->has_non_vars)
+ converted_whole_row = is_converted_whole_row_reference(node);
+ if (context->outer_itlist &&
+ (context->outer_itlist->has_non_vars ||
+ (context->outer_itlist->has_conv_whole_rows && converted_whole_row)))
{
newvar = search_indexed_tlist_for_non_var((Expr *) node,
context->outer_itlist,
@@ -2275,7 +2291,9 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
if (newvar)
return (Node *) newvar;
}
- if (context->inner_itlist && context->inner_itlist->has_non_vars)
+ if (context->inner_itlist &&
+ (context->inner_itlist->has_non_vars ||
+ (context->inner_itlist->has_conv_whole_rows && converted_whole_row)))
{
newvar = search_indexed_tlist_for_non_var((Expr *) node,
context->inner_itlist,
@@ -2395,7 +2413,9 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
/* If no match, just fall through to process it normally */
}
/* Try matching more complex expressions too, if tlist has any */
- if (context->subplan_itlist->has_non_vars)
+ if (context->subplan_itlist->has_non_vars ||
+ (context->subplan_itlist->has_conv_whole_rows &&
+ is_converted_whole_row_reference(node)))
{
newvar = search_indexed_tlist_for_non_var((Expr *) node,
context->subplan_itlist,
@@ -2602,3 +2622,33 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context)
return expression_tree_walker(node, extract_query_dependencies_walker,
(void *) context);
}
+
+/*
+ * is_converted_whole_row_reference
+ * If the given node is a ConvertRowtypeExpr encapsulating a whole-row
+ * reference as implicit cast, return true. Otherwise return false.
+ */
+static bool
+is_converted_whole_row_reference(Node *node)
+{
+ ConvertRowtypeExpr *convexpr;
+
+ if (!node || !IsA(node, ConvertRowtypeExpr))
+ return false;
+
+ /* Traverse nested ConvertRowtypeExpr's. */
+ convexpr = castNode(ConvertRowtypeExpr, node);
+ while (convexpr->convertformat == COERCE_IMPLICIT_CAST &&
+ IsA(convexpr->arg, ConvertRowtypeExpr))
+ convexpr = castNode(ConvertRowtypeExpr, convexpr->arg);
+
+ if (IsA(convexpr->arg, Var))
+ {
+ Var *var = castNode(Var, convexpr->arg);
+
+ if (var->varattno == 0)
+ return true;
+ }
+
+ return false;
+}