aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/initsplan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/initsplan.c')
-rw-r--r--src/backend/optimizer/plan/initsplan.c62
1 files changed, 61 insertions, 1 deletions
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 3c7fa632b8e..4481db5c341 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -204,6 +204,64 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars,
}
}
+/*
+ * extract_lateral_references
+ * If the specified RTE is a LATERAL subquery, extract all its references
+ * to Vars of the current query level, and make sure those Vars will be
+ * available for evaluation of the RTE.
+ *
+ * XXX this is rather duplicative of processing that has to happen elsewhere.
+ * Maybe it'd be a good idea to do this type of extraction further upstream
+ * and save the results?
+ */
+static void
+extract_lateral_references(PlannerInfo *root, int rtindex)
+{
+ RangeTblEntry *rte = root->simple_rte_array[rtindex];
+ List *vars;
+ List *newvars;
+ Relids where_needed;
+ ListCell *lc;
+
+ /* No cross-references are possible if it's not LATERAL */
+ if (!rte->lateral)
+ return;
+
+ /* Fetch the appropriate variables */
+ if (rte->rtekind == RTE_SUBQUERY)
+ vars = pull_vars_of_level((Node *) rte->subquery, 1);
+ else if (rte->rtekind == RTE_FUNCTION)
+ vars = pull_vars_of_level(rte->funcexpr, 0);
+ else
+ return;
+
+ /* Copy each Var and adjust it to match our level */
+ newvars = NIL;
+ foreach(lc, vars)
+ {
+ Var *var = (Var *) lfirst(lc);
+
+ var = copyObject(var);
+ var->varlevelsup = 0;
+ newvars = lappend(newvars, var);
+ }
+
+ /*
+ * We mark the Vars as being "needed" at the LATERAL RTE. This is a bit
+ * of a cheat: a more formal approach would be to mark each one as needed
+ * at the join of the LATERAL RTE with its source RTE. But it will work,
+ * and it's much less tedious than computing a separate where_needed for
+ * each Var.
+ */
+ where_needed = bms_make_singleton(rtindex);
+
+ /* Push the Vars into their source relations' targetlists */
+ add_vars_to_targetlist(root, newvars, where_needed, false);
+
+ list_free(newvars);
+ list_free(vars);
+}
+
/*****************************************************************************
*
@@ -286,7 +344,9 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
- /* No quals to deal with, just return correct result */
+ /* No quals to deal with, but do check for LATERAL subqueries */
+ extract_lateral_references(root, varno);
+ /* Result qualscope is just the one Relid */
*qualscope = bms_make_singleton(varno);
/* A single baserel does not create an inner join */
*inner_join_rels = NULL;