#include "postgres.h"#include "catalog/pg_type.h"#include "nodes/makefuncs.h"#include "nodes/nodeFuncs.h"#include "nodes/plannodes.h"#include "optimizer/clauses.h"#include "parser/parse_coerce.h"#include "parser/parse_relation.h"#include "parser/parsetree.h"#include "rewrite/rewriteManip.h"
Go to the source code of this file.
Definition at line 1061 of file rewriteManip.c.
References AddQual(), BooleanTest::arg, BooleanTest::booltesttype, makeNode, and NULL.
Referenced by CopyAndAddInvertedQual().
{
BooleanTest *invqual;
if (qual == NULL)
return;
/* Need not copy input qual, because AddQual will... */
invqual = makeNode(BooleanTest);
invqual->arg = (Expr *) qual;
invqual->booltesttype = IS_NOT_TRUE;
AddQual(parsetree, (Node *) invqual);
}
Definition at line 993 of file rewriteManip.c.
References Assert, checkExprHasSubLink(), CMD_UTILITY, Query::commandType, contain_aggs_of_level(), copyObject(), ereport, errcode(), errmsg(), ERROR, Query::hasSubLinks, IsA, Query::jointree, make_and_qual(), NULL, FromExpr::quals, Query::setOperations, and Query::utilityStmt.
Referenced by AddInvertedQual(), rewriteRuleAction(), and rewriteTargetView().
{
Node *copy;
if (qual == NULL)
return;
if (parsetree->commandType == CMD_UTILITY)
{
/*
* There's noplace to put the qual on a utility statement.
*
* If it's a NOTIFY, silently ignore the qual; this means that the
* NOTIFY will execute, whether or not there are any qualifying rows.
* While clearly wrong, this is much more useful than refusing to
* execute the rule at all, and extra NOTIFY events are harmless for
* typical uses of NOTIFY.
*
* If it isn't a NOTIFY, error out, since unconditional execution of
* other utility stmts is unlikely to be wanted. (This case is not
* currently allowed anyway, but keep the test for safety.)
*/
if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
return;
else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("conditional utility statements are not implemented")));
}
if (parsetree->setOperations != NULL)
{
/*
* There's noplace to put the qual on a setop statement, either. (This
* could be fixed, but right now the planner simply ignores any qual
* condition on a setop query.)
*/
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
}
/* INTERSECT want's the original, but we need to copy - Jan */
copy = copyObject(qual);
parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
copy);
/*
* We had better not have stuck an aggregate into the WHERE clause.
*/
Assert(!contain_aggs_of_level(copy, 0));
/*
* Make sure query is marked correctly if added qual has sublinks. Need
* not search qual when query is already marked.
*/
if (!parsetree->hasSubLinks)
parsetree->hasSubLinks = checkExprHasSubLink(copy);
}
Definition at line 621 of file rewriteManip.c.
References bms_add_member(), bms_copy(), bms_del_member(), and bms_is_member().
Referenced by ChangeVarNodes_walker().
{
if (bms_is_member(oldrelid, relids))
{
/* Ensure we have a modifiable copy */
relids = bms_copy(relids);
/* Remove old, add new */
relids = bms_del_member(relids, oldrelid);
relids = bms_add_member(relids, newrelid);
}
return relids;
}
Definition at line 905 of file rewriteManip.c.
References attribute_used_context::attno, attribute_used_walker(), query_or_expression_tree_walker(), attribute_used_context::rt_index, and attribute_used_context::sublevels_up.
Referenced by fireRIRrules(), and matchLocks().
{
attribute_used_context context;
context.rt_index = rt_index;
context.attno = attno;
context.sublevels_up = sublevels_up;
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
return query_or_expression_tree_walker(node,
attribute_used_walker,
(void *) &context,
0);
}
| static bool attribute_used_walker | ( | Node * | node, | |
| attribute_used_context * | context | |||
| ) | [static] |
Definition at line 874 of file rewriteManip.c.
References attribute_used_context::attno, expression_tree_walker(), IsA, NULL, query_tree_walker(), attribute_used_context::rt_index, attribute_used_context::sublevels_up, Var::varattno, Var::varlevelsup, and Var::varno.
Referenced by attribute_used().
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up &&
var->varno == context->rt_index &&
var->varattno == context->attno)
return true;
return false;
}
if (IsA(node, Query))
{
/* Recurse into subselects */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node, attribute_used_walker,
(void *) context, 0);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, attribute_used_walker,
(void *) context);
}
| void ChangeVarNodes | ( | Node * | node, | |
| int | rt_index, | |||
| int | new_index, | |||
| int | sublevels_up | |||
| ) |
Definition at line 572 of file rewriteManip.c.
References ChangeVarNodes_walker(), IsA, lfirst, ChangeVarNodes_context::new_index, query_tree_walker(), Query::resultRelation, Query::rowMarks, ChangeVarNodes_context::rt_index, RowMarkClause::rti, and ChangeVarNodes_context::sublevels_up.
Referenced by ApplyRetrieveRule(), CopyAndAddInvertedQual(), get_relation_constraints(), get_relation_info(), inheritance_planner(), rewriteRuleAction(), rewriteTargetView(), and TriggerEnabled().
{
ChangeVarNodes_context context;
context.rt_index = rt_index;
context.new_index = new_index;
context.sublevels_up = sublevels_up;
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, go straight to query_tree_walker to make sure that
* sublevels_up doesn't get incremented prematurely.
*/
if (node && IsA(node, Query))
{
Query *qry = (Query *) node;
/*
* If we are starting at a Query, and sublevels_up is zero, then we
* must also fix rangetable indexes in the Query itself --- namely
* resultRelation and rowMarks entries. sublevels_up cannot be zero
* when recursing into a subquery, so there's no need to have the same
* logic inside ChangeVarNodes_walker.
*/
if (sublevels_up == 0)
{
ListCell *l;
if (qry->resultRelation == rt_index)
qry->resultRelation = new_index;
foreach(l, qry->rowMarks)
{
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
if (rc->rti == rt_index)
rc->rti = new_index;
}
}
query_tree_walker(qry, ChangeVarNodes_walker,
(void *) &context, 0);
}
else
ChangeVarNodes_walker(node, &context);
}
| static bool ChangeVarNodes_walker | ( | Node * | node, | |
| ChangeVarNodes_context * | context | |||
| ) | [static] |
Definition at line 468 of file rewriteManip.c.
References adjust_relid_set(), Assert, AppendRelInfo::child_relid, CurrentOfExpr::cvarno, expression_tree_walker(), IsA, ChangeVarNodes_context::new_index, NULL, AppendRelInfo::parent_relid, PlaceHolderVar::phlevelsup, PlaceHolderVar::phrels, PlanRowMark::prti, query_tree_walker(), ChangeVarNodes_context::rt_index, PlanRowMark::rti, JoinExpr::rtindex, RangeTblRef::rtindex, ChangeVarNodes_context::sublevels_up, Var::varlevelsup, Var::varno, and Var::varnoold.
Referenced by ChangeVarNodes().
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up &&
var->varno == context->rt_index)
{
var->varno = context->new_index;
var->varnoold = context->new_index;
}
return false;
}
if (IsA(node, CurrentOfExpr))
{
CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
if (context->sublevels_up == 0 &&
cexpr->cvarno == context->rt_index)
cexpr->cvarno = context->new_index;
return false;
}
if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) node;
if (context->sublevels_up == 0 &&
rtr->rtindex == context->rt_index)
rtr->rtindex = context->new_index;
/* the subquery itself is visited separately */
return false;
}
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);
}
/* 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;
}
return false;
}
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, LateralJoinInfo));
Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo));
if (IsA(node, Query))
{
/* Recurse into subselects */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
(void *) context, 0);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, ChangeVarNodes_walker,
(void *) context);
}
Definition at line 262 of file rewriteManip.c.
References checkExprHasSubLink_walker(), NULL, QTW_IGNORE_RC_SUBQUERIES, and query_or_expression_tree_walker().
Referenced by AddQual(), flatten_join_alias_vars_mutator(), replace_rte_variables_mutator(), and rewriteRuleAction().
{
/*
* If a Query is passed, examine it --- but we should not recurse into
* sub-Queries that are in its rangetable or CTE list.
*/
return query_or_expression_tree_walker(node,
checkExprHasSubLink_walker,
NULL,
QTW_IGNORE_RC_SUBQUERIES);
}
Definition at line 275 of file rewriteManip.c.
References expression_tree_walker(), IsA, and NULL.
Referenced by checkExprHasSubLink().
{
if (node == NULL)
return false;
if (IsA(node, SubLink))
return true; /* abort the tree traversal and return true */
return expression_tree_walker(node, checkExprHasSubLink_walker, context);
}
Definition at line 67 of file rewriteManip.c.
References contain_aggs_of_level_walker(), query_or_expression_tree_walker(), and contain_aggs_of_level_context::sublevels_up.
Referenced by AddQual(), checkTargetlistEntrySQL92(), and convert_EXISTS_to_ANY().
{
contain_aggs_of_level_context context;
context.sublevels_up = levelsup;
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
return query_or_expression_tree_walker(node,
contain_aggs_of_level_walker,
(void *) &context,
0);
}
| static bool contain_aggs_of_level_walker | ( | Node * | node, | |
| contain_aggs_of_level_context * | context | |||
| ) | [static] |
Definition at line 84 of file rewriteManip.c.
References expression_tree_walker(), IsA, NULL, query_tree_walker(), and contain_aggs_of_level_context::sublevels_up.
Referenced by contain_aggs_of_level().
{
if (node == NULL)
return false;
if (IsA(node, Aggref))
{
if (((Aggref *) node)->agglevelsup == context->sublevels_up)
return true; /* abort the tree traversal and return true */
/* else fall through to examine argument */
}
if (IsA(node, Query))
{
/* Recurse into subselects */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node,
contain_aggs_of_level_walker,
(void *) context, 0);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, contain_aggs_of_level_walker,
(void *) context);
}
Definition at line 182 of file rewriteManip.c.
References contain_windowfuncs_walker(), NULL, and query_or_expression_tree_walker().
Referenced by checkTargetlistEntrySQL92(), contain_window_function(), and transformWindowFuncCall().
{
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
return query_or_expression_tree_walker(node,
contain_windowfuncs_walker,
NULL,
0);
}
Definition at line 195 of file rewriteManip.c.
References expression_tree_walker(), IsA, and NULL.
Referenced by contain_windowfuncs().
{
if (node == NULL)
return false;
if (IsA(node, WindowFunc))
return true; /* abort the tree traversal and return true */
/* Mustn't recurse into subselects */
return expression_tree_walker(node, contain_windowfuncs_walker,
(void *) context);
}
Definition at line 938 of file rewriteManip.c.
References Assert, CMD_INSERT, CMD_SELECT, Query::commandType, elog, ERROR, FromExpr::fromlist, IsA, Query::jointree, linitial, list_length(), NULL, PRS2_NEW_VARNO, PRS2_OLD_VARNO, rt_fetch, Query::rtable, RangeTblRef::rtindex, and RangeTblEntry::subquery.
Referenced by DefineQueryRewrite(), InsertRule(), make_ruledef(), rewriteRuleAction(), and transformRuleStmt().
{
Query *selectquery;
RangeTblEntry *selectrte;
RangeTblRef *rtr;
if (subquery_ptr)
*subquery_ptr = NULL;
if (parsetree == NULL)
return parsetree;
if (parsetree->commandType != CMD_INSERT)
return parsetree;
/*
* Currently, this is ONLY applied to rule-action queries, and so we
* expect to find the OLD and NEW placeholder entries in the given query.
* If they're not there, it must be an INSERT/SELECT in which they've been
* pushed down to the SELECT.
*/
if (list_length(parsetree->rtable) >= 2 &&
strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
"old") == 0 &&
strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
"new") == 0)
return parsetree;
Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
if (list_length(parsetree->jointree->fromlist) != 1)
elog(ERROR, "expected to find SELECT subquery");
rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
Assert(IsA(rtr, RangeTblRef));
selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
selectquery = selectrte->subquery;
if (!(selectquery && IsA(selectquery, Query) &&
selectquery->commandType == CMD_SELECT))
elog(ERROR, "expected to find SELECT subquery");
if (list_length(selectquery->rtable) >= 2 &&
strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
"old") == 0 &&
strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
"new") == 0)
{
if (subquery_ptr)
*subquery_ptr = &(selectrte->subquery);
return selectquery;
}
elog(ERROR, "could not find rule placeholders");
return NULL; /* not reached */
}
| void IncrementVarSublevelsUp | ( | Node * | node, | |
| int | delta_sublevels_up, | |||
| int | min_sublevels_up | |||
| ) |
Definition at line 725 of file rewriteManip.c.
References IncrementVarSublevelsUp_context::delta_sublevels_up, IncrementVarSublevelsUp_walker(), IncrementVarSublevelsUp_context::min_sublevels_up, QTW_EXAMINE_RTES, and query_or_expression_tree_walker().
Referenced by assign_param_for_placeholdervar(), convert_EXISTS_sublink_to_join(), convert_EXISTS_to_ANY(), extract_lateral_references(), flatten_join_alias_vars_mutator(), pull_up_simple_subquery(), pullup_replace_vars_callback(), replace_outer_agg(), ReplaceVarsFromTargetList_callback(), and substitute_actual_srf_parameters_mutator().
{
IncrementVarSublevelsUp_context context;
context.delta_sublevels_up = delta_sublevels_up;
context.min_sublevels_up = min_sublevels_up;
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
query_or_expression_tree_walker(node,
IncrementVarSublevelsUp_walker,
(void *) &context,
QTW_EXAMINE_RTES);
}
| void IncrementVarSublevelsUp_rtable | ( | List * | rtable, | |
| int | delta_sublevels_up, | |||
| int | min_sublevels_up | |||
| ) |
Definition at line 748 of file rewriteManip.c.
References IncrementVarSublevelsUp_context::delta_sublevels_up, IncrementVarSublevelsUp_walker(), IncrementVarSublevelsUp_context::min_sublevels_up, QTW_EXAMINE_RTES, and range_table_walker().
Referenced by pull_up_simple_union_all().
{
IncrementVarSublevelsUp_context context;
context.delta_sublevels_up = delta_sublevels_up;
context.min_sublevels_up = min_sublevels_up;
range_table_walker(rtable,
IncrementVarSublevelsUp_walker,
(void *) &context,
QTW_EXAMINE_RTES);
}
| static bool IncrementVarSublevelsUp_walker | ( | Node * | node, | |
| IncrementVarSublevelsUp_context * | context | |||
| ) | [static] |
Definition at line 660 of file rewriteManip.c.
References Aggref::agglevelsup, RangeTblEntry::ctelevelsup, IncrementVarSublevelsUp_context::delta_sublevels_up, elog, ERROR, expression_tree_walker(), IsA, IncrementVarSublevelsUp_context::min_sublevels_up, NULL, PlaceHolderVar::phlevelsup, QTW_EXAMINE_RTES, query_tree_walker(), RTE_CTE, RangeTblEntry::rtekind, and Var::varlevelsup.
Referenced by IncrementVarSublevelsUp(), and IncrementVarSublevelsUp_rtable().
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup >= context->min_sublevels_up)
var->varlevelsup += context->delta_sublevels_up;
return false; /* done here */
}
if (IsA(node, CurrentOfExpr))
{
/* this should not happen */
if (context->min_sublevels_up == 0)
elog(ERROR, "cannot push down CurrentOfExpr");
return false;
}
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, 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, RangeTblEntry))
{
RangeTblEntry *rte = (RangeTblEntry *) node;
if (rte->rtekind == RTE_CTE)
{
if (rte->ctelevelsup >= context->min_sublevels_up)
rte->ctelevelsup += context->delta_sublevels_up;
}
return false; /* allow range_table_walker to continue */
}
if (IsA(node, Query))
{
/* Recurse into subselects */
bool result;
context->min_sublevels_up++;
result = query_tree_walker((Query *) node,
IncrementVarSublevelsUp_walker,
(void *) context,
QTW_EXAMINE_RTES);
context->min_sublevels_up--;
return result;
}
return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
(void *) context);
}
| int locate_agg_of_level | ( | Node * | node, | |
| int | levelsup | |||
| ) |
Definition at line 125 of file rewriteManip.c.
References locate_agg_of_level_context::agg_location, locate_agg_of_level_walker(), query_or_expression_tree_walker(), and locate_agg_of_level_context::sublevels_up.
Referenced by check_agg_arguments(), checkTargetlistEntrySQL92(), and parseCheckAggregates().
{
locate_agg_of_level_context context;
context.agg_location = -1; /* in case we find nothing */
context.sublevels_up = levelsup;
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
(void) query_or_expression_tree_walker(node,
locate_agg_of_level_walker,
(void *) &context,
0);
return context.agg_location;
}
| static bool locate_agg_of_level_walker | ( | Node * | node, | |
| locate_agg_of_level_context * | context | |||
| ) | [static] |
Definition at line 145 of file rewriteManip.c.
References locate_agg_of_level_context::agg_location, expression_tree_walker(), IsA, NULL, query_tree_walker(), and locate_agg_of_level_context::sublevels_up.
Referenced by locate_agg_of_level().
{
if (node == NULL)
return false;
if (IsA(node, Aggref))
{
if (((Aggref *) node)->agglevelsup == context->sublevels_up &&
((Aggref *) node)->location >= 0)
{
context->agg_location = ((Aggref *) node)->location;
return true; /* abort the tree traversal and return true */
}
/* else fall through to examine argument */
}
if (IsA(node, Query))
{
/* Recurse into subselects */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node,
locate_agg_of_level_walker,
(void *) context, 0);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, locate_agg_of_level_walker,
(void *) context);
}
| int locate_windowfunc | ( | Node * | node | ) |
Definition at line 220 of file rewriteManip.c.
References locate_windowfunc_walker(), query_or_expression_tree_walker(), and locate_windowfunc_context::win_location.
Referenced by checkTargetlistEntrySQL92(), and transformWindowFuncCall().
{
locate_windowfunc_context context;
context.win_location = -1; /* in case we find nothing */
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
(void) query_or_expression_tree_walker(node,
locate_windowfunc_walker,
(void *) &context,
0);
return context.win_location;
}
| static bool locate_windowfunc_walker | ( | Node * | node, | |
| locate_windowfunc_context * | context | |||
| ) | [static] |
Definition at line 239 of file rewriteManip.c.
References expression_tree_walker(), IsA, NULL, and locate_windowfunc_context::win_location.
Referenced by locate_windowfunc().
{
if (node == NULL)
return false;
if (IsA(node, WindowFunc))
{
if (((WindowFunc *) node)->location >= 0)
{
context->win_location = ((WindowFunc *) node)->location;
return true; /* abort the tree traversal and return true */
}
/* else fall through to examine argument */
}
/* Mustn't recurse into subselects */
return expression_tree_walker(node, locate_windowfunc_walker,
(void *) context);
}
| Node* map_variable_attnos | ( | Node * | node, | |
| int | target_varno, | |||
| int | sublevels_up, | |||
| const AttrNumber * | attno_map, | |||
| int | map_length, | |||
| bool * | found_whole_row | |||
| ) |
Definition at line 1299 of file rewriteManip.c.
References map_variable_attnos_context::attno_map, map_variable_attnos_context::found_whole_row, map_variable_attnos_context::map_length, map_variable_attnos_mutator(), query_or_expression_tree_mutator(), map_variable_attnos_context::sublevels_up, and map_variable_attnos_context::target_varno.
Referenced by generateClonedIndexStmt(), MergeAttributes(), and transformTableLikeClause().
{
map_variable_attnos_context context;
context.target_varno = target_varno;
context.sublevels_up = sublevels_up;
context.attno_map = attno_map;
context.map_length = map_length;
context.found_whole_row = found_whole_row;
*found_whole_row = false;
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
return query_or_expression_tree_mutator(node,
map_variable_attnos_mutator,
(void *) &context,
0);
}
| static Node* map_variable_attnos_mutator | ( | Node * | node, | |
| map_variable_attnos_context * | context | |||
| ) | [static] |
Definition at line 1246 of file rewriteManip.c.
References map_variable_attnos_context::attno_map, elog, ERROR, expression_tree_mutator(), map_variable_attnos_context::found_whole_row, IsA, map_variable_attnos_context::map_length, NULL, palloc(), query_tree_mutator(), map_variable_attnos_context::sublevels_up, map_variable_attnos_context::target_varno, Var::varattno, Var::varlevelsup, Var::varno, and Var::varoattno.
Referenced by map_variable_attnos().
{
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;
if (attno > 0)
{
/* user-defined column, replace attno */
if (attno > context->map_length ||
context->attno_map[attno - 1] == 0)
elog(ERROR, "unexpected varattno %d in expression to be mapped",
attno);
newvar->varattno = newvar->varoattno = context->attno_map[attno - 1];
}
else if (attno == 0)
{
/* whole-row variable, warn caller */
*(context->found_whole_row) = true;
}
return (Node *) newvar;
}
/* otherwise fall through to copy the var normally */
}
else if (IsA(node, Query))
{
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
Query *newnode;
context->sublevels_up++;
newnode = query_tree_mutator((Query *) node,
map_variable_attnos_mutator,
(void *) context,
0);
context->sublevels_up--;
return (Node *) newnode;
}
return expression_tree_mutator(node, map_variable_attnos_mutator,
(void *) context);
}
Definition at line 434 of file rewriteManip.c.
References bms_add_member(), bms_copy(), bms_first_member(), and bms_free().
Referenced by OffsetVarNodes_walker().
{
Relids result = NULL;
Relids tmprelids;
int rtindex;
tmprelids = bms_copy(relids);
while ((rtindex = bms_first_member(tmprelids)) >= 0)
result = bms_add_member(result, rtindex + offset);
bms_free(tmprelids);
return result;
}
| void OffsetVarNodes | ( | Node * | node, | |
| int | offset, | |||
| int | sublevels_up | |||
| ) |
Definition at line 390 of file rewriteManip.c.
References IsA, lfirst, OffsetVarNodes_context::offset, OffsetVarNodes_walker(), query_tree_walker(), Query::resultRelation, Query::rowMarks, RowMarkClause::rti, and OffsetVarNodes_context::sublevels_up.
Referenced by convert_EXISTS_sublink_to_join(), pull_up_simple_subquery(), rewriteRuleAction(), and UpdateRangeTableOfViewParse().
{
OffsetVarNodes_context context;
context.offset = offset;
context.sublevels_up = sublevels_up;
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, go straight to query_tree_walker to make sure that
* sublevels_up doesn't get incremented prematurely.
*/
if (node && IsA(node, Query))
{
Query *qry = (Query *) node;
/*
* If we are starting at a Query, and sublevels_up is zero, then we
* must also fix rangetable indexes in the Query itself --- namely
* resultRelation and rowMarks entries. sublevels_up cannot be zero
* when recursing into a subquery, so there's no need to have the same
* logic inside OffsetVarNodes_walker.
*/
if (sublevels_up == 0)
{
ListCell *l;
if (qry->resultRelation)
qry->resultRelation += offset;
foreach(l, qry->rowMarks)
{
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
rc->rti += offset;
}
}
query_tree_walker(qry, OffsetVarNodes_walker,
(void *) &context, 0);
}
else
OffsetVarNodes_walker(node, &context);
}
| static bool OffsetVarNodes_walker | ( | Node * | node, | |
| OffsetVarNodes_context * | context | |||
| ) | [static] |
Definition at line 305 of file rewriteManip.c.
References Assert, AppendRelInfo::child_relid, CurrentOfExpr::cvarno, expression_tree_walker(), IsA, NULL, OffsetVarNodes_context::offset, offset_relid_set(), AppendRelInfo::parent_relid, PlaceHolderVar::phlevelsup, PlaceHolderVar::phrels, query_tree_walker(), JoinExpr::rtindex, RangeTblRef::rtindex, OffsetVarNodes_context::sublevels_up, Var::varlevelsup, Var::varno, and Var::varnoold.
Referenced by OffsetVarNodes().
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up)
{
var->varno += context->offset;
var->varnoold += context->offset;
}
return false;
}
if (IsA(node, CurrentOfExpr))
{
CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
if (context->sublevels_up == 0)
cexpr->cvarno += context->offset;
return false;
}
if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) node;
if (context->sublevels_up == 0)
rtr->rtindex += context->offset;
/* the subquery itself is visited separately */
return false;
}
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);
}
/* 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, LateralJoinInfo));
Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo));
if (IsA(node, Query))
{
/* Recurse into subselects */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
(void *) context, 0);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, OffsetVarNodes_walker,
(void *) context);
}
Definition at line 842 of file rewriteManip.c.
References query_or_expression_tree_walker(), rangeTableEntry_used_walker(), rangeTableEntry_used_context::rt_index, and rangeTableEntry_used_context::sublevels_up.
Referenced by fireRIRrules(), matchLocks(), rewriteRuleAction(), and transformRuleStmt().
{
rangeTableEntry_used_context context;
context.rt_index = rt_index;
context.sublevels_up = sublevels_up;
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
return query_or_expression_tree_walker(node,
rangeTableEntry_used_walker,
(void *) &context,
0);
}
| static bool rangeTableEntry_used_walker | ( | Node * | node, | |
| rangeTableEntry_used_context * | context | |||
| ) | [static] |
Definition at line 775 of file rewriteManip.c.
References Assert, CurrentOfExpr::cvarno, expression_tree_walker(), IsA, NULL, query_tree_walker(), rangeTableEntry_used_context::rt_index, JoinExpr::rtindex, RangeTblRef::rtindex, rangeTableEntry_used_context::sublevels_up, Var::varlevelsup, and Var::varno.
Referenced by rangeTableEntry_used().
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up &&
var->varno == context->rt_index)
return true;
return false;
}
if (IsA(node, CurrentOfExpr))
{
CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
if (context->sublevels_up == 0 &&
cexpr->cvarno == context->rt_index)
return true;
return false;
}
if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) node;
if (rtr->rtindex == context->rt_index &&
context->sublevels_up == 0)
return true;
/* the subquery itself is visited separately */
return false;
}
if (IsA(node, JoinExpr))
{
JoinExpr *j = (JoinExpr *) node;
if (j->rtindex == context->rt_index &&
context->sublevels_up == 0)
return true;
/* 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, LateralJoinInfo));
Assert(!IsA(node, AppendRelInfo));
Assert(!IsA(node, PlaceHolderInfo));
Assert(!IsA(node, MinMaxAggInfo));
if (IsA(node, Query))
{
/* Recurse into subselects */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
(void *) context, 0);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, rangeTableEntry_used_walker,
(void *) context);
}
| Node* replace_rte_variables | ( | Node * | node, | |
| int | target_varno, | |||
| int | sublevels_up, | |||
| replace_rte_variables_callback | callback, | |||
| void * | callback_arg, | |||
| bool * | outer_hasSubLinks | |||
| ) |
Definition at line 1100 of file rewriteManip.c.
References replace_rte_variables_context::callback, replace_rte_variables_context::callback_arg, elog, ERROR, replace_rte_variables_context::inserted_sublink, IsA, query_or_expression_tree_mutator(), replace_rte_variables_mutator(), replace_rte_variables_context::sublevels_up, and replace_rte_variables_context::target_varno.
Referenced by pullup_replace_vars(), pullup_replace_vars_subquery(), and ReplaceVarsFromTargetList().
{
Node *result;
replace_rte_variables_context context;
context.callback = callback;
context.callback_arg = callback_arg;
context.target_varno = target_varno;
context.sublevels_up = sublevels_up;
/*
* We try to initialize inserted_sublink to true if there is no need to
* detect new sublinks because the query already has some.
*/
if (node && IsA(node, Query))
context.inserted_sublink = ((Query *) node)->hasSubLinks;
else if (outer_hasSubLinks)
context.inserted_sublink = *outer_hasSubLinks;
else
context.inserted_sublink = false;
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
result = query_or_expression_tree_mutator(node,
replace_rte_variables_mutator,
(void *) &context,
0);
if (context.inserted_sublink)
{
if (result && IsA(result, Query))
((Query *) result)->hasSubLinks = true;
else if (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 | |||
| ) |
Definition at line 1147 of file rewriteManip.c.
References replace_rte_variables_context::callback, checkExprHasSubLink(), CurrentOfExpr::cvarno, ereport, errcode(), errmsg(), ERROR, expression_tree_mutator(), Query::hasSubLinks, replace_rte_variables_context::inserted_sublink, IsA, NULL, query_tree_mutator(), replace_rte_variables_mutator(), replace_rte_variables_context::sublevels_up, replace_rte_variables_context::target_varno, Var::varlevelsup, and Var::varno.
Referenced by pullup_replace_vars_callback(), replace_rte_variables(), replace_rte_variables_mutator(), and ReplaceVarsFromTargetList_callback().
{
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 */
}
else if (IsA(node, CurrentOfExpr))
{
CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
if (cexpr->cvarno == context->target_varno &&
context->sublevels_up == 0)
{
/*
* We get here if a WHERE CURRENT OF expression turns out to apply
* to a view. Someday we might be able to translate the
* expression to apply to an underlying table of the view, but
* right now it's not implemented.
*/
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("WHERE CURRENT OF on a view is not implemented")));
}
/* otherwise fall through to copy the expr normally */
}
else if (IsA(node, Query))
{
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
Query *newnode;
bool save_inserted_sublink;
context->sublevels_up++;
save_inserted_sublink = context->inserted_sublink;
context->inserted_sublink = ((Query *) node)->hasSubLinks;
newnode = query_tree_mutator((Query *) node,
replace_rte_variables_mutator,
(void *) context,
0);
newnode->hasSubLinks |= context->inserted_sublink;
context->inserted_sublink = save_inserted_sublink;
context->sublevels_up--;
return (Node *) newnode;
}
return expression_tree_mutator(node, replace_rte_variables_mutator,
(void *) context);
}
| Node* ReplaceVarsFromTargetList | ( | Node * | node, | |
| int | target_varno, | |||
| int | sublevels_up, | |||
| RangeTblEntry * | target_rte, | |||
| List * | targetlist, | |||
| ReplaceVarsNoMatchOption | nomatch_option, | |||
| int | nomatch_varno, | |||
| bool * | outer_hasSubLinks | |||
| ) |
Definition at line 1441 of file rewriteManip.c.
References ReplaceVarsFromTargetList_context::nomatch_option, ReplaceVarsFromTargetList_context::nomatch_varno, replace_rte_variables(), ReplaceVarsFromTargetList_callback(), ReplaceVarsFromTargetList_context::target_rte, and ReplaceVarsFromTargetList_context::targetlist.
Referenced by CopyAndAddInvertedQual(), rewriteRuleAction(), rewriteTargetView(), and subquery_push_qual().
{
ReplaceVarsFromTargetList_context context;
context.target_rte = target_rte;
context.targetlist = targetlist;
context.nomatch_option = nomatch_option;
context.nomatch_varno = nomatch_varno;
return replace_rte_variables(node, target_varno, sublevels_up,
ReplaceVarsFromTargetList_callback,
(void *) &context,
outer_hasSubLinks);
}
| static Node* ReplaceVarsFromTargetList_callback | ( | Var * | var, | |
| replace_rte_variables_context * | context | |||
| ) | [static] |
Definition at line 1353 of file rewriteManip.c.
References RowExpr::args, replace_rte_variables_context::callback_arg, COERCE_IMPLICIT_CAST, coerce_to_domain(), RowExpr::colnames, copyObject(), elog, ERROR, expandRTE(), get_tle_by_resno(), IncrementVarSublevelsUp(), InvalidAttrNumber, InvalidOid, RowExpr::location, Var::location, makeNode, makeNullConst(), ReplaceVarsFromTargetList_context::nomatch_option, ReplaceVarsFromTargetList_context::nomatch_varno, NULL, RECORDOID, replace_rte_variables_mutator(), REPLACEVARS_CHANGE_VARNO, REPLACEVARS_REPORT_ERROR, REPLACEVARS_SUBSTITUTE_NULL, RowExpr::row_format, RowExpr::row_typeid, ReplaceVarsFromTargetList_context::target_rte, ReplaceVarsFromTargetList_context::targetlist, Var::varattno, Var::varcollid, Var::varlevelsup, Var::varno, Var::varnoold, Var::vartype, and Var::vartypmod.
Referenced by ReplaceVarsFromTargetList().
{
ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
TargetEntry *tle;
if (var->varattno == InvalidAttrNumber)
{
/* Must expand whole-tuple reference into RowExpr */
RowExpr *rowexpr;
List *colnames;
List *fields;
/*
* If generating an expansion for a var of a named rowtype (ie, this
* is a plain relation RTE), then we must include dummy items for
* dropped columns. If the var is RECORD (ie, this is a JOIN), then
* omit dropped columns. Either way, attach column names to the
* RowExpr for use of ruleutils.c.
*/
expandRTE(rcon->target_rte,
var->varno, var->varlevelsup, var->location,
(var->vartype != RECORDOID),
&colnames, &fields);
/* Adjust the generated per-field Vars... */
fields = (List *) replace_rte_variables_mutator((Node *) fields,
context);
rowexpr = makeNode(RowExpr);
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
rowexpr->colnames = colnames;
rowexpr->location = var->location;
return (Node *) rowexpr;
}
/* Normal case referencing one targetlist element */
tle = get_tle_by_resno(rcon->targetlist, var->varattno);
if (tle == NULL || tle->resjunk)
{
/* Failed to find column in targetlist */
switch (rcon->nomatch_option)
{
case REPLACEVARS_REPORT_ERROR:
/* fall through, throw error below */
break;
case REPLACEVARS_CHANGE_VARNO:
var = (Var *) copyObject(var);
var->varno = rcon->nomatch_varno;
var->varnoold = rcon->nomatch_varno;
return (Node *) var;
case REPLACEVARS_SUBSTITUTE_NULL:
/*
* If Var is of domain type, we should add a CoerceToDomain
* node, in case there is a NOT NULL domain constraint.
*/
return coerce_to_domain((Node *) makeNullConst(var->vartype,
var->vartypmod,
var->varcollid),
InvalidOid, -1,
var->vartype,
COERCE_IMPLICIT_CAST,
-1,
false,
false);
}
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 */
Node *newnode = copyObject(tle->expr);
/* Must adjust varlevelsup if tlist item is from higher query */
if (var->varlevelsup > 0)
IncrementVarSublevelsUp(newnode, var->varlevelsup, 0);
return newnode;
}
}
1.7.1