#include "nodes/plannodes.h"#include "nodes/relation.h"

Go to the source code of this file.
Functions | |
| void | pull_up_sublinks (PlannerInfo *root) |
| void | inline_set_returning_functions (PlannerInfo *root) |
| Node * | pull_up_subqueries (PlannerInfo *root, Node *jtnode) |
| void | flatten_simple_union_all (PlannerInfo *root) |
| void | reduce_outer_joins (PlannerInfo *root) |
| Relids | get_relids_in_jointree (Node *jtnode, bool include_joins) |
| Relids | get_relids_for_join (PlannerInfo *root, int joinrelid) |
| Node * | negate_clause (Node *node) |
| Expr * | canonicalize_qual (Expr *qual) |
| List * | preprocess_targetlist (PlannerInfo *root, List *tlist) |
| PlanRowMark * | get_plan_rowmark (List *rowmarks, Index rtindex) |
| Plan * | plan_set_operations (PlannerInfo *root, double tuple_fraction, List **sortClauses) |
| void | expand_inherited_tables (PlannerInfo *root) |
| Node * | adjust_appendrel_attrs (PlannerInfo *root, Node *node, AppendRelInfo *appinfo) |
| Node* adjust_appendrel_attrs | ( | PlannerInfo * | root, | |
| Node * | node, | |||
| AppendRelInfo * | appinfo | |||
| ) |
Definition at line 1590 of file prepunion.c.
References adjust_appendrel_attrs_mutator(), adjust_inherited_tlist(), adjust_appendrel_attrs_context::appinfo, AppendRelInfo::child_relid, CMD_UPDATE, Query::commandType, IsA, AppendRelInfo::parent_relid, QTW_IGNORE_RC_SUBQUERIES, query_tree_mutator(), Query::resultRelation, adjust_appendrel_attrs_context::root, and Query::targetList.
Referenced by add_child_rel_equivalences(), generate_join_implied_equalities_broken(), inheritance_planner(), and set_append_rel_size().
{
Node *result;
adjust_appendrel_attrs_context context;
context.root = root;
context.appinfo = appinfo;
/*
* Must be prepared to start with a Query or a bare expression tree.
*/
if (node && IsA(node, Query))
{
Query *newnode;
newnode = query_tree_mutator((Query *) node,
adjust_appendrel_attrs_mutator,
(void *) &context,
QTW_IGNORE_RC_SUBQUERIES);
if (newnode->resultRelation == appinfo->parent_relid)
{
newnode->resultRelation = appinfo->child_relid;
/* Fix tlist resnos too, if it's inherited UPDATE */
if (newnode->commandType == CMD_UPDATE)
newnode->targetList =
adjust_inherited_tlist(newnode->targetList,
appinfo);
}
result = (Node *) newnode;
}
else
result = adjust_appendrel_attrs_mutator(node, &context);
return result;
}
Definition at line 285 of file prepqual.c.
References find_duplicate_ors(), and NULL.
Referenced by convert_EXISTS_to_ANY(), get_relation_constraints(), preprocess_expression(), and RelationGetIndexPredicate().
{
Expr *newqual;
/* Quick exit for empty qual */
if (qual == NULL)
return NULL;
/*
* Pull up redundant subclauses in OR-of-AND trees. We do this only
* within the top-level AND/OR structure; there's no point in looking
* deeper.
*/
newqual = find_duplicate_ors(qual);
return newqual;
}
| void expand_inherited_tables | ( | PlannerInfo * | root | ) |
Definition at line 1191 of file prepunion.c.
References expand_inherited_rtentry(), lfirst, list_head(), list_length(), lnext, PlannerInfo::parse, and Query::rtable.
Referenced by subquery_planner().
{
Index nrtes;
Index rti;
ListCell *rl;
/*
* expand_inherited_rtentry may add RTEs to parse->rtable; there is no
* need to scan them since they can't have inh=true. So just scan as far
* as the original end of the rtable list.
*/
nrtes = list_length(root->parse->rtable);
rl = list_head(root->parse->rtable);
for (rti = 1; rti <= nrtes; rti++)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
expand_inherited_rtentry(root, rte, rti);
rl = lnext(rl);
}
}
| void flatten_simple_union_all | ( | PlannerInfo * | root | ) |
Definition at line 1779 of file prepjointree.c.
References Assert, copyObject(), FromExpr::fromlist, PlannerInfo::hasRecursion, RangeTblEntry::inh, is_simple_union_all_recurse(), IsA, Query::jointree, lappend(), list_length(), list_make1, makeNode, NIL, PlannerInfo::parse, parse(), pull_up_union_leaf_queries(), rt_fetch, Query::rtable, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblRef::rtindex, and Query::setOperations.
Referenced by subquery_planner().
{
Query *parse = root->parse;
SetOperationStmt *topop;
Node *leftmostjtnode;
int leftmostRTI;
RangeTblEntry *leftmostRTE;
int childRTI;
RangeTblEntry *childRTE;
RangeTblRef *rtr;
/* Shouldn't be called unless query has setops */
topop = (SetOperationStmt *) parse->setOperations;
Assert(topop && IsA(topop, SetOperationStmt));
/* Can't optimize away a recursive UNION */
if (root->hasRecursion)
return;
/*
* Recursively check the tree of set operations. If not all UNION ALL
* with identical column types, punt.
*/
if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
return;
/*
* Locate the leftmost leaf query in the setops tree. The upper query's
* Vars all refer to this RTE (see transformSetOperationStmt).
*/
leftmostjtnode = topop->larg;
while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
/*
* Make a copy of the leftmost RTE and add it to the rtable. This copy
* will represent the leftmost leaf query in its capacity as a member of
* the appendrel. The original will represent the appendrel as a whole.
* (We must do things this way because the upper query's Vars have to be
* seen as referring to the whole appendrel.)
*/
childRTE = copyObject(leftmostRTE);
parse->rtable = lappend(parse->rtable, childRTE);
childRTI = list_length(parse->rtable);
/* Modify the setops tree to reference the child copy */
((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
/* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
leftmostRTE->inh = true;
/*
* Form a RangeTblRef for the appendrel, and insert it into FROM. The top
* Query of a setops tree should have had an empty FromClause initially.
*/
rtr = makeNode(RangeTblRef);
rtr->rtindex = leftmostRTI;
Assert(parse->jointree->fromlist == NIL);
parse->jointree->fromlist = list_make1(rtr);
/*
* Now pretend the query has no setops. We must do this before trying to
* do subquery pullup, because of Assert in pull_up_simple_subquery.
*/
parse->setOperations = NULL;
/*
* Build AppendRelInfo information, and apply pull_up_subqueries to the
* leaf queries of the UNION ALL. (We must do that now because they
* weren't previously referenced by the jointree, and so were missed by
* the main invocation of pull_up_subqueries.)
*/
pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
}
| PlanRowMark* get_plan_rowmark | ( | List * | rowmarks, | |
| Index | rtindex | |||
| ) |
Definition at line 373 of file preptlist.c.
References lfirst, and PlanRowMark::rti.
Referenced by AcquireExecutorLocks(), and expand_inherited_rtentry().
{
ListCell *l;
foreach(l, rowmarks)
{
PlanRowMark *rc = (PlanRowMark *) lfirst(l);
if (rc->rti == rtindex)
return rc;
}
return NULL;
}
| Relids get_relids_for_join | ( | PlannerInfo * | root, | |
| int | joinrelid | |||
| ) |
Definition at line 2446 of file prepjointree.c.
References elog, ERROR, find_jointree_node_for_rel(), get_relids_in_jointree(), Query::jointree, and PlannerInfo::parse.
Referenced by alias_relid_set().
{
Node *jtnode;
jtnode = find_jointree_node_for_rel((Node *) root->parse->jointree,
joinrelid);
if (!jtnode)
elog(ERROR, "could not find join node %d", joinrelid);
return get_relids_in_jointree(jtnode, false);
}
Definition at line 2402 of file prepjointree.c.
References bms_add_member(), bms_join(), bms_make_singleton(), elog, ERROR, FromExpr::fromlist, get_relids_in_jointree(), IsA, JoinExpr::larg, lfirst, nodeTag, NULL, JoinExpr::rarg, and JoinExpr::rtindex.
Referenced by distribute_qual_to_rels(), get_relids_for_join(), get_relids_in_jointree(), is_simple_subquery(), and pull_up_simple_subquery().
{
Relids result = NULL;
if (jtnode == NULL)
return result;
if (IsA(jtnode, RangeTblRef))
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
result = bms_make_singleton(varno);
}
else if (IsA(jtnode, FromExpr))
{
FromExpr *f = (FromExpr *) jtnode;
ListCell *l;
foreach(l, f->fromlist)
{
result = bms_join(result,
get_relids_in_jointree(lfirst(l),
include_joins));
}
}
else if (IsA(jtnode, JoinExpr))
{
JoinExpr *j = (JoinExpr *) jtnode;
result = get_relids_in_jointree(j->larg, include_joins);
result = bms_join(result,
get_relids_in_jointree(j->rarg, include_joins));
if (include_joins && j->rtindex)
result = bms_add_member(result, j->rtindex);
}
else
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(jtnode));
return result;
}
| void inline_set_returning_functions | ( | PlannerInfo * | root | ) |
Definition at line 560 of file prepjointree.c.
References RangeTblEntry::funccolcollations, RangeTblEntry::funccoltypes, RangeTblEntry::funccoltypmods, RangeTblEntry::funcexpr, inline_set_returning_function(), lfirst, PlannerInfo::parse, Query::rtable, RTE_FUNCTION, RangeTblEntry::rtekind, and RangeTblEntry::subquery.
Referenced by pull_up_simple_subquery(), and subquery_planner().
{
ListCell *rt;
foreach(rt, root->parse->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
if (rte->rtekind == RTE_FUNCTION)
{
Query *funcquery;
/* Check safety of expansion, and expand if possible */
funcquery = inline_set_returning_function(root, rte);
if (funcquery)
{
/* Successful expansion, replace the rtable entry */
rte->rtekind = RTE_SUBQUERY;
rte->subquery = funcquery;
rte->funcexpr = NULL;
rte->funccoltypes = NIL;
rte->funccoltypmods = NIL;
rte->funccolcollations = NIL;
}
}
}
}
Definition at line 74 of file prepqual.c.
References AND_EXPR, BooleanTest::arg, NullTest::arg, NullTest::argisrow, BoolExpr::args, ScalarArrayOpExpr::args, OpExpr::args, BoolExpr::boolop, BooleanTest::booltesttype, Const::constisnull, Const::constvalue, DatumGetBool, elog, ERROR, get_negator(), ScalarArrayOpExpr::inputcollid, OpExpr::inputcollid, IS_FALSE, IS_NOT_FALSE, IS_NOT_NULL, IS_NOT_TRUE, IS_NOT_UNKNOWN, IS_NULL, IS_TRUE, IS_UNKNOWN, lappend(), lfirst, linitial, ScalarArrayOpExpr::location, OpExpr::location, make_andclause(), make_notclause(), make_orclause(), makeBoolConst(), makeNode, negate_clause(), nodeTag, NOT_EXPR, NULL, NullTest::nulltesttype, OpExpr::opcollid, ScalarArrayOpExpr::opfuncid, OpExpr::opfuncid, ScalarArrayOpExpr::opno, OpExpr::opno, OpExpr::opresulttype, OpExpr::opretset, OR_EXPR, T_BooleanTest, T_BoolExpr, T_Const, T_NullTest, T_OpExpr, T_ScalarArrayOpExpr, and ScalarArrayOpExpr::useOr.
Referenced by eval_const_expressions_mutator(), negate_clause(), and simplify_boolean_equality().
{
if (node == NULL) /* should not happen */
elog(ERROR, "can't negate an empty subexpression");
switch (nodeTag(node))
{
case T_Const:
{
Const *c = (Const *) node;
/* NOT NULL is still NULL */
if (c->constisnull)
return makeBoolConst(false, true);
/* otherwise pretty easy */
return makeBoolConst(!DatumGetBool(c->constvalue), false);
}
break;
case T_OpExpr:
{
/*
* Negate operator if possible: (NOT (< A B)) => (>= A B)
*/
OpExpr *opexpr = (OpExpr *) node;
Oid negator = get_negator(opexpr->opno);
if (negator)
{
OpExpr *newopexpr = makeNode(OpExpr);
newopexpr->opno = negator;
newopexpr->opfuncid = InvalidOid;
newopexpr->opresulttype = opexpr->opresulttype;
newopexpr->opretset = opexpr->opretset;
newopexpr->opcollid = opexpr->opcollid;
newopexpr->inputcollid = opexpr->inputcollid;
newopexpr->args = opexpr->args;
newopexpr->location = opexpr->location;
return (Node *) newopexpr;
}
}
break;
case T_ScalarArrayOpExpr:
{
/*
* Negate a ScalarArrayOpExpr if its operator has a negator;
* for example x = ANY (list) becomes x <> ALL (list)
*/
ScalarArrayOpExpr *saopexpr = (ScalarArrayOpExpr *) node;
Oid negator = get_negator(saopexpr->opno);
if (negator)
{
ScalarArrayOpExpr *newopexpr = makeNode(ScalarArrayOpExpr);
newopexpr->opno = negator;
newopexpr->opfuncid = InvalidOid;
newopexpr->useOr = !saopexpr->useOr;
newopexpr->inputcollid = saopexpr->inputcollid;
newopexpr->args = saopexpr->args;
newopexpr->location = saopexpr->location;
return (Node *) newopexpr;
}
}
break;
case T_BoolExpr:
{
BoolExpr *expr = (BoolExpr *) node;
switch (expr->boolop)
{
/*--------------------
* Apply DeMorgan's Laws:
* (NOT (AND A B)) => (OR (NOT A) (NOT B))
* (NOT (OR A B)) => (AND (NOT A) (NOT B))
* i.e., swap AND for OR and negate each subclause.
*
* If the input is already AND/OR flat and has no NOT
* directly above AND or OR, this transformation preserves
* those properties. For example, if no direct child of
* the given AND clause is an AND or a NOT-above-OR, then
* the recursive calls of negate_clause() can't return any
* OR clauses. So we needn't call pull_ors() before
* building a new OR clause. Similarly for the OR case.
*--------------------
*/
case AND_EXPR:
{
List *nargs = NIL;
ListCell *lc;
foreach(lc, expr->args)
{
nargs = lappend(nargs,
negate_clause(lfirst(lc)));
}
return (Node *) make_orclause(nargs);
}
break;
case OR_EXPR:
{
List *nargs = NIL;
ListCell *lc;
foreach(lc, expr->args)
{
nargs = lappend(nargs,
negate_clause(lfirst(lc)));
}
return (Node *) make_andclause(nargs);
}
break;
case NOT_EXPR:
/*
* NOT underneath NOT: they cancel. We assume the
* input is already simplified, so no need to recurse.
*/
return (Node *) linitial(expr->args);
default:
elog(ERROR, "unrecognized boolop: %d",
(int) expr->boolop);
break;
}
}
break;
case T_NullTest:
{
NullTest *expr = (NullTest *) node;
/*
* In the rowtype case, the two flavors of NullTest are *not*
* logical inverses, so we can't simplify. But it does work
* for scalar datatypes.
*/
if (!expr->argisrow)
{
NullTest *newexpr = makeNode(NullTest);
newexpr->arg = expr->arg;
newexpr->nulltesttype = (expr->nulltesttype == IS_NULL ?
IS_NOT_NULL : IS_NULL);
newexpr->argisrow = expr->argisrow;
return (Node *) newexpr;
}
}
break;
case T_BooleanTest:
{
BooleanTest *expr = (BooleanTest *) node;
BooleanTest *newexpr = makeNode(BooleanTest);
newexpr->arg = expr->arg;
switch (expr->booltesttype)
{
case IS_TRUE:
newexpr->booltesttype = IS_NOT_TRUE;
break;
case IS_NOT_TRUE:
newexpr->booltesttype = IS_TRUE;
break;
case IS_FALSE:
newexpr->booltesttype = IS_NOT_FALSE;
break;
case IS_NOT_FALSE:
newexpr->booltesttype = IS_FALSE;
break;
case IS_UNKNOWN:
newexpr->booltesttype = IS_NOT_UNKNOWN;
break;
case IS_NOT_UNKNOWN:
newexpr->booltesttype = IS_UNKNOWN;
break;
default:
elog(ERROR, "unrecognized booltesttype: %d",
(int) expr->booltesttype);
break;
}
return (Node *) newexpr;
}
break;
default:
/* else fall through */
break;
}
/*
* Otherwise we don't know how to simplify this, so just tack on an
* explicit NOT node.
*/
return (Node *) make_notclause((Expr *) node);
}
| Plan* plan_set_operations | ( | PlannerInfo * | root, | |
| double | tuple_fraction, | |||
| List ** | sortClauses | |||
| ) |
Definition at line 135 of file prepunion.c.
References Assert, Query::distinctClause, FromExpr::fromlist, generate_recursion_plan(), Query::groupClause, PlannerInfo::hasRecursion, Query::havingQual, IsA, Query::jointree, SetOperationStmt::larg, NIL, NULL, PlannerInfo::parse, parse(), FromExpr::quals, recurse_set_operations(), Query::setOperations, setup_simple_rel_arrays(), PlannerInfo::simple_rte_array, RangeTblEntry::subquery, and Query::windowClause.
Referenced by grouping_planner().
{
Query *parse = root->parse;
SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
Node *node;
RangeTblEntry *leftmostRTE;
Query *leftmostQuery;
Assert(topop && IsA(topop, SetOperationStmt));
/* check for unsupported stuff */
Assert(parse->jointree->fromlist == NIL);
Assert(parse->jointree->quals == NULL);
Assert(parse->groupClause == NIL);
Assert(parse->havingQual == NULL);
Assert(parse->windowClause == NIL);
Assert(parse->distinctClause == NIL);
/*
* We'll need to build RelOptInfos for each of the leaf subqueries, which
* are RTE_SUBQUERY rangetable entries in this Query. Prepare the index
* arrays for that.
*/
setup_simple_rel_arrays(root);
/*
* Find the leftmost component Query. We need to use its column names for
* all generated tlists (else SELECT INTO won't work right).
*/
node = topop->larg;
while (node && IsA(node, SetOperationStmt))
node = ((SetOperationStmt *) node)->larg;
Assert(node && IsA(node, RangeTblRef));
leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
leftmostQuery = leftmostRTE->subquery;
Assert(leftmostQuery != NULL);
/*
* If the topmost node is a recursive union, it needs special processing.
*/
if (root->hasRecursion)
return generate_recursion_plan(topop, root, tuple_fraction,
leftmostQuery->targetList,
sortClauses);
/*
* Recurse on setOperations tree to generate plans for set ops. The final
* output plan should have just the column types shown as the output from
* the top-level node, plus possibly resjunk working columns (we can rely
* on upper-level nodes to deal with that).
*/
return recurse_set_operations((Node *) topop, root, tuple_fraction,
topop->colTypes, topop->colCollations,
true, -1,
leftmostQuery->targetList,
sortClauses, NULL);
}
| List* preprocess_targetlist | ( | PlannerInfo * | root, | |
| List * | tlist | |||
| ) |
Definition at line 50 of file preptlist.c.
References CMD_INSERT, CMD_UPDATE, Query::commandType, elog, ERROR, expand_targetlist(), InvalidOid, IsA, PlanRowMark::isParent, lappend(), lfirst, list_free(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), PlanRowMark::markType, NULL, OIDOID, PlannerInfo::parse, parse(), PlanRowMark::prti, pstrdup(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, RangeTblEntry::relid, Query::resultRelation, Query::returningList, ROW_MARK_COPY, PlanRowMark::rowmarkId, PlannerInfo::rowMarks, rt_fetch, Query::rtable, PlanRowMark::rti, SelfItemPointerAttributeNumber, snprintf(), RangeTblEntry::subquery, TableOidAttributeNumber, TIDOID, tlist_member(), and Var::varno.
Referenced by grouping_planner(), and inheritance_planner().
{
Query *parse = root->parse;
int result_relation = parse->resultRelation;
List *range_table = parse->rtable;
CmdType command_type = parse->commandType;
ListCell *lc;
/*
* Sanity check: if there is a result relation, it'd better be a real
* relation not a subquery. Else parser or rewriter messed up.
*/
if (result_relation)
{
RangeTblEntry *rte = rt_fetch(result_relation, range_table);
if (rte->subquery != NULL || rte->relid == InvalidOid)
elog(ERROR, "subquery cannot be result relation");
}
/*
* for heap_form_tuple to work, the targetlist must match the exact order
* of the attributes. We also need to fill in any missing attributes. -ay
* 10/94
*/
if (command_type == CMD_INSERT || command_type == CMD_UPDATE)
tlist = expand_targetlist(tlist, command_type,
result_relation, range_table);
/*
* Add necessary junk columns for rowmarked rels. These values are needed
* for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
* rechecking. See comments for PlanRowMark in plannodes.h.
*/
foreach(lc, root->rowMarks)
{
PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
Var *var;
char resname[32];
TargetEntry *tle;
/* child rels use the same junk attrs as their parents */
if (rc->rti != rc->prti)
continue;
if (rc->markType != ROW_MARK_COPY)
{
/* It's a regular table, so fetch its TID */
var = makeVar(rc->rti,
SelfItemPointerAttributeNumber,
TIDOID,
-1,
InvalidOid,
0);
snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
tle = makeTargetEntry((Expr *) var,
list_length(tlist) + 1,
pstrdup(resname),
true);
tlist = lappend(tlist, tle);
/* if parent of inheritance tree, need the tableoid too */
if (rc->isParent)
{
var = makeVar(rc->rti,
TableOidAttributeNumber,
OIDOID,
-1,
InvalidOid,
0);
snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
tle = makeTargetEntry((Expr *) var,
list_length(tlist) + 1,
pstrdup(resname),
true);
tlist = lappend(tlist, tle);
}
}
else
{
/* Not a table, so we need the whole row as a junk var */
var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
rc->rti,
0,
false);
snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
tle = makeTargetEntry((Expr *) var,
list_length(tlist) + 1,
pstrdup(resname),
true);
tlist = lappend(tlist, tle);
}
}
/*
* If the query has a RETURNING list, add resjunk entries for any Vars
* used in RETURNING that belong to other relations. We need to do this
* to make these Vars available for the RETURNING calculation. Vars that
* belong to the result rel don't need to be added, because they will be
* made to refer to the actual heap tuple.
*/
if (parse->returningList && list_length(parse->rtable) > 1)
{
List *vars;
ListCell *l;
vars = pull_var_clause((Node *) parse->returningList,
PVC_RECURSE_AGGREGATES,
PVC_INCLUDE_PLACEHOLDERS);
foreach(l, vars)
{
Var *var = (Var *) lfirst(l);
TargetEntry *tle;
if (IsA(var, Var) &&
var->varno == result_relation)
continue; /* don't need it */
if (tlist_member((Node *) var, tlist))
continue; /* already got it */
tle = makeTargetEntry((Expr *) var,
list_length(tlist) + 1,
NULL,
true);
tlist = lappend(tlist, tle);
}
list_free(vars);
}
return tlist;
}
| void pull_up_sublinks | ( | PlannerInfo * | root | ) |
Definition at line 137 of file prepjointree.c.
References IsA, Query::jointree, list_make1, makeFromExpr(), NULL, PlannerInfo::parse, and pull_up_sublinks_jointree_recurse().
Referenced by pull_up_simple_subquery(), and subquery_planner().
{
Node *jtnode;
Relids relids;
/* Begin recursion through the jointree */
jtnode = pull_up_sublinks_jointree_recurse(root,
(Node *) root->parse->jointree,
&relids);
/*
* root->parse->jointree must always be a FromExpr, so insert a dummy one
* if we got a bare RangeTblRef or JoinExpr out of the recursion.
*/
if (IsA(jtnode, FromExpr))
root->parse->jointree = (FromExpr *) jtnode;
else
root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
}
| Node* pull_up_subqueries | ( | PlannerInfo * | root, | |
| Node * | jtnode | |||
| ) |
Definition at line 599 of file prepjointree.c.
References NULL, and pull_up_subqueries_recurse().
Referenced by subquery_planner().
{
/* Start off with no containing join nor appendrel */
return pull_up_subqueries_recurse(root, jtnode, NULL, NULL, NULL);
}
| void reduce_outer_joins | ( | PlannerInfo * | root | ) |
Definition at line 1897 of file prepjointree.c.
References reduce_outer_joins_state::contains_outer, elog, ERROR, Query::jointree, NIL, NULL, PlannerInfo::parse, reduce_outer_joins_pass1(), and reduce_outer_joins_pass2().
Referenced by subquery_planner().
{
reduce_outer_joins_state *state;
/*
* To avoid doing strictness checks on more quals than necessary, we want
* to stop descending the jointree as soon as there are no outer joins
* below our current point. This consideration forces a two-pass process.
* The first pass gathers information about which base rels appear below
* each side of each join clause, and about whether there are outer
* join(s) below each side of each join clause. The second pass examines
* qual clauses and changes join types as it descends the tree.
*/
state = reduce_outer_joins_pass1((Node *) root->parse->jointree);
/* planner.c shouldn't have called me if no outer joins */
if (state == NULL || !state->contains_outer)
elog(ERROR, "so where are the outer joins?");
reduce_outer_joins_pass2((Node *) root->parse->jointree,
state, root, NULL, NIL, NIL);
}
1.7.1