Update ruleutils_13.c with postgres ruleutils

Some manual updates are done for ruleutils_13 based on the difference
between pg12 ruleutils and pg13 ruleutils.
pull/3900/head
Sait Talha Nisanci 2020-05-28 12:26:31 +03:00
parent 30549dc0e2
commit 8ce8683ac4
1 changed files with 215 additions and 111 deletions

View File

@ -132,7 +132,8 @@ typedef struct
int64 shardid; /* a distributed table's shardid, if positive */ int64 shardid; /* a distributed table's shardid, if positive */
ParseExprKind special_exprkind; /* set only for exprkinds needing special ParseExprKind special_exprkind; /* set only for exprkinds needing special
* handling */ * handling */
Bitmapset *appendparents; Bitmapset *appendparents; /* if not null, map child Vars of these relids
* back to the parent rel */
} deparse_context; } deparse_context;
/* /*
@ -167,20 +168,26 @@ typedef struct
List *rtable; /* List of RangeTblEntry nodes */ List *rtable; /* List of RangeTblEntry nodes */
List *rtable_names; /* Parallel list of names for RTEs */ List *rtable_names; /* Parallel list of names for RTEs */
List *rtable_columns; /* Parallel list of deparse_columns structs */ List *rtable_columns; /* Parallel list of deparse_columns structs */
List *subplans; /* List of Plan trees for SubPlans */
List *ctes; /* List of CommonTableExpr nodes */ List *ctes; /* List of CommonTableExpr nodes */
AppendRelInfo **appendrels; /* Array of AppendRelInfo nodes, or NULL */
/* Workspace for column alias assignment: */ /* Workspace for column alias assignment: */
bool unique_using; /* Are we making USING names globally unique */ bool unique_using; /* Are we making USING names globally unique */
List *using_names; /* List of assigned names for USING columns */ List *using_names; /* List of assigned names for USING columns */
/* Remaining fields are used only when deparsing a Plan tree: */ /* Remaining fields are used only when deparsing a Plan tree: */
PlanState *planstate; /* immediate parent of current expression */ Plan *plan; /* immediate parent of current expression */
List *ancestors; /* ancestors of planstate */ List *ancestors; /* ancestors of planstate */
PlanState *outer_planstate; /* outer subplan state, or NULL if none */ Plan *outer_plan; /* outer subnode, or NULL if none */
PlanState *inner_planstate; /* inner subplan state, or NULL if none */ Plan *inner_plan; /* inner subnode, or NULL if none */
List *outer_tlist; /* referent for OUTER_VAR Vars */ List *outer_tlist; /* referent for OUTER_VAR Vars */
List *inner_tlist; /* referent for INNER_VAR Vars */ List *inner_tlist; /* referent for INNER_VAR Vars */
List *index_tlist; /* referent for INDEX_VAR Vars */ List *index_tlist; /* referent for INDEX_VAR Vars */
} deparse_namespace; } deparse_namespace;
/* Callback signature for resolve_special_varno() */
typedef void (*rsv_callback) (Node *node, deparse_context *context,
void *callback_arg);
/* /*
* Per-relation data about column alias names. * Per-relation data about column alias names.
* *
@ -333,8 +340,8 @@ static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
static void flatten_join_using_qual(Node *qual, static void flatten_join_using_qual(Node *qual,
List **leftvars, List **rightvars); List **leftvars, List **rightvars);
static char *get_rtable_name(int rtindex, deparse_context *context); static char *get_rtable_name(int rtindex, deparse_context *context);
static void set_deparse_planstate(deparse_namespace *dpns, PlanState *ps); static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
static void push_child_plan(deparse_namespace *dpns, PlanState *ps, static void push_child_plan(deparse_namespace *dpns, Plan *plan,
deparse_namespace *save_dpns); deparse_namespace *save_dpns);
static void pop_child_plan(deparse_namespace *dpns, static void pop_child_plan(deparse_namespace *dpns,
deparse_namespace *save_dpns); deparse_namespace *save_dpns);
@ -380,10 +387,9 @@ static void get_rule_windowspec(WindowClause *wc, List *targetList,
static char *get_variable(Var *var, int levelsup, bool istoplevel, static char *get_variable(Var *var, int levelsup, bool istoplevel,
deparse_context *context); deparse_context *context);
static void get_special_variable(Node *node, deparse_context *context, static void get_special_variable(Node *node, deparse_context *context,
void *private); void *callback_arg);
static void resolve_special_varno(Node *node, deparse_context *context, static void resolve_special_varno(Node *node, deparse_context *context,
void *private, rsv_callback callback, void *callback_arg);
void (*callback) (Node *, deparse_context *, void *));
static Node *find_param_referent(Param *param, deparse_context *context, static Node *find_param_referent(Param *param, deparse_context *context,
deparse_namespace **dpns_p, ListCell **ancestor_cell_p); deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
static void get_parameter(Param *param, deparse_context *context); static void get_parameter(Param *param, deparse_context *context);
@ -405,7 +411,7 @@ static void get_func_expr(FuncExpr *expr, deparse_context *context,
static void get_agg_expr(Aggref *aggref, deparse_context *context, static void get_agg_expr(Aggref *aggref, deparse_context *context,
Aggref *original_aggref); Aggref *original_aggref);
static void get_agg_combine_expr(Node *node, deparse_context *context, static void get_agg_combine_expr(Node *node, deparse_context *context,
void *private); void *callback_arg);
static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context); static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
static void get_coercion_expr(Node *arg, deparse_context *context, static void get_coercion_expr(Node *arg, deparse_context *context,
Oid resulttype, int32 resulttypmod, Oid resulttype, int32 resulttypmod,
@ -672,7 +678,9 @@ set_deparse_for_query(deparse_namespace *dpns, Query *query,
/* Initialize *dpns and fill rtable/ctes links */ /* Initialize *dpns and fill rtable/ctes links */
memset(dpns, 0, sizeof(deparse_namespace)); memset(dpns, 0, sizeof(deparse_namespace));
dpns->rtable = query->rtable; dpns->rtable = query->rtable;
dpns->subplans = NIL;
dpns->ctes = query->cteList; dpns->ctes = query->cteList;
dpns->appendrels = NULL;
/* Assign a unique relation alias to each RTE */ /* Assign a unique relation alias to each RTE */
set_rtable_names(dpns, parent_namespaces, NULL); set_rtable_names(dpns, parent_namespaces, NULL);
@ -1710,19 +1718,19 @@ get_rtable_name(int rtindex, deparse_context *context)
} }
/* /*
* set_deparse_planstate: set up deparse_namespace to parse subexpressions * set_deparse_plan: set up deparse_namespace to parse subexpressions
* of a given PlanState node * of a given Plan node
* *
* This sets the planstate, outer_planstate, inner_planstate, outer_tlist, * This sets the plan, outer_planstate, inner_planstate, outer_tlist,
* inner_tlist, and index_tlist fields. Caller is responsible for adjusting * inner_tlist, and index_tlist fields. Caller is responsible for adjusting
* the ancestors list if necessary. Note that the rtable and ctes fields do * the ancestors list if necessary. Note that the rtable and ctes fields do
* not need to change when shifting attention to different plan nodes in a * not need to change when shifting attention to different plan nodes in a
* single plan tree. * single plan tree.
*/ */
static void static void
set_deparse_planstate(deparse_namespace *dpns, PlanState *ps) set_deparse_plan(deparse_namespace *dpns, Plan *plan)
{ {
dpns->planstate = ps; dpns->plan = plan;
/* /*
* We special-case Append and MergeAppend to pretend that the first child * We special-case Append and MergeAppend to pretend that the first child
@ -1732,17 +1740,17 @@ set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
* first child plan is the OUTER referent; this is to support RETURNING * first child plan is the OUTER referent; this is to support RETURNING
* lists containing references to non-target relations. * lists containing references to non-target relations.
*/ */
if (IsA(ps, AppendState)) if (IsA(plan, Append))
dpns->outer_planstate = ((AppendState *) ps)->appendplans[0]; dpns->outer_plan = linitial(((Append *) plan)->appendplans);
else if (IsA(ps, MergeAppendState)) else if (IsA(plan, MergeAppend))
dpns->outer_planstate = ((MergeAppendState *) ps)->mergeplans[0]; dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
else if (IsA(ps, ModifyTableState)) else if (IsA(plan, ModifyTable))
dpns->outer_planstate = ((ModifyTableState *) ps)->mt_plans[0]; dpns->outer_plan = linitial(((ModifyTable *) plan)->plans);
else else
dpns->outer_planstate = outerPlanState(ps); dpns->outer_plan = outerPlan(plan);
if (dpns->outer_planstate) if (dpns->outer_plan)
dpns->outer_tlist = dpns->outer_planstate->plan->targetlist; dpns->outer_tlist = dpns->outer_plan->targetlist;
else else
dpns->outer_tlist = NIL; dpns->outer_tlist = NIL;
@ -1755,29 +1763,30 @@ set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
* to reuse OUTER, it's used for RETURNING in some modify table cases, * to reuse OUTER, it's used for RETURNING in some modify table cases,
* although not INSERT .. CONFLICT). * although not INSERT .. CONFLICT).
*/ */
if (IsA(ps, SubqueryScanState)) if (IsA(plan, SubqueryScan))
dpns->inner_planstate = ((SubqueryScanState *) ps)->subplan; dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
else if (IsA(ps, CteScanState)) else if (IsA(plan, CteScan))
dpns->inner_planstate = ((CteScanState *) ps)->cteplanstate; dpns->inner_plan = list_nth(dpns->subplans,
else if (IsA(ps, ModifyTableState)) ((CteScan *) plan)->ctePlanId - 1);
dpns->inner_planstate = ps; else if (IsA(plan, ModifyTable))
dpns->inner_plan = plan;
else else
dpns->inner_planstate = innerPlanState(ps); dpns->inner_plan = innerPlan(plan);
if (IsA(ps, ModifyTableState)) if (IsA(plan, ModifyTable))
dpns->inner_tlist = ((ModifyTableState *) ps)->mt_excludedtlist; dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
else if (dpns->inner_planstate) else if (dpns->inner_plan)
dpns->inner_tlist = dpns->inner_planstate->plan->targetlist; dpns->inner_tlist = dpns->inner_plan->targetlist;
else else
dpns->inner_tlist = NIL; dpns->inner_tlist = NIL;
/* Set up referent for INDEX_VAR Vars, if needed */ /* Set up referent for INDEX_VAR Vars, if needed */
if (IsA(ps->plan, IndexOnlyScan)) if (IsA(plan, IndexOnlyScan))
dpns->index_tlist = ((IndexOnlyScan *) ps->plan)->indextlist; dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
else if (IsA(ps->plan, ForeignScan)) else if (IsA(plan, ForeignScan))
dpns->index_tlist = ((ForeignScan *) ps->plan)->fdw_scan_tlist; dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
else if (IsA(ps->plan, CustomScan)) else if (IsA(plan, CustomScan))
dpns->index_tlist = ((CustomScan *) ps->plan)->custom_scan_tlist; dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
else else
dpns->index_tlist = NIL; dpns->index_tlist = NIL;
} }
@ -1795,17 +1804,17 @@ set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
* previous state for pop_child_plan. * previous state for pop_child_plan.
*/ */
static void static void
push_child_plan(deparse_namespace *dpns, PlanState *ps, push_child_plan(deparse_namespace *dpns, Plan *plan,
deparse_namespace *save_dpns) deparse_namespace *save_dpns)
{ {
/* Save state for restoration later */ /* Save state for restoration later */
*save_dpns = *dpns; *save_dpns = *dpns;
/* Link current plan node into ancestors list */ /* Link current plan node into ancestors list */
dpns->ancestors = lcons(dpns->planstate, dpns->ancestors); dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
/* Set attention on selected child */ /* Set attention on selected child */
set_deparse_planstate(dpns, ps); set_deparse_plan(dpns, plan);
} }
/* /*
@ -1960,6 +1969,7 @@ get_query_def_extended(Query *query, StringInfo buf, List *parentnamespace,
context.wrapColumn = wrapColumn; context.wrapColumn = wrapColumn;
context.indentLevel = startIndent; context.indentLevel = startIndent;
context.special_exprkind = EXPR_KIND_NONE; context.special_exprkind = EXPR_KIND_NONE;
context.appendparents = NULL;
context.distrelid = distrelid; context.distrelid = distrelid;
context.shardid = shardid; context.shardid = shardid;
@ -2246,10 +2256,11 @@ get_select_query_def(Query *query, deparse_context *context,
* if so, return the VALUES RTE. Otherwise return NULL. * if so, return the VALUES RTE. Otherwise return NULL.
*/ */
static RangeTblEntry * static RangeTblEntry *
get_simple_values_rte(Query *query) get_simple_values_rte(Query *query, TupleDesc resultDesc)
{ {
RangeTblEntry *result = NULL; RangeTblEntry *result = NULL;
ListCell *lc; ListCell *lc;
int colno;
/* /*
* We want to return true even if the Query also contains OLD or NEW rule * We want to return true even if the Query also contains OLD or NEW rule
@ -2286,14 +2297,24 @@ get_simple_values_rte(Query *query)
if (list_length(query->targetList) != list_length(result->eref->colnames)) if (list_length(query->targetList) != list_length(result->eref->colnames))
return NULL; /* this probably cannot happen */ return NULL; /* this probably cannot happen */
colno = 0;
forboth(lc, query->targetList, lcn, result->eref->colnames) forboth(lc, query->targetList, lcn, result->eref->colnames)
{ {
TargetEntry *tle = (TargetEntry *) lfirst(lc); TargetEntry *tle = (TargetEntry *) lfirst(lc);
char *cname = strVal(lfirst(lcn)); char *cname = strVal(lfirst(lcn));
char *colname;
if (tle->resjunk) if (tle->resjunk)
return NULL; /* this probably cannot happen */ return NULL; /* this probably cannot happen */
if (tle->resname == NULL || strcmp(tle->resname, cname) != 0) /* compute name that get_target_list would use for column */
colno++;
if (resultDesc && colno <= resultDesc->natts)
colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
else
colname = tle->resname;
/* does it match the VALUES RTE? */
if (colname == NULL || strcmp(colname, cname) != 0)
return NULL; /* column name has been changed */ return NULL; /* column name has been changed */
} }
} }
@ -2321,7 +2342,7 @@ get_basic_select_query(Query *query, deparse_context *context,
* VALUES part. This reverses what transformValuesClause() did at parse * VALUES part. This reverses what transformValuesClause() did at parse
* time. * time.
*/ */
values_rte = get_simple_values_rte(query); values_rte = get_simple_values_rte(query, resultDesc);
if (values_rte) if (values_rte)
{ {
get_values_def(values_rte->values_lists, context); get_values_def(values_rte->values_lists, context);
@ -3644,15 +3665,62 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
*/ */
if (var->varno >= 1 && var->varno <= list_length(dpns->rtable)) if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
{ {
rte = rt_fetch(var->varno, dpns->rtable); Index varno = var->varno;
refname = (char *) list_nth(dpns->rtable_names, var->varno - 1); AttrNumber varattno = var->varattno;
colinfo = deparse_columns_fetch(var->varno, dpns); /*
attnum = var->varattno; * We might have been asked to map child Vars to some parent relation.
*/
if (context->appendparents && dpns->appendrels)
{
Index pvarno = varno;
AttrNumber pvarattno = varattno;
AppendRelInfo *appinfo = dpns->appendrels[pvarno];
bool found = false;
/* Only map up to inheritance parents, not UNION ALL appendrels */
while (appinfo &&
rt_fetch(appinfo->parent_relid,
dpns->rtable)->rtekind == RTE_RELATION)
{
found = false;
if (pvarattno > 0) /* system columns stay as-is */
{
if (pvarattno > appinfo->num_child_cols)
break; /* safety check */
pvarattno = appinfo->parent_colnos[pvarattno - 1];
if (pvarattno == 0)
break; /* Var is local to child */
}
pvarno = appinfo->parent_relid;
found = true;
/* If the parent is itself a child, continue up. */
Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
appinfo = dpns->appendrels[pvarno];
}
/*
* If we found an ancestral rel, and that rel is included in
* appendparents, print that column not the original one.
*/
if (found && bms_is_member(pvarno, context->appendparents))
{
varno = pvarno;
varattno = pvarattno;
}
}
rte = rt_fetch(varno, dpns->rtable);
refname = (char *) list_nth(dpns->rtable_names, varno - 1);
colinfo = deparse_columns_fetch(varno, dpns);
attnum = varattno;
} }
else else
{ {
resolve_special_varno((Node *) var, context, NULL, resolve_special_varno((Node *) var, context, get_special_variable,
get_special_variable); NULL);
return NULL; return NULL;
} }
@ -3665,22 +3733,22 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
* no alias. So in that case, drill down to the subplan and print the * no alias. So in that case, drill down to the subplan and print the
* contents of the referenced tlist item. This works because in a plan * contents of the referenced tlist item. This works because in a plan
* tree, such Vars can only occur in a SubqueryScan or CteScan node, and * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
* we'll have set dpns->inner_planstate to reference the child plan node. * we'll have set dpns->inner_plan to reference the child plan node.
*/ */
if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) && if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
attnum > list_length(rte->eref->colnames) && attnum > list_length(rte->eref->colnames) &&
dpns->inner_planstate) dpns->inner_plan)
{ {
TargetEntry *tle; TargetEntry *tle;
deparse_namespace save_dpns; deparse_namespace save_dpns;
tle = get_tle_by_resno(dpns->inner_tlist, var->varattno); tle = get_tle_by_resno(dpns->inner_tlist, attnum);
if (!tle) if (!tle)
elog(ERROR, "invalid attnum %d for relation \"%s\"", elog(ERROR, "invalid attnum %d for relation \"%s\"",
var->varattno, rte->eref->aliasname); attnum, rte->eref->aliasname);
Assert(netlevelsup == 0); Assert(netlevelsup == 0);
push_child_plan(dpns, dpns->inner_planstate, &save_dpns); push_child_plan(dpns, dpns->inner_plan, &save_dpns);
/* /*
* Force parentheses because our caller probably assumed a Var is a * Force parentheses because our caller probably assumed a Var is a
@ -3796,13 +3864,13 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
* get_rule_expr. * get_rule_expr.
*/ */
static void static void
get_special_variable(Node *node, deparse_context *context, void *private) get_special_variable(Node *node, deparse_context *context, void *callback_arg)
{ {
StringInfo buf = context->buf; StringInfo buf = context->buf;
/* /*
* Force parentheses because our caller probably assumed a Var is a simple * For a non-Var referent, force parentheses because our caller probably
* expression. * assumed a Var is a simple expression.
*/ */
if (!IsA(node, Var)) if (!IsA(node, Var))
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
@ -3817,16 +3885,18 @@ get_special_variable(Node *node, deparse_context *context, void *private)
* invoke the callback provided. * invoke the callback provided.
*/ */
static void static void
resolve_special_varno(Node *node, deparse_context *context, void *private, resolve_special_varno(Node *node, deparse_context *context, rsv_callback callback, void *callback_arg)
void (*callback) (Node *, deparse_context *, void *))
{ {
Var *var; Var *var;
deparse_namespace *dpns; deparse_namespace *dpns;
/* This function is recursive, so let's be paranoid. */
check_stack_depth();
/* If it's not a Var, invoke the callback. */ /* If it's not a Var, invoke the callback. */
if (!IsA(node, Var)) if (!IsA(node, Var))
{ {
callback(node, context, private); (*callback) (node, context, callback_arg);
return; return;
} }
@ -3842,14 +3912,30 @@ resolve_special_varno(Node *node, deparse_context *context, void *private,
{ {
TargetEntry *tle; TargetEntry *tle;
deparse_namespace save_dpns; deparse_namespace save_dpns;
Bitmapset *save_appendparents;
tle = get_tle_by_resno(dpns->outer_tlist, var->varattno); tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
if (!tle) if (!tle)
elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno); elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
push_child_plan(dpns, dpns->outer_planstate, &save_dpns); /* If we're descending to the first child of an Append or MergeAppend,
resolve_special_varno((Node *) tle->expr, context, private, callback); * update appendparents. This will affect deparsing of all Vars
* appearing within the eventually-resolved subexpression.
*/
save_appendparents = context->appendparents;
if (IsA(dpns->plan, Append))
context->appendparents = bms_union(context->appendparents,
((Append *) dpns->plan)->apprelids);
else if (IsA(dpns->plan, MergeAppend))
context->appendparents = bms_union(context->appendparents,
((MergeAppend *) dpns->plan)->apprelids);
push_child_plan(dpns, dpns->outer_plan, &save_dpns);
resolve_special_varno((Node *) tle->expr, context,
callback, callback_arg);
pop_child_plan(dpns, &save_dpns); pop_child_plan(dpns, &save_dpns);
context->appendparents = save_appendparents;
return; return;
} }
else if (var->varno == INNER_VAR && dpns->inner_tlist) else if (var->varno == INNER_VAR && dpns->inner_tlist)
@ -3861,8 +3947,8 @@ resolve_special_varno(Node *node, deparse_context *context, void *private,
if (!tle) if (!tle)
elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno); elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
push_child_plan(dpns, dpns->inner_planstate, &save_dpns); push_child_plan(dpns, dpns->inner_plan, &save_dpns);
resolve_special_varno((Node *) tle->expr, context, private, callback); resolve_special_varno((Node *) tle->expr, context, callback, callback_arg);
pop_child_plan(dpns, &save_dpns); pop_child_plan(dpns, &save_dpns);
return; return;
} }
@ -3874,14 +3960,14 @@ resolve_special_varno(Node *node, deparse_context *context, void *private,
if (!tle) if (!tle)
elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno); elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
resolve_special_varno((Node *) tle->expr, context, private, callback); resolve_special_varno((Node *) tle->expr, context, callback, callback_arg);
return; return;
} }
else if (var->varno < 1 || var->varno > list_length(dpns->rtable)) else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
elog(ERROR, "bogus varno: %d", var->varno); elog(ERROR, "bogus varno: %d", var->varno);
/* Not special. Just invoke the callback. */ /* Not special. Just invoke the callback. */
callback(node, context, private); (*callback) (node, context, callback_arg);
} }
/* /*
@ -3989,7 +4075,7 @@ get_name_for_var_field(Var *var, int fieldno,
elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno); elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
Assert(netlevelsup == 0); Assert(netlevelsup == 0);
push_child_plan(dpns, dpns->outer_planstate, &save_dpns); push_child_plan(dpns, dpns->outer_plan, &save_dpns);
result = get_name_for_var_field((Var *) tle->expr, fieldno, result = get_name_for_var_field((Var *) tle->expr, fieldno,
levelsup, context); levelsup, context);
@ -4008,7 +4094,7 @@ get_name_for_var_field(Var *var, int fieldno,
elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno); elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
Assert(netlevelsup == 0); Assert(netlevelsup == 0);
push_child_plan(dpns, dpns->inner_planstate, &save_dpns); push_child_plan(dpns, dpns->inner_plan, &save_dpns);
result = get_name_for_var_field((Var *) tle->expr, fieldno, result = get_name_for_var_field((Var *) tle->expr, fieldno,
levelsup, context); levelsup, context);
@ -4118,7 +4204,7 @@ get_name_for_var_field(Var *var, int fieldno,
deparse_namespace save_dpns; deparse_namespace save_dpns;
const char *result; const char *result;
if (!dpns->inner_planstate) if (!dpns->inner_plan)
elog(ERROR, "failed to find plan for subquery %s", elog(ERROR, "failed to find plan for subquery %s",
rte->eref->aliasname); rte->eref->aliasname);
tle = get_tle_by_resno(dpns->inner_tlist, attnum); tle = get_tle_by_resno(dpns->inner_tlist, attnum);
@ -4126,7 +4212,7 @@ get_name_for_var_field(Var *var, int fieldno,
elog(ERROR, "bogus varattno for subquery var: %d", elog(ERROR, "bogus varattno for subquery var: %d",
attnum); attnum);
Assert(netlevelsup == 0); Assert(netlevelsup == 0);
push_child_plan(dpns, dpns->inner_planstate, &save_dpns); push_child_plan(dpns, dpns->inner_plan, &save_dpns);
result = get_name_for_var_field((Var *) tle->expr, fieldno, result = get_name_for_var_field((Var *) tle->expr, fieldno,
levelsup, context); levelsup, context);
@ -4236,7 +4322,7 @@ get_name_for_var_field(Var *var, int fieldno,
deparse_namespace save_dpns; deparse_namespace save_dpns;
const char *result; const char *result;
if (!dpns->inner_planstate) if (!dpns->inner_plan)
elog(ERROR, "failed to find plan for CTE %s", elog(ERROR, "failed to find plan for CTE %s",
rte->eref->aliasname); rte->eref->aliasname);
tle = get_tle_by_resno(dpns->inner_tlist, attnum); tle = get_tle_by_resno(dpns->inner_tlist, attnum);
@ -4244,7 +4330,7 @@ get_name_for_var_field(Var *var, int fieldno,
elog(ERROR, "bogus varattno for subquery var: %d", elog(ERROR, "bogus varattno for subquery var: %d",
attnum); attnum);
Assert(netlevelsup == 0); Assert(netlevelsup == 0);
push_child_plan(dpns, dpns->inner_planstate, &save_dpns); push_child_plan(dpns, dpns->inner_plan, &save_dpns);
result = get_name_for_var_field((Var *) tle->expr, fieldno, result = get_name_for_var_field((Var *) tle->expr, fieldno,
levelsup, context); levelsup, context);
@ -4285,22 +4371,22 @@ find_param_referent(Param *param, deparse_context *context,
/* /*
* If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
* SubPlan argument. This will necessarily be in some ancestor of the * SubPlan argument. This will necessarily be in some ancestor of the
* current expression's PlanState. * current expression's Plan.
*/ */
if (param->paramkind == PARAM_EXEC) if (param->paramkind == PARAM_EXEC)
{ {
deparse_namespace *dpns; deparse_namespace *dpns;
PlanState *child_ps; Plan *child_plan;
bool in_same_plan_level; bool in_same_plan_level;
ListCell *lc; ListCell *lc;
dpns = (deparse_namespace *) linitial(context->namespaces); dpns = (deparse_namespace *) linitial(context->namespaces);
child_ps = dpns->planstate; child_plan = dpns->plan;
in_same_plan_level = true; in_same_plan_level = true;
foreach(lc, dpns->ancestors) foreach(lc, dpns->ancestors)
{ {
PlanState *ps = (PlanState *) lfirst(lc); Node *ancestor = (Node *) lfirst(lc);
ListCell *lc2; ListCell *lc2;
/* /*
@ -4308,11 +4394,11 @@ find_param_referent(Param *param, deparse_context *context,
* we've crawled up out of a subplan, this couldn't possibly be * we've crawled up out of a subplan, this couldn't possibly be
* the right match. * the right match.
*/ */
if (IsA(ps, NestLoopState) && if (IsA(ancestor, NestLoop) &&
child_ps == innerPlanState(ps) && child_plan == innerPlan(ancestor) &&
in_same_plan_level) in_same_plan_level)
{ {
NestLoop *nl = (NestLoop *) ps->plan; NestLoop *nl = (NestLoop *) ancestor;
foreach(lc2, nl->nestParams) foreach(lc2, nl->nestParams)
{ {
@ -4331,16 +4417,12 @@ find_param_referent(Param *param, deparse_context *context,
/* /*
* Check to see if we're crawling up from a subplan. * Check to see if we're crawling up from a subplan.
*/ */
foreach(lc2, ps->subPlan) if(IsA(ancestor, SubPlan))
{ {
SubPlanState *sstate = (SubPlanState *) lfirst(lc2); SubPlan *subplan = (SubPlan *) ancestor;
SubPlan *subplan = sstate->subplan;
ListCell *lc3; ListCell *lc3;
ListCell *lc4; ListCell *lc4;
if (child_ps != sstate->planstate)
continue;
/* Matched subplan, so check its arguments */ /* Matched subplan, so check its arguments */
forboth(lc3, subplan->parParam, lc4, subplan->args) forboth(lc3, subplan->parParam, lc4, subplan->args)
{ {
@ -4349,41 +4431,61 @@ find_param_referent(Param *param, deparse_context *context,
if (paramid == param->paramid) if (paramid == param->paramid)
{ {
/* Found a match, so return it */ /*
* Found a match, so return it. But, since Vars in
* the arg are to be evaluated in the surrounding
* context, we have to point to the next ancestor item
* that is *not* a SubPlan.
*/
ListCell *rest;
for_each_cell(rest, dpns->ancestors,
lnext(dpns->ancestors, lc))
{
Node *ancestor2 = (Node *) lfirst(rest);
if (!IsA(ancestor2, SubPlan))
{
*dpns_p = dpns; *dpns_p = dpns;
*ancestor_cell_p = lc; *ancestor_cell_p = rest;
return arg; return arg;
} }
} }
elog(ERROR, "SubPlan cannot be outermost ancestor");
}
}
/* Keep looking, but we are emerging from a subplan. */ /* We have emerged from a subplan. */
in_same_plan_level = false; in_same_plan_level = false;
break;
/* SubPlan isn't a kind of Plan, so skip the rest */
continue;
} }
/* /*
* Likewise check to see if we're emerging from an initplan. * Check to see if we're emerging from an initplan of the current
* Initplans never have any parParams, so no need to search that * ancestor plan. Initplans never have any parParams, so no need
* list, but we need to know if we should reset * to search that list, but we need to know if we should reset
* in_same_plan_level. * in_same_plan_level.
*/ */
foreach(lc2, ps->initPlan) foreach(lc2, ((Plan *) ancestor)->initPlan)
{ {
SubPlanState *sstate = (SubPlanState *) lfirst(lc2); SubPlan *subplan = castNode(SubPlan, lfirst(lc2));
if (child_ps != sstate->planstate) if (child_plan != (Plan *) list_nth(dpns->subplans,
subplan->plan_id - 1))
continue; continue;
/* No parameters to be had here. */ /* No parameters to be had here. */
Assert(sstate->subplan->parParam == NIL); Assert(subplan->parParam == NIL);
/* Keep looking, but we are emerging from an initplan. */ /* We have emerged from an initplan. */
in_same_plan_level = false; in_same_plan_level = false;
break; break;
} }
/* No luck, crawl up to next ancestor */ /* No luck, crawl up to next ancestor */
child_ps = ps; child_plan = (Plan *) ancestor;
} }
} }
@ -6247,11 +6349,13 @@ get_agg_expr(Aggref *aggref, deparse_context *context,
*/ */
if (DO_AGGSPLIT_COMBINE(aggref->aggsplit)) if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
{ {
TargetEntry *tle = linitial_node(TargetEntry, aggref->args); TargetEntry *tle;
Assert(list_length(aggref->args) == 1); Assert(list_length(aggref->args) == 1);
resolve_special_varno((Node *) tle->expr, context, original_aggref, tle = linitial_node(TargetEntry, aggref->args);
get_agg_combine_expr); resolve_special_varno((Node *) tle->expr, context,
get_agg_combine_expr, original_aggref);
return; return;
} }
@ -6336,10 +6440,10 @@ get_agg_expr(Aggref *aggref, deparse_context *context,
* Aggref and then calls this. * Aggref and then calls this.
*/ */
static void static void
get_agg_combine_expr(Node *node, deparse_context *context, void *private) get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
{ {
Aggref *aggref; Aggref *aggref;
Aggref *original_aggref = private; Aggref *original_aggref = callback_arg;
if (!IsA(node, Aggref)) if (!IsA(node, Aggref))
elog(ERROR, "combining Aggref does not point to an Aggref"); elog(ERROR, "combining Aggref does not point to an Aggref");
@ -7102,7 +7206,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc); RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
List *args = ((FuncExpr *) rtfunc->funcexpr)->args; List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
allargs = list_concat(allargs, list_copy(args)); allargs = list_concat(allargs, args);
} }
appendStringInfoString(buf, "UNNEST("); appendStringInfoString(buf, "UNNEST(");
@ -7628,7 +7732,7 @@ printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
/* If subexpression is NULL, get_rule_expr prints nothing */ /* If subexpression is NULL, get_rule_expr prints nothing */
get_rule_expr((Node *) lfirst(lowlist_item), context, false); get_rule_expr((Node *) lfirst(lowlist_item), context, false);
appendStringInfoChar(buf, ':'); appendStringInfoChar(buf, ':');
lowlist_item = lnext(sbsref->refupperindexpr, lowlist_item); lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
} }
/* If subexpression is NULL, get_rule_expr prints nothing */ /* If subexpression is NULL, get_rule_expr prints nothing */
get_rule_expr((Node *) lfirst(uplist_item), context, false); get_rule_expr((Node *) lfirst(uplist_item), context, false);