Adds find_recursive_union to ruleutils_15.c

Relevant PG commit:
3f50b82639637c9908afa2087de7588450aa866b
version-15-socket
naisila 2022-07-25 12:28:04 +03:00
parent 6da9798281
commit 445820d7de
1 changed files with 37 additions and 3 deletions

View File

@ -341,6 +341,8 @@ static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
deparse_columns *colinfo);
static char *get_rtable_name(int rtindex, deparse_context *context);
static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
static Plan *find_recursive_union(deparse_namespace *dpns,
WorkTableScan *wtscan);
static void push_child_plan(deparse_namespace *dpns, Plan *plan,
deparse_namespace *save_dpns);
static void pop_child_plan(deparse_namespace *dpns,
@ -1779,6 +1781,9 @@ set_deparse_plan(deparse_namespace *dpns, Plan *plan)
* For a SubqueryScan, pretend the subplan is INNER referent. (We don't
* use OUTER because that could someday conflict with the normal meaning.)
* Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
* For a WorkTableScan, locate the parent RecursiveUnion plan node and use
* that as INNER referent.
*
* For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
* excluded expression's tlist. (Similar to the SubqueryScan we don't want
* to reuse OUTER, it's used for RETURNING in some modify table cases,
@ -1789,6 +1794,9 @@ set_deparse_plan(deparse_namespace *dpns, Plan *plan)
else if (IsA(plan, CteScan))
dpns->inner_plan = list_nth(dpns->subplans,
((CteScan *) plan)->ctePlanId - 1);
else if (IsA(plan, WorkTableScan))
dpns->inner_plan = find_recursive_union(dpns,
(WorkTableScan *) plan);
else if (IsA(plan, ModifyTable))
dpns->inner_plan = plan;
else
@ -1812,6 +1820,29 @@ set_deparse_plan(deparse_namespace *dpns, Plan *plan)
dpns->index_tlist = NIL;
}
/*
* Locate the ancestor plan node that is the RecursiveUnion generating
* the WorkTableScan's work table. We can match on wtParam, since that
* should be unique within the plan tree.
*/
static Plan *
find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
{
ListCell *lc;
foreach(lc, dpns->ancestors)
{
Plan *ancestor = (Plan *) lfirst(lc);
if (IsA(ancestor, RecursiveUnion) &&
((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
return ancestor;
}
elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
wtscan->wtParam);
return NULL;
}
/*
* push_child_plan: temporarily transfer deparsing attention to a child plan
*
@ -4448,9 +4479,12 @@ get_name_for_var_field(Var *var, int fieldno,
{
/*
* We're deparsing a Plan tree so we don't have a CTE
* list. But the only place we'd see a Var directly
* referencing a CTE RTE is in a CteScan plan node, and we
* can look into the subplan's tlist instead.
* list. But the only places we'd see a Var directly
* referencing a CTE RTE are in CteScan or WorkTableScan
* plan nodes. For those cases, set_deparse_plan arranged
* for dpns->inner_plan to be the plan node that emits the
* CTE or RecursiveUnion result, and we can look at its
* tlist instead.
*/
TargetEntry *tle;
deparse_namespace save_dpns;