staticbool
contain_aggs_of_level_walker(Node *node,
contain_aggs_of_level_context *context)
{ if (node == NULL) returnfalse; if (IsA(node, Aggref))
{ if (((Aggref *) node)->agglevelsup == context->sublevels_up) returntrue; /* abort the tree traversal and return true */ /* else fall through to examine argument */
} if (IsA(node, GroupingFunc))
{ if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up) returntrue; /* else fall through to examine argument */
} if (IsA(node, Query))
{ /* Recurse into subselects */ bool result;
if (context->sublevels_up == 0)
cexpr->cvarno += context->offset; returnfalse;
} if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) node;
if (context->sublevels_up == 0)
rtr->rtindex += context->offset; /* the subquery itself is visited separately */ returnfalse;
} if (IsA(node, JoinExpr))
{
JoinExpr *j = (JoinExpr *) node;
if (j->rtindex && context->sublevels_up == 0)
j->rtindex += context->offset; /* fall through to examine children */
} if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
if (phv->phlevelsup == context->sublevels_up)
{
phv->phrels = offset_relid_set(phv->phrels,
context->offset);
phv->phnullingrels = offset_relid_set(phv->phnullingrels,
context->offset);
} /* fall through to examine children */
} if (IsA(node, AppendRelInfo))
{
AppendRelInfo *appinfo = (AppendRelInfo *) node;
if (context->sublevels_up == 0)
{
appinfo->parent_relid += context->offset;
appinfo->child_relid += context->offset;
} /* fall through to examine children */
} /* Shouldn't need to handle other planner auxiliary nodes here */
Assert(!IsA(node, PlanRowMark));
Assert(!IsA(node, SpecialJoinInfo));
Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo));
if (IsA(node, Query))
{ /* Recurse into subselects */ bool result;
if (context->sublevels_up == 0 &&
rtr->rtindex == context->rt_index)
rtr->rtindex = context->new_index; /* the subquery itself is visited separately */ returnfalse;
} if (IsA(node, JoinExpr))
{
JoinExpr *j = (JoinExpr *) node;
if (context->sublevels_up == 0 &&
j->rtindex == context->rt_index)
j->rtindex = context->new_index; /* fall through to examine children */
} if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
if (phv->phlevelsup == context->sublevels_up)
{
phv->phrels = adjust_relid_set(phv->phrels,
context->rt_index,
context->new_index);
phv->phnullingrels = adjust_relid_set(phv->phnullingrels,
context->rt_index,
context->new_index);
} /* fall through to examine children */
} if (IsA(node, PlanRowMark))
{
PlanRowMark *rowmark = (PlanRowMark *) node;
if (context->sublevels_up == 0)
{ if (rowmark->rti == context->rt_index)
rowmark->rti = context->new_index; if (rowmark->prti == context->rt_index)
rowmark->prti = context->new_index;
} returnfalse;
} if (IsA(node, AppendRelInfo))
{
AppendRelInfo *appinfo = (AppendRelInfo *) node;
if (context->sublevels_up == 0)
{ if (appinfo->parent_relid == context->rt_index)
appinfo->parent_relid = context->new_index; if (appinfo->child_relid == context->rt_index)
appinfo->child_relid = context->new_index;
} /* fall through to examine children */
} /* Shouldn't need to handle other planner auxiliary nodes here */
Assert(!IsA(node, SpecialJoinInfo));
Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo));
if (IsA(node, Query))
{ /* Recurse into subselects */ bool result;
if (qry->resultRelation == rt_index)
qry->resultRelation = new_index;
if (qry->mergeTargetRelation == rt_index)
qry->mergeTargetRelation = new_index;
/* this is unlikely to ever be used, but ... */ if (qry->onConflict && qry->onConflict->exclRelIndex == rt_index)
qry->onConflict->exclRelIndex = new_index;
typedefstruct
{ int delta_sublevels_up; int min_sublevels_up;
} IncrementVarSublevelsUp_context;
staticbool
IncrementVarSublevelsUp_walker(Node *node,
IncrementVarSublevelsUp_context *context)
{ if (node == NULL) returnfalse; if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup >= context->min_sublevels_up)
var->varlevelsup += context->delta_sublevels_up; returnfalse; /* done here */
} if (IsA(node, CurrentOfExpr))
{ /* this should not happen */ if (context->min_sublevels_up == 0)
elog(ERROR, "cannot push down CurrentOfExpr"); returnfalse;
} if (IsA(node, Aggref))
{
Aggref *agg = (Aggref *) node;
if (agg->agglevelsup >= context->min_sublevels_up)
agg->agglevelsup += context->delta_sublevels_up; /* fall through to recurse into argument */
} if (IsA(node, GroupingFunc))
{
GroupingFunc *grp = (GroupingFunc *) node;
if (grp->agglevelsup >= context->min_sublevels_up)
grp->agglevelsup += context->delta_sublevels_up; /* fall through to recurse into argument */
} if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
if (phv->phlevelsup >= context->min_sublevels_up)
phv->phlevelsup += context->delta_sublevels_up; /* fall through to recurse into argument */
} if (IsA(node, ReturningExpr))
{
ReturningExpr *rexpr = (ReturningExpr *) node;
if (rexpr->retlevelsup >= context->min_sublevels_up)
rexpr->retlevelsup += context->delta_sublevels_up; /* fall through to recurse into argument */
} if (IsA(node, RangeTblEntry))
{
RangeTblEntry *rte = (RangeTblEntry *) node;
if (rte->rtekind == RTE_CTE)
{ if (rte->ctelevelsup >= context->min_sublevels_up)
rte->ctelevelsup += context->delta_sublevels_up;
} returnfalse; /* allow range_table_walker to continue */
} if (IsA(node, Query))
{ /* Recurse into subselects */ bool result;
if (rtr->rtindex == context->rt_index &&
context->sublevels_up == 0) returntrue; /* the subquery itself is visited separately */ returnfalse;
} if (IsA(node, JoinExpr))
{
JoinExpr *j = (JoinExpr *) node;
if (j->rtindex == context->rt_index &&
context->sublevels_up == 0) returntrue; /* fall through to examine children */
} /* Shouldn't need to handle planner auxiliary nodes here */
Assert(!IsA(node, PlaceHolderVar));
Assert(!IsA(node, PlanRowMark));
Assert(!IsA(node, SpecialJoinInfo));
Assert(!IsA(node, AppendRelInfo));
Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo));
if (IsA(node, Query))
{ /* Recurse into subselects */ bool result;
/* Copy the Var ... */
var = copyObject(var); /* ... and replace the copy's varnullingrels field */
var->varnullingrels = newnullingrels; return (Node *) var;
} /* Otherwise fall through to copy the Var normally */
} elseif (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
static Node *
remove_nulling_relids_mutator(Node *node,
remove_nulling_relids_context *context)
{ if (node == NULL) return NULL; if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up &&
!bms_is_member(var->varno, context->except_relids) &&
bms_overlap(var->varnullingrels, context->removable_relids))
{ /* Copy the Var ... */
var = copyObject(var); /* ... and replace the copy's varnullingrels field */
var->varnullingrels = bms_difference(var->varnullingrels,
context->removable_relids); return (Node *) var;
} /* Otherwise fall through to copy the Var normally */
} elseif (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
if (phv->phlevelsup == context->sublevels_up &&
!bms_overlap(phv->phrels, context->except_relids))
{ /* *Note:itmightseemdesirabletoremovethePHValtogetherif *phnullingrelsgoestoempty.Currentlywedarenotdothat *becauseweusePHVsinsomecasestoenforceseparateidentity *ofsubexpressions;seewrap_optionusagesinprepjointree.c.
*/ /* Copy the PlaceHolderVar and mutate what's below ... */
phv = (PlaceHolderVar *)
expression_tree_mutator(node,
remove_nulling_relids_mutator,
context); /* ... and replace the copy's phnullingrels field */
phv->phnullingrels = bms_difference(phv->phnullingrels,
context->removable_relids); /* We must also update phrels, if it contains a removable RTI */
phv->phrels = bms_difference(phv->phrels,
context->removable_relids);
Assert(!bms_is_empty(phv->phrels)); return (Node *) phv;
} /* Otherwise fall through to copy the PlaceHolderVar normally */
} elseif (IsA(node, Query))
{ /* Recurse into RTE or sublink subquery */
Query *newnode;
/* *MustbepreparedtostartwithaQueryorabareexpressiontree;if *it'saQuery,wedon'twanttoincrementsublevels_up.
*/
result = query_or_expression_tree_mutator(node,
replace_rte_variables_mutator,
&context, 0);
if (context.inserted_sublink)
{ if (result && IsA(result, Query))
((Query *) result)->hasSubLinks = true; elseif (outer_hasSubLinks)
*outer_hasSubLinks = true; else
elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
}
return result;
}
Node *
replace_rte_variables_mutator(Node *node,
replace_rte_variables_context *context)
{ if (node == NULL) return NULL; if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varno == context->target_varno &&
var->varlevelsup == context->sublevels_up)
{ /* Found a matching variable, make the substitution */
Node *newnode;
newnode = context->callback(var, context); /* Detect if we are adding a sublink to query */ if (!context->inserted_sublink)
context->inserted_sublink = checkExprHasSubLink(newnode); return newnode;
} /* otherwise fall through to copy the var normally */
} elseif (IsA(node, Query))
{ /* Recurse into RTE subquery or not-yet-planned sublink subquery */
Query *newnode; bool save_inserted_sublink;
typedefstruct
{ int target_varno; /* RTE index to search for */ int sublevels_up; /* (current) nesting depth */ const AttrMap *attno_map; /* map array for user attnos */
Oid to_rowtype; /* change whole-row Vars to this type */ bool *found_whole_row; /* output flag */
} map_variable_attnos_context;
static Node *
map_variable_attnos_mutator(Node *node,
map_variable_attnos_context *context)
{ if (node == NULL) return NULL; if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varno == context->target_varno &&
var->varlevelsup == context->sublevels_up)
{ /* Found a matching variable, make the substitution */
Var *newvar = (Var *) palloc(sizeof(Var)); int attno = var->varattno;
*newvar = *var; /* initially copy all fields of the Var */
if (attno > 0)
{ /* user-defined column, replace attno */ if (attno > context->attno_map->maplen ||
context->attno_map->attnums[attno - 1] == 0)
elog(ERROR, "unexpected varattno %d in expression to be mapped",
attno);
newvar->varattno = context->attno_map->attnums[attno - 1]; /* If the syntactic referent is same RTE, fix it too */ if (newvar->varnosyn == context->target_varno)
newvar->varattnosyn = newvar->varattno;
} elseif (attno == 0)
{ /* whole-row variable, warn caller */
*(context->found_whole_row) = true;
/* If the caller expects us to convert the Var, do so. */ if (OidIsValid(context->to_rowtype) &&
context->to_rowtype != var->vartype)
{
ConvertRowtypeExpr *r;
/* This certainly won't work for a RECORD variable. */
Assert(var->vartype != RECORDOID);
/* Var itself is changed to the requested type. */
newvar->vartype = context->to_rowtype;
*newvar = *var; /* initially copy all fields of the Var */
/* This certainly won't work for a RECORD variable. */
Assert(var->vartype != RECORDOID);
/* Var itself is changed to the requested type. */
newvar->vartype = context->to_rowtype;
newnode = (ConvertRowtypeExpr *) palloc(sizeof(ConvertRowtypeExpr));
*newnode = *r; /* initially copy all fields of the CRE */
newnode->arg = (Expr *) newvar;
return (Node *) newnode;
} /* otherwise fall through to process the expression normally */
} elseif (IsA(node, Query))
{ /* Recurse into RTE subquery or not-yet-planned sublink subquery */
Query *newnode;
typedefstruct
{
RangeTblEntry *target_rte;
List *targetlist; int result_relation;
ReplaceVarsNoMatchOption nomatch_option; int nomatch_varno;
} ReplaceVarsFromTargetList_context;
/* Must adjust varlevelsup if replaced Var is within a subquery */ if (var->varlevelsup > 0)
IncrementVarSublevelsUp(newnode, var->varlevelsup, 0);
return newnode;
}
Node *
ReplaceVarFromTargetList(Var *var,
RangeTblEntry *target_rte,
List *targetlist, int result_relation,
ReplaceVarsNoMatchOption nomatch_option, int nomatch_varno)
{
TargetEntry *tle;
if (var->varattno == InvalidAttrNumber)
{ /* Must expand whole-tuple reference into RowExpr */
RowExpr *rowexpr;
List *colnames;
List *fields;
ListCell *lc;
if (field && IsA(field, Var))
field = ReplaceVarFromTargetList((Var *) field,
target_rte,
targetlist,
result_relation,
nomatch_option,
nomatch_varno);
rowexpr->args = lappend(rowexpr->args, field);
}
/* Wrap it in a ReturningExpr, if needed, per comments above */ if (var->varreturningtype != VAR_RETURNING_DEFAULT)
{
ReturningExpr *rexpr = makeNode(ReturningExpr);
get_typlenbyval(var->vartype, &vartyplen, &vartypbyval); return coerce_null_to_domain(var->vartype,
var->vartypmod,
var->varcollid,
vartyplen,
vartypbyval);
}
}
elog(ERROR, "could not find replacement targetlist entry for attno %d",
var->varattno); return NULL; /* keep compiler quiet */
} else
{ /* Make a copy of the tlist item to return */
Expr *newnode = copyObject(tle->expr);
/* *ChecktoseeifthetlistitemcontainsaPARAM_MULTIEXPRParam, *andthrowerrorifso.Thiscasecouldonlyhappenwhenexpanding *anONUPDATErule'sNEWvariableandthereferencedtlistitemin *theoriginalUPDATEcommandispartofamultipleassignment.There *seemsnopracticalwaytohandlesuchcaseswithoutmultiple *evaluationofthemultipleassignment'ssub-select,whichwould *createsemanticodditiesthatusersofruleswouldprobablyprefer *nottocopewith.Sotreatitasanunimplementedfeature.
*/ if (contains_multiexpr_param((Node *) newnode, NULL))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));
/* Handle any OLD/NEW RETURNING list Vars */ if (var->varreturningtype != VAR_RETURNING_DEFAULT)
{ /* *CopyvarreturningtypeontoanyVarsinthetlistitemthat *refertoresult_relation(whichhadbetterbenon-zero).
*/ if (result_relation == 0)
elog(ERROR, "variable returning old/new found outside RETURNING list");
Node *
ReplaceVarsFromTargetList(Node *node, int target_varno, int sublevels_up,
RangeTblEntry *target_rte,
List *targetlist, int result_relation,
ReplaceVarsNoMatchOption nomatch_option, int nomatch_varno, bool *outer_hasSubLinks)
{
ReplaceVarsFromTargetList_context context;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.