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

Go to the source code of this file.
Defines | |
| #define | DEFAULT_CURSOR_TUPLE_FRACTION 0.1 |
Typedefs | |
| typedef void(* | query_pathkeys_callback )(PlannerInfo *root, void *extra) |
Functions | |
| void | query_planner (PlannerInfo *root, List *tlist, double tuple_fraction, double limit_tuples, query_pathkeys_callback qp_callback, void *qp_extra, Path **cheapest_path, Path **sorted_path, double *num_groups) |
| void | preprocess_minmax_aggregates (PlannerInfo *root, List *tlist) |
| Plan * | optimize_minmax_aggregates (PlannerInfo *root, List *tlist, const AggClauseCosts *aggcosts, Path *best_path) |
| Plan * | create_plan (PlannerInfo *root, Path *best_path) |
| SubqueryScan * | make_subqueryscan (List *qptlist, List *qpqual, Index scanrelid, Plan *subplan) |
| ForeignScan * | make_foreignscan (List *qptlist, List *qpqual, Index scanrelid, List *fdw_exprs, List *fdw_private) |
| Append * | make_append (List *appendplans, List *tlist) |
| RecursiveUnion * | make_recursive_union (List *tlist, Plan *lefttree, Plan *righttree, int wtParam, List *distinctList, long numGroups) |
| Sort * | make_sort_from_pathkeys (PlannerInfo *root, Plan *lefttree, List *pathkeys, double limit_tuples) |
| Sort * | make_sort_from_sortclauses (PlannerInfo *root, List *sortcls, Plan *lefttree) |
| Sort * | make_sort_from_groupcols (PlannerInfo *root, List *groupcls, AttrNumber *grpColIdx, Plan *lefttree) |
| Agg * | make_agg (PlannerInfo *root, List *tlist, List *qual, AggStrategy aggstrategy, const AggClauseCosts *aggcosts, int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators, long numGroups, Plan *lefttree) |
| WindowAgg * | make_windowagg (PlannerInfo *root, List *tlist, List *windowFuncs, Index winref, int partNumCols, AttrNumber *partColIdx, Oid *partOperators, int ordNumCols, AttrNumber *ordColIdx, Oid *ordOperators, int frameOptions, Node *startOffset, Node *endOffset, Plan *lefttree) |
| Group * | make_group (PlannerInfo *root, List *tlist, List *qual, int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators, double numGroups, Plan *lefttree) |
| Plan * | materialize_finished_plan (Plan *subplan) |
| Unique * | make_unique (Plan *lefttree, List *distinctList) |
| LockRows * | make_lockrows (Plan *lefttree, List *rowMarks, int epqParam) |
| Limit * | make_limit (Plan *lefttree, Node *limitOffset, Node *limitCount, int64 offset_est, int64 count_est) |
| SetOp * | make_setop (SetOpCmd cmd, SetOpStrategy strategy, Plan *lefttree, List *distinctList, AttrNumber flagColIdx, int firstFlag, long numGroups, double outputRows) |
| Result * | make_result (PlannerInfo *root, List *tlist, Node *resconstantqual, Plan *subplan) |
| ModifyTable * | make_modifytable (PlannerInfo *root, CmdType operation, bool canSetTag, List *resultRelations, List *subplans, List *returningLists, List *rowMarks, int epqParam) |
| bool | is_projection_capable_plan (Plan *plan) |
| void | add_base_rels_to_query (PlannerInfo *root, Node *jtnode) |
| void | build_base_rel_tlists (PlannerInfo *root, List *final_tlist) |
| void | add_vars_to_targetlist (PlannerInfo *root, List *vars, Relids where_needed, bool create_new_ph) |
| void | find_lateral_references (PlannerInfo *root) |
| void | create_lateral_join_info (PlannerInfo *root) |
| List * | deconstruct_jointree (PlannerInfo *root) |
| void | distribute_restrictinfo_to_rels (PlannerInfo *root, RestrictInfo *restrictinfo) |
| void | process_implied_equality (PlannerInfo *root, Oid opno, Oid collation, Expr *item1, Expr *item2, Relids qualscope, Relids nullable_relids, bool below_outer_join, bool both_const) |
| RestrictInfo * | build_implied_join_equality (Oid opno, Oid collation, Expr *item1, Expr *item2, Relids qualscope, Relids nullable_relids) |
| List * | remove_useless_joins (PlannerInfo *root, List *joinlist) |
| Plan * | set_plan_references (PlannerInfo *root, Plan *plan) |
| void | fix_opfuncids (Node *node) |
| void | set_opfuncid (OpExpr *opexpr) |
| void | set_sa_opfuncid (ScalarArrayOpExpr *opexpr) |
| void | record_plan_function_dependency (PlannerInfo *root, Oid funcid) |
| void | extract_query_dependencies (Node *query, List **relationOids, List **invalItems) |
Variables | |
| double | cursor_tuple_fraction |
| int | from_collapse_limit |
| int | join_collapse_limit |
| #define DEFAULT_CURSOR_TUPLE_FRACTION 0.1 |
Definition at line 21 of file planmain.h.
| typedef void(* query_pathkeys_callback)(PlannerInfo *root, void *extra) |
Definition at line 25 of file planmain.h.
| void add_base_rels_to_query | ( | PlannerInfo * | root, | |
| Node * | jtnode | |||
| ) |
Definition at line 88 of file initsplan.c.
References add_base_rels_to_query(), build_simple_rel(), elog, ERROR, FromExpr::fromlist, IsA, JoinExpr::larg, lfirst, nodeTag, NULL, JoinExpr::rarg, and RELOPT_BASEREL.
Referenced by add_base_rels_to_query(), and query_planner().
{
if (jtnode == NULL)
return;
if (IsA(jtnode, RangeTblRef))
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
(void) build_simple_rel(root, varno, RELOPT_BASEREL);
}
else if (IsA(jtnode, FromExpr))
{
FromExpr *f = (FromExpr *) jtnode;
ListCell *l;
foreach(l, f->fromlist)
add_base_rels_to_query(root, lfirst(l));
}
else if (IsA(jtnode, JoinExpr))
{
JoinExpr *j = (JoinExpr *) jtnode;
add_base_rels_to_query(root, j->larg);
add_base_rels_to_query(root, j->rarg);
}
else
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(jtnode));
}
| void add_vars_to_targetlist | ( | PlannerInfo * | root, | |
| List * | vars, | |||
| Relids | where_needed, | |||
| bool | create_new_ph | |||
| ) |
Definition at line 163 of file initsplan.c.
References Assert, RelOptInfo::attr_needed, bms_add_members(), bms_is_empty(), bms_is_subset(), copyObject(), elog, ERROR, find_base_rel(), find_placeholder_info(), IsA, lappend(), lfirst, mark_placeholder_maybe_needed(), RelOptInfo::min_attr, nodeTag, NULL, PlaceHolderInfo::ph_may_need, PlaceHolderInfo::ph_needed, RelOptInfo::reltargetlist, RangeQueryClause::var, Var::varattno, and Var::varno.
Referenced by build_base_rel_tlists(), distribute_qual_to_rels(), extract_lateral_references(), fix_placeholder_input_needed_levels(), and generate_base_implied_equalities_no_const().
{
ListCell *temp;
Assert(!bms_is_empty(where_needed));
foreach(temp, vars)
{
Node *node = (Node *) lfirst(temp);
if (IsA(node, Var))
{
Var *var = (Var *) node;
RelOptInfo *rel = find_base_rel(root, var->varno);
int attno = var->varattno;
Assert(attno >= rel->min_attr && attno <= rel->max_attr);
attno -= rel->min_attr;
if (rel->attr_needed[attno] == NULL)
{
/* Variable not yet requested, so add to reltargetlist */
/* XXX is copyObject necessary here? */
rel->reltargetlist = lappend(rel->reltargetlist,
copyObject(var));
}
rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno],
where_needed);
}
else if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
PlaceHolderInfo *phinfo = find_placeholder_info(root, phv,
create_new_ph);
/* Always adjust ph_needed */
phinfo->ph_needed = bms_add_members(phinfo->ph_needed,
where_needed);
/*
* If we are creating PlaceHolderInfos, mark them with the correct
* maybe-needed locations. Otherwise, it's too late to change
* that, so we'd better not have set ph_needed to more than
* ph_may_need.
*/
if (create_new_ph)
mark_placeholder_maybe_needed(root, phinfo, where_needed);
else
Assert(bms_is_subset(phinfo->ph_needed, phinfo->ph_may_need));
}
else
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
}
}
| void build_base_rel_tlists | ( | PlannerInfo * | root, | |
| List * | final_tlist | |||
| ) |
Definition at line 134 of file initsplan.c.
References add_vars_to_targetlist(), bms_make_singleton(), list_free(), NIL, pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, and PVC_RECURSE_AGGREGATES.
Referenced by query_planner().
{
List *tlist_vars = pull_var_clause((Node *) final_tlist,
PVC_RECURSE_AGGREGATES,
PVC_INCLUDE_PLACEHOLDERS);
if (tlist_vars != NIL)
{
add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0), true);
list_free(tlist_vars);
}
}
| RestrictInfo* build_implied_join_equality | ( | Oid | opno, | |
| Oid | collation, | |||
| Expr * | item1, | |||
| Expr * | item2, | |||
| Relids | qualscope, | |||
| Relids | nullable_relids | |||
| ) |
Definition at line 1803 of file initsplan.c.
References BOOLOID, check_hashjoinable(), check_mergejoinable(), copyObject(), InvalidOid, make_opclause(), make_restrictinfo(), and NULL.
Referenced by create_join_clause(), reconsider_full_join_clause(), and reconsider_outer_join_clause().
{
RestrictInfo *restrictinfo;
Expr *clause;
/*
* Build the new clause. Copy to ensure it shares no substructure with
* original (this is necessary in case there are subselects in there...)
*/
clause = make_opclause(opno,
BOOLOID, /* opresulttype */
false, /* opretset */
(Expr *) copyObject(item1),
(Expr *) copyObject(item2),
InvalidOid,
collation);
/*
* Build the RestrictInfo node itself.
*/
restrictinfo = make_restrictinfo(clause,
true, /* is_pushed_down */
false, /* outerjoin_delayed */
false, /* pseudoconstant */
qualscope, /* required_relids */
NULL, /* outer_relids */
nullable_relids); /* nullable_relids */
/* Set mergejoinability/hashjoinability flags */
check_mergejoinable(restrictinfo);
check_hashjoinable(restrictinfo);
return restrictinfo;
}
| void create_lateral_join_info | ( | PlannerInfo * | root | ) |
Definition at line 377 of file initsplan.c.
References add_lateral_info(), PlannerInfo::append_rel_list, Assert, bms_add_member(), bms_add_members(), bms_copy(), bms_is_empty(), bms_make_singleton(), AppendRelInfo::child_relid, find_placeholder_info(), PlannerInfo::hasLateralRTEs, RangeTblEntry::inh, IsA, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, lfirst, NULL, AppendRelInfo::parent_relid, PlaceHolderInfo::ph_eval_at, RelOptInfo::relid, RELOPT_BASEREL, RELOPT_OTHER_MEMBER_REL, RelOptInfo::reloptkind, PlannerInfo::simple_rel_array, PlannerInfo::simple_rel_array_size, PlannerInfo::simple_rte_array, RangeQueryClause::var, and Var::varno.
Referenced by query_planner().
{
Index rti;
/* We need do nothing if the query contains no LATERAL RTEs */
if (!root->hasLateralRTEs)
return;
/*
* Examine all baserels (the rel array has been set up by now).
*/
for (rti = 1; rti < root->simple_rel_array_size; rti++)
{
RelOptInfo *brel = root->simple_rel_array[rti];
Relids lateral_relids;
ListCell *lc;
/* there may be empty slots corresponding to non-baserel RTEs */
if (brel == NULL)
continue;
Assert(brel->relid == rti); /* sanity check on array */
/* ignore RTEs that are "other rels" */
if (brel->reloptkind != RELOPT_BASEREL)
continue;
lateral_relids = NULL;
/* consider each laterally-referenced Var or PHV */
foreach(lc, brel->lateral_vars)
{
Node *node = (Node *) lfirst(lc);
if (IsA(node, Var))
{
Var *var = (Var *) node;
add_lateral_info(root, rti, bms_make_singleton(var->varno));
lateral_relids = bms_add_member(lateral_relids,
var->varno);
}
else if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
PlaceHolderInfo *phinfo = find_placeholder_info(root, phv,
false);
add_lateral_info(root, rti, bms_copy(phinfo->ph_eval_at));
lateral_relids = bms_add_members(lateral_relids,
phinfo->ph_eval_at);
}
else
Assert(false);
}
/* We now know all the relids needed for lateral refs in this rel */
if (bms_is_empty(lateral_relids))
continue; /* ensure lateral_relids is NULL if empty */
brel->lateral_relids = lateral_relids;
/*
* If it's an appendrel parent, copy its lateral_relids to each child
* rel. We intentionally give each child rel the same minimum
* parameterization, even though it's quite possible that some don't
* reference all the lateral rels. This is because any append path
* for the parent will have to have the same parameterization for
* every child anyway, and there's no value in forcing extra
* reparameterize_path() calls.
*/
if (root->simple_rte_array[rti]->inh)
{
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
RelOptInfo *childrel;
if (appinfo->parent_relid != rti)
continue;
childrel = root->simple_rel_array[appinfo->child_relid];
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
Assert(childrel->lateral_relids == NULL);
childrel->lateral_relids = lateral_relids;
}
}
}
}
| Plan* create_plan | ( | PlannerInfo * | root, | |
| Path * | best_path | |||
| ) |
Definition at line 189 of file createplan.c.
References Assert, create_plan_recurse(), PlannerInfo::curOuterParams, PlannerInfo::curOuterRels, elog, ERROR, NIL, and PlannerInfo::plan_params.
Referenced by grouping_planner(), and make_agg_subplan().
{
Plan *plan;
/* plan_params should not be in use in current query level */
Assert(root->plan_params == NIL);
/* Initialize this module's private workspace in PlannerInfo */
root->curOuterRels = NULL;
root->curOuterParams = NIL;
/* Recursively process the path tree */
plan = create_plan_recurse(root, best_path);
/* Check we successfully assigned all NestLoopParams to plan nodes */
if (root->curOuterParams != NIL)
elog(ERROR, "failed to assign all NestLoopParams to plan nodes");
/*
* Reset plan_params to ensure param IDs used for nestloop params are not
* re-used later
*/
root->plan_params = NIL;
return plan;
}
| List* deconstruct_jointree | ( | PlannerInfo * | root | ) |
Definition at line 538 of file initsplan.c.
References Assert, deconstruct_recurse(), IsA, Query::jointree, NULL, and PlannerInfo::parse.
Referenced by query_planner().
| void distribute_restrictinfo_to_rels | ( | PlannerInfo * | root, | |
| RestrictInfo * | restrictinfo | |||
| ) |
Definition at line 1662 of file initsplan.c.
References add_join_clause_to_rels(), RelOptInfo::baserestrictinfo, bms_membership(), BMS_MULTIPLE, BMS_SINGLETON, bms_singleton_member(), check_hashjoinable(), elog, ERROR, find_base_rel(), lappend(), and RestrictInfo::required_relids.
Referenced by distribute_qual_to_rels(), generate_base_implied_equalities_broken(), generate_base_implied_equalities_const(), reconsider_outer_join_clauses(), and remove_rel_from_query().
{
Relids relids = restrictinfo->required_relids;
RelOptInfo *rel;
switch (bms_membership(relids))
{
case BMS_SINGLETON:
/*
* There is only one relation participating in the clause, so it
* is a restriction clause for that relation.
*/
rel = find_base_rel(root, bms_singleton_member(relids));
/* Add clause to rel's restriction list */
rel->baserestrictinfo = lappend(rel->baserestrictinfo,
restrictinfo);
break;
case BMS_MULTIPLE:
/*
* The clause is a join clause, since there is more than one rel
* in its relid set.
*/
/*
* Check for hashjoinable operators. (We don't bother setting the
* hashjoin info except in true join clauses.)
*/
check_hashjoinable(restrictinfo);
/*
* Add clause to the join lists of all the relevant relations.
*/
add_join_clause_to_rels(root, restrictinfo, relids);
break;
default:
/*
* clause references no rels, and therefore we have no place to
* attach it. Shouldn't get here if callers are working properly.
*/
elog(ERROR, "cannot cope with variable-free clause");
break;
}
}
Definition at line 1904 of file setrefs.c.
References extract_query_dependencies_walker(), PlannerInfo::glob, PlannerGlobal::invalItems, MemSet, PlannerGlobal::relationOids, PlannerInfo::type, and PlannerGlobal::type.
Referenced by CompleteCachedPlan(), and RevalidateCachedQuery().
{
PlannerGlobal glob;
PlannerInfo root;
/* Make up dummy planner state so we can use this module's machinery */
MemSet(&glob, 0, sizeof(glob));
glob.type = T_PlannerGlobal;
glob.relationOids = NIL;
glob.invalItems = NIL;
MemSet(&root, 0, sizeof(root));
root.type = T_PlannerInfo;
root.glob = &glob;
(void) extract_query_dependencies_walker(query, &root);
*relationOids = glob.relationOids;
*invalItems = glob.invalItems;
}
| void find_lateral_references | ( | PlannerInfo * | root | ) |
Definition at line 240 of file initsplan.c.
References Assert, extract_lateral_references(), PlannerInfo::hasLateralRTEs, NULL, RelOptInfo::relid, RELOPT_BASEREL, RelOptInfo::reloptkind, PlannerInfo::simple_rel_array, and PlannerInfo::simple_rel_array_size.
Referenced by query_planner().
{
Index rti;
/* We need do nothing if the query contains no LATERAL RTEs */
if (!root->hasLateralRTEs)
return;
/*
* Examine all baserels (the rel array has been set up by now).
*/
for (rti = 1; rti < root->simple_rel_array_size; rti++)
{
RelOptInfo *brel = root->simple_rel_array[rti];
/* there may be empty slots corresponding to non-baserel RTEs */
if (brel == NULL)
continue;
Assert(brel->relid == rti); /* sanity check on array */
/*
* This bit is less obvious than it might look. We ignore appendrel
* otherrels and consider only their parent baserels. In a case where
* a LATERAL-containing UNION ALL subquery was pulled up, it is the
* otherrels that are actually going to be in the plan. However, we
* want to mark all their lateral references as needed by the parent,
* because it is the parent's relid that will be used for join
* planning purposes. And the parent's RTE will contain all the
* lateral references we need to know, since the pulled-up members are
* nothing but copies of parts of the original RTE's subquery. We
* could visit the children instead and transform their references
* back to the parent's relid, but it would be much more complicated
* for no real gain. (Important here is that the child members have
* not yet received any processing beyond being pulled up.)
*/
/* ignore RTEs that are "other rels" */
if (brel->reloptkind != RELOPT_BASEREL)
continue;
extract_lateral_references(root, brel, rti);
}
}
| void fix_opfuncids | ( | Node * | node | ) |
Definition at line 1807 of file setrefs.c.
References fix_opfuncids_walker(), and NULL.
Referenced by btree_predicate_proof(), evaluate_expr(), expression_planner(), RelationGetIndexExpressions(), and RelationGetIndexPredicate().
{
/* This tree walk requires no special setup, so away we go... */
fix_opfuncids_walker(node, NULL);
}
Definition at line 4837 of file createplan.c.
References nodeTag, T_Append, T_Hash, T_Limit, T_LockRows, T_Material, T_MergeAppend, T_ModifyTable, T_RecursiveUnion, T_SetOp, T_Sort, and T_Unique.
Referenced by create_unique_plan(), grouping_planner(), and prepare_sort_from_pathkeys().
{
/* Most plan types can project, so just list the ones that can't */
switch (nodeTag(plan))
{
case T_Hash:
case T_Material:
case T_Sort:
case T_Unique:
case T_SetOp:
case T_LockRows:
case T_Limit:
case T_ModifyTable:
case T_Append:
case T_MergeAppend:
case T_RecursiveUnion:
return false;
default:
break;
}
return true;
}
| Agg* make_agg | ( | PlannerInfo * | root, | |
| List * | tlist, | |||
| List * | qual, | |||
| AggStrategy | aggstrategy, | |||
| const AggClauseCosts * | aggcosts, | |||
| int | numGroupCols, | |||
| AttrNumber * | grpColIdx, | |||
| Oid * | grpOperators, | |||
| long | numGroups, | |||
| Plan * | lefttree | |||
| ) |
Definition at line 4274 of file createplan.c.
References add_tlist_costs_to_plan(), AGG_PLAIN, Agg::aggstrategy, copy_plan_costsize(), cost_agg(), cost_qual_eval(), Agg::grpColIdx, Agg::grpOperators, Plan::lefttree, makeNode, Agg::numCols, Agg::numGroups, QualCost::per_tuple, Agg::plan, Plan::plan_rows, Plan::qual, Plan::righttree, QualCost::startup, Path::startup_cost, Plan::startup_cost, Plan::targetlist, Path::total_cost, and Plan::total_cost.
Referenced by create_unique_plan(), grouping_planner(), and make_union_unique().
{
Agg *node = makeNode(Agg);
Plan *plan = &node->plan;
Path agg_path; /* dummy for result of cost_agg */
QualCost qual_cost;
node->aggstrategy = aggstrategy;
node->numCols = numGroupCols;
node->grpColIdx = grpColIdx;
node->grpOperators = grpOperators;
node->numGroups = numGroups;
copy_plan_costsize(plan, lefttree); /* only care about copying size */
cost_agg(&agg_path, root,
aggstrategy, aggcosts,
numGroupCols, numGroups,
lefttree->startup_cost,
lefttree->total_cost,
lefttree->plan_rows);
plan->startup_cost = agg_path.startup_cost;
plan->total_cost = agg_path.total_cost;
/*
* We will produce a single output tuple if not grouping, and a tuple per
* group otherwise.
*/
if (aggstrategy == AGG_PLAIN)
plan->plan_rows = 1;
else
plan->plan_rows = numGroups;
/*
* We also need to account for the cost of evaluation of the qual (ie, the
* HAVING clause) and the tlist. Note that cost_qual_eval doesn't charge
* anything for Aggref nodes; this is okay since they are really
* comparable to Vars.
*
* See notes in add_tlist_costs_to_plan about why only make_agg,
* make_windowagg and make_group worry about tlist eval cost.
*/
if (qual)
{
cost_qual_eval(&qual_cost, qual, root);
plan->startup_cost += qual_cost.startup;
plan->total_cost += qual_cost.startup;
plan->total_cost += qual_cost.per_tuple * plan->plan_rows;
}
add_tlist_costs_to_plan(root, plan, tlist);
plan->qual = qual;
plan->targetlist = tlist;
plan->lefttree = lefttree;
plan->righttree = NULL;
return node;
}
Definition at line 3498 of file createplan.c.
References Append::appendplans, Plan::lefttree, lfirst, list_head(), makeNode, Append::plan, Plan::plan_rows, Plan::plan_width, Plan::qual, Plan::righttree, rint(), Plan::startup_cost, Plan::targetlist, and Plan::total_cost.
Referenced by create_append_plan(), generate_nonunion_plan(), and generate_union_plan().
{
Append *node = makeNode(Append);
Plan *plan = &node->plan;
double total_size;
ListCell *subnode;
/*
* Compute cost as sum of subplan costs. We charge nothing extra for the
* Append itself, which perhaps is too optimistic, but since it doesn't do
* any selection or projection, it is a pretty cheap node.
*
* If you change this, see also create_append_path(). Also, the size
* calculations should match set_append_rel_pathlist(). It'd be better
* not to duplicate all this logic, but some callers of this function
* aren't working from an appendrel or AppendPath, so there's noplace to
* copy the data from.
*/
plan->startup_cost = 0;
plan->total_cost = 0;
plan->plan_rows = 0;
total_size = 0;
foreach(subnode, appendplans)
{
Plan *subplan = (Plan *) lfirst(subnode);
if (subnode == list_head(appendplans)) /* first node? */
plan->startup_cost = subplan->startup_cost;
plan->total_cost += subplan->total_cost;
plan->plan_rows += subplan->plan_rows;
total_size += subplan->plan_width * subplan->plan_rows;
}
if (plan->plan_rows > 0)
plan->plan_width = rint(total_size / plan->plan_rows);
else
plan->plan_width = 0;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = NULL;
plan->righttree = NULL;
node->appendplans = appendplans;
return node;
}
| ForeignScan* make_foreignscan | ( | List * | qptlist, | |
| List * | qpqual, | |||
| Index | scanrelid, | |||
| List * | fdw_exprs, | |||
| List * | fdw_private | |||
| ) |
Definition at line 3474 of file createplan.c.
References ForeignScan::fdw_exprs, ForeignScan::fdw_private, ForeignScan::fsSystemCol, Plan::lefttree, makeNode, Scan::plan, Plan::qual, Plan::righttree, ForeignScan::scan, Scan::scanrelid, and Plan::targetlist.
Referenced by fileGetForeignPlan(), and postgresGetForeignPlan().
{
ForeignScan *node = makeNode(ForeignScan);
Plan *plan = &node->scan.plan;
/* cost will be filled in by create_foreignscan_plan */
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->fdw_exprs = fdw_exprs;
node->fdw_private = fdw_private;
/* fsSystemCol will be filled in by create_foreignscan_plan */
node->fsSystemCol = false;
return node;
}
| Group* make_group | ( | PlannerInfo * | root, | |
| List * | tlist, | |||
| List * | qual, | |||
| int | numGroupCols, | |||
| AttrNumber * | grpColIdx, | |||
| Oid * | grpOperators, | |||
| double | numGroups, | |||
| Plan * | lefttree | |||
| ) |
Definition at line 4386 of file createplan.c.
References add_tlist_costs_to_plan(), copy_plan_costsize(), cost_group(), cost_qual_eval(), Group::grpColIdx, Group::grpOperators, Plan::lefttree, makeNode, Group::numCols, QualCost::per_tuple, Group::plan, Plan::plan_rows, Plan::qual, Plan::righttree, QualCost::startup, Path::startup_cost, Plan::startup_cost, Plan::targetlist, Path::total_cost, and Plan::total_cost.
Referenced by grouping_planner().
{
Group *node = makeNode(Group);
Plan *plan = &node->plan;
Path group_path; /* dummy for result of cost_group */
QualCost qual_cost;
node->numCols = numGroupCols;
node->grpColIdx = grpColIdx;
node->grpOperators = grpOperators;
copy_plan_costsize(plan, lefttree); /* only care about copying size */
cost_group(&group_path, root,
numGroupCols, numGroups,
lefttree->startup_cost,
lefttree->total_cost,
lefttree->plan_rows);
plan->startup_cost = group_path.startup_cost;
plan->total_cost = group_path.total_cost;
/* One output tuple per estimated result group */
plan->plan_rows = numGroups;
/*
* We also need to account for the cost of evaluation of the qual (ie, the
* HAVING clause) and the tlist.
*
* XXX this double-counts the cost of evaluation of any expressions used
* for grouping, since in reality those will have been evaluated at a
* lower plan level and will only be copied by the Group node. Worth
* fixing?
*
* See notes in add_tlist_costs_to_plan about why only make_agg,
* make_windowagg and make_group worry about tlist eval cost.
*/
if (qual)
{
cost_qual_eval(&qual_cost, qual, root);
plan->startup_cost += qual_cost.startup;
plan->total_cost += qual_cost.startup;
plan->total_cost += qual_cost.per_tuple * plan->plan_rows;
}
add_tlist_costs_to_plan(root, plan, tlist);
plan->qual = qual;
plan->targetlist = tlist;
plan->lefttree = lefttree;
plan->righttree = NULL;
return node;
}
| Limit* make_limit | ( | Plan * | lefttree, | |
| Node * | limitOffset, | |||
| Node * | limitCount, | |||
| int64 | offset_est, | |||
| int64 | count_est | |||
| ) |
Definition at line 4604 of file createplan.c.
References clamp_row_est(), copy_plan_costsize(), Plan::lefttree, Limit::limitCount, Limit::limitOffset, makeNode, Limit::plan, Plan::plan_rows, Plan::qual, Plan::righttree, Plan::startup_cost, Plan::targetlist, and Plan::total_cost.
Referenced by make_agg_subplan().
{
Limit *node = makeNode(Limit);
Plan *plan = &node->plan;
copy_plan_costsize(plan, lefttree);
/*
* Adjust the output rows count and costs according to the offset/limit.
* This is only a cosmetic issue if we are at top level, but if we are
* building a subquery then it's important to report correct info to the
* outer planner.
*
* When the offset or count couldn't be estimated, use 10% of the
* estimated number of rows emitted from the subplan.
*/
if (offset_est != 0)
{
double offset_rows;
if (offset_est > 0)
offset_rows = (double) offset_est;
else
offset_rows = clamp_row_est(lefttree->plan_rows * 0.10);
if (offset_rows > plan->plan_rows)
offset_rows = plan->plan_rows;
if (plan->plan_rows > 0)
plan->startup_cost +=
(plan->total_cost - plan->startup_cost)
* offset_rows / plan->plan_rows;
plan->plan_rows -= offset_rows;
if (plan->plan_rows < 1)
plan->plan_rows = 1;
}
if (count_est != 0)
{
double count_rows;
if (count_est > 0)
count_rows = (double) count_est;
else
count_rows = clamp_row_est(lefttree->plan_rows * 0.10);
if (count_rows > plan->plan_rows)
count_rows = plan->plan_rows;
if (plan->plan_rows > 0)
plan->total_cost = plan->startup_cost +
(plan->total_cost - plan->startup_cost)
* count_rows / plan->plan_rows;
plan->plan_rows = count_rows;
if (plan->plan_rows < 1)
plan->plan_rows = 1;
}
plan->targetlist = lefttree->targetlist;
plan->qual = NIL;
plan->lefttree = lefttree;
plan->righttree = NULL;
node->limitOffset = limitOffset;
node->limitCount = limitCount;
return node;
}
Definition at line 4575 of file createplan.c.
References copy_plan_costsize(), cpu_tuple_cost, LockRows::epqParam, Plan::lefttree, makeNode, LockRows::plan, Plan::plan_rows, Plan::qual, Plan::righttree, LockRows::rowMarks, Plan::targetlist, and Plan::total_cost.
{
LockRows *node = makeNode(LockRows);
Plan *plan = &node->plan;
copy_plan_costsize(plan, lefttree);
/* charge cpu_tuple_cost to reflect locking costs (underestimate?) */
plan->total_cost += cpu_tuple_cost * plan->plan_rows;
plan->targetlist = lefttree->targetlist;
plan->qual = NIL;
plan->lefttree = lefttree;
plan->righttree = NULL;
node->rowMarks = rowMarks;
node->epqParam = epqParam;
return node;
}
| ModifyTable* make_modifytable | ( | PlannerInfo * | root, | |
| CmdType | operation, | |||
| bool | canSetTag, | |||
| List * | resultRelations, | |||
| List * | subplans, | |||
| List * | returningLists, | |||
| List * | rowMarks, | |||
| int | epqParam | |||
| ) |
Definition at line 4727 of file createplan.c.
References Assert, ModifyTable::canSetTag, ModifyTable::epqParam, ModifyTable::fdwPrivLists, RelOptInfo::fdwroutine, GetFdwRoutineByRelId(), i, lappend(), Plan::lefttree, lfirst, lfirst_int, list_head(), list_length(), makeNode, NIL, NULL, ModifyTable::operation, ModifyTable::plan, Plan::plan_rows, Plan::plan_width, FdwRoutine::PlanForeignModify, planner_rt_fetch, ModifyTable::plans, Plan::qual, RangeTblEntry::relid, RangeTblEntry::relkind, RELKIND_FOREIGN_TABLE, ModifyTable::resultRelations, ModifyTable::resultRelIndex, ModifyTable::returningLists, Plan::righttree, rint(), ModifyTable::rowMarks, RTE_RELATION, RangeTblEntry::rtekind, PlannerInfo::simple_rel_array, Plan::startup_cost, Plan::targetlist, and Plan::total_cost.
Referenced by inheritance_planner(), and subquery_planner().
{
ModifyTable *node = makeNode(ModifyTable);
Plan *plan = &node->plan;
double total_size;
List *fdw_private_list;
ListCell *subnode;
ListCell *lc;
int i;
Assert(list_length(resultRelations) == list_length(subplans));
Assert(returningLists == NIL ||
list_length(resultRelations) == list_length(returningLists));
/*
* Compute cost as sum of subplan costs.
*/
plan->startup_cost = 0;
plan->total_cost = 0;
plan->plan_rows = 0;
total_size = 0;
foreach(subnode, subplans)
{
Plan *subplan = (Plan *) lfirst(subnode);
if (subnode == list_head(subplans)) /* first node? */
plan->startup_cost = subplan->startup_cost;
plan->total_cost += subplan->total_cost;
plan->plan_rows += subplan->plan_rows;
total_size += subplan->plan_width * subplan->plan_rows;
}
if (plan->plan_rows > 0)
plan->plan_width = rint(total_size / plan->plan_rows);
else
plan->plan_width = 0;
node->plan.lefttree = NULL;
node->plan.righttree = NULL;
node->plan.qual = NIL;
/* setrefs.c will fill in the targetlist, if needed */
node->plan.targetlist = NIL;
node->operation = operation;
node->canSetTag = canSetTag;
node->resultRelations = resultRelations;
node->resultRelIndex = -1; /* will be set correctly in setrefs.c */
node->plans = subplans;
node->returningLists = returningLists;
node->rowMarks = rowMarks;
node->epqParam = epqParam;
/*
* For each result relation that is a foreign table, allow the FDW to
* construct private plan data, and accumulate it all into a list.
*/
fdw_private_list = NIL;
i = 0;
foreach(lc, resultRelations)
{
Index rti = lfirst_int(lc);
FdwRoutine *fdwroutine;
List *fdw_private;
/*
* If possible, we want to get the FdwRoutine from our RelOptInfo for
* the table. But sometimes we don't have a RelOptInfo and must get
* it the hard way. (In INSERT, the target relation is not scanned,
* so it's not a baserel; and there are also corner cases for
* updatable views where the target rel isn't a baserel.)
*/
if (rti < root->simple_rel_array_size &&
root->simple_rel_array[rti] != NULL)
{
RelOptInfo *resultRel = root->simple_rel_array[rti];
fdwroutine = resultRel->fdwroutine;
}
else
{
RangeTblEntry *rte = planner_rt_fetch(rti, root);
Assert(rte->rtekind == RTE_RELATION);
if (rte->relkind == RELKIND_FOREIGN_TABLE)
fdwroutine = GetFdwRoutineByRelId(rte->relid);
else
fdwroutine = NULL;
}
if (fdwroutine != NULL &&
fdwroutine->PlanForeignModify != NULL)
fdw_private = fdwroutine->PlanForeignModify(root, node, rti, i);
else
fdw_private = NIL;
fdw_private_list = lappend(fdw_private_list, fdw_private);
i++;
}
node->fdwPrivLists = fdw_private_list;
return node;
}
| RecursiveUnion* make_recursive_union | ( | List * | tlist, | |
| Plan * | lefttree, | |||
| Plan * | righttree, | |||
| int | wtParam, | |||
| List * | distinctList, | |||
| long | numGroups | |||
| ) |
Definition at line 3545 of file createplan.c.
References Assert, cost_recursive_union(), RecursiveUnion::dupColIdx, RecursiveUnion::dupOperators, SortGroupClause::eqop, get_sortgroupclause_tle(), Plan::lefttree, lfirst, list_length(), makeNode, RecursiveUnion::numCols, RecursiveUnion::numGroups, OidIsValid, palloc(), RecursiveUnion::plan, Plan::qual, TargetEntry::resno, Plan::righttree, Plan::targetlist, and RecursiveUnion::wtParam.
Referenced by generate_recursion_plan().
{
RecursiveUnion *node = makeNode(RecursiveUnion);
Plan *plan = &node->plan;
int numCols = list_length(distinctList);
cost_recursive_union(plan, lefttree, righttree);
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = lefttree;
plan->righttree = righttree;
node->wtParam = wtParam;
/*
* convert SortGroupClause list into arrays of attr indexes and equality
* operators, as wanted by executor
*/
node->numCols = numCols;
if (numCols > 0)
{
int keyno = 0;
AttrNumber *dupColIdx;
Oid *dupOperators;
ListCell *slitem;
dupColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
dupOperators = (Oid *) palloc(sizeof(Oid) * numCols);
foreach(slitem, distinctList)
{
SortGroupClause *sortcl = (SortGroupClause *) lfirst(slitem);
TargetEntry *tle = get_sortgroupclause_tle(sortcl,
plan->targetlist);
dupColIdx[keyno] = tle->resno;
dupOperators[keyno] = sortcl->eqop;
Assert(OidIsValid(dupOperators[keyno]));
keyno++;
}
node->dupColIdx = dupColIdx;
node->dupOperators = dupOperators;
}
node->numGroups = numGroups;
return node;
}
| Result* make_result | ( | PlannerInfo * | root, | |
| List * | tlist, | |||
| Node * | resconstantqual, | |||
| Plan * | subplan | |||
| ) |
Definition at line 4680 of file createplan.c.
References copy_plan_costsize(), cost_qual_eval(), cpu_tuple_cost, Plan::lefttree, makeNode, QualCost::per_tuple, Result::plan, Plan::plan_rows, Plan::plan_width, Plan::qual, Result::resconstantqual, Plan::righttree, QualCost::startup, Plan::startup_cost, Plan::targetlist, and Plan::total_cost.
Referenced by create_append_plan(), create_gating_plan(), create_result_plan(), create_unique_plan(), float4_numeric(), float8_numeric(), grouping_planner(), inheritance_planner(), int2_numeric(), int4_numeric(), int8_numeric(), numeric(), numeric_abs(), numeric_add(), numeric_ceil(), numeric_div(), numeric_div_trunc(), numeric_exp(), numeric_fac(), numeric_floor(), numeric_in(), numeric_inc(), numeric_ln(), numeric_log(), numeric_mod(), numeric_mul(), numeric_power(), numeric_recv(), numeric_round(), numeric_sign(), numeric_sqrt(), numeric_stddev_internal(), numeric_sub(), numeric_trunc(), numeric_uminus(), optimize_minmax_aggregates(), prepare_sort_from_pathkeys(), and recurse_set_operations().
{
Result *node = makeNode(Result);
Plan *plan = &node->plan;
if (subplan)
copy_plan_costsize(plan, subplan);
else
{
plan->startup_cost = 0;
plan->total_cost = cpu_tuple_cost;
plan->plan_rows = 1; /* wrong if we have a set-valued function? */
plan->plan_width = 0; /* XXX is it worth being smarter? */
if (resconstantqual)
{
QualCost qual_cost;
cost_qual_eval(&qual_cost, (List *) resconstantqual, root);
/* resconstantqual is evaluated once at startup */
plan->startup_cost += qual_cost.startup + qual_cost.per_tuple;
plan->total_cost += qual_cost.startup + qual_cost.per_tuple;
}
}
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = subplan;
plan->righttree = NULL;
node->resconstantqual = resconstantqual;
return node;
}
| SetOp* make_setop | ( | SetOpCmd | cmd, | |
| SetOpStrategy | strategy, | |||
| Plan * | lefttree, | |||
| List * | distinctList, | |||
| AttrNumber | flagColIdx, | |||
| int | firstFlag, | |||
| long | numGroups, | |||
| double | outputRows | |||
| ) |
Definition at line 4513 of file createplan.c.
References Assert, SetOp::cmd, copy_plan_costsize(), cpu_operator_cost, SetOp::dupColIdx, SetOp::dupOperators, SortGroupClause::eqop, SetOp::firstFlag, SetOp::flagColIdx, get_sortgroupclause_tle(), Plan::lefttree, lfirst, list_length(), makeNode, SetOp::numCols, SetOp::numGroups, OidIsValid, palloc(), SetOp::plan, Plan::plan_rows, Plan::qual, TargetEntry::resno, Plan::righttree, SetOp::strategy, Plan::targetlist, and Plan::total_cost.
Referenced by generate_nonunion_plan().
{
SetOp *node = makeNode(SetOp);
Plan *plan = &node->plan;
int numCols = list_length(distinctList);
int keyno = 0;
AttrNumber *dupColIdx;
Oid *dupOperators;
ListCell *slitem;
copy_plan_costsize(plan, lefttree);
plan->plan_rows = outputRows;
/*
* Charge one cpu_operator_cost per comparison per input tuple. We assume
* all columns get compared at most of the tuples.
*/
plan->total_cost += cpu_operator_cost * lefttree->plan_rows * numCols;
plan->targetlist = lefttree->targetlist;
plan->qual = NIL;
plan->lefttree = lefttree;
plan->righttree = NULL;
/*
* convert SortGroupClause list into arrays of attr indexes and equality
* operators, as wanted by executor
*/
Assert(numCols > 0);
dupColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
dupOperators = (Oid *) palloc(sizeof(Oid) * numCols);
foreach(slitem, distinctList)
{
SortGroupClause *sortcl = (SortGroupClause *) lfirst(slitem);
TargetEntry *tle = get_sortgroupclause_tle(sortcl, plan->targetlist);
dupColIdx[keyno] = tle->resno;
dupOperators[keyno] = sortcl->eqop;
Assert(OidIsValid(dupOperators[keyno]));
keyno++;
}
node->cmd = cmd;
node->strategy = strategy;
node->numCols = numCols;
node->dupColIdx = dupColIdx;
node->dupOperators = dupOperators;
node->flagColIdx = flagColIdx;
node->firstFlag = firstFlag;
node->numGroups = numGroups;
return node;
}
| Sort* make_sort_from_groupcols | ( | PlannerInfo * | root, | |
| List * | groupcls, | |||
| AttrNumber * | grpColIdx, | |||
| Plan * | lefttree | |||
| ) |
Definition at line 4184 of file createplan.c.
References TargetEntry::expr, exprCollation(), get_tle_by_resno(), lfirst, list_length(), make_sort(), SortGroupClause::nulls_first, palloc(), TargetEntry::resno, SortGroupClause::sortop, and Plan::targetlist.
Referenced by grouping_planner().
{
List *sub_tlist = lefttree->targetlist;
ListCell *l;
int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *collations;
bool *nullsFirst;
/* Convert list-ish representation to arrays wanted by executor */
numsortkeys = list_length(groupcls);
sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
collations = (Oid *) palloc(numsortkeys * sizeof(Oid));
nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
numsortkeys = 0;
foreach(l, groupcls)
{
SortGroupClause *grpcl = (SortGroupClause *) lfirst(l);
TargetEntry *tle = get_tle_by_resno(sub_tlist, grpColIdx[numsortkeys]);
sortColIdx[numsortkeys] = tle->resno;
sortOperators[numsortkeys] = grpcl->sortop;
collations[numsortkeys] = exprCollation((Node *) tle->expr);
nullsFirst[numsortkeys] = grpcl->nulls_first;
numsortkeys++;
}
return make_sort(root, lefttree, numsortkeys,
sortColIdx, sortOperators, collations,
nullsFirst, -1.0);
}
| Sort* make_sort_from_pathkeys | ( | PlannerInfo * | root, | |
| Plan * | lefttree, | |||
| List * | pathkeys, | |||
| double | limit_tuples | |||
| ) |
Definition at line 4101 of file createplan.c.
References make_sort(), NULL, and prepare_sort_from_pathkeys().
Referenced by create_mergejoin_plan(), and grouping_planner().
{
int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *collations;
bool *nullsFirst;
/* Compute sort column info, and adjust lefttree as needed */
lefttree = prepare_sort_from_pathkeys(root, lefttree, pathkeys,
NULL,
NULL,
false,
&numsortkeys,
&sortColIdx,
&sortOperators,
&collations,
&nullsFirst);
/* Now build the Sort node */
return make_sort(root, lefttree, numsortkeys,
sortColIdx, sortOperators, collations,
nullsFirst, limit_tuples);
}
| Sort* make_sort_from_sortclauses | ( | PlannerInfo * | root, | |
| List * | sortcls, | |||
| Plan * | lefttree | |||
| ) |
Definition at line 4135 of file createplan.c.
References TargetEntry::expr, exprCollation(), get_sortgroupclause_tle(), lfirst, list_length(), make_sort(), SortGroupClause::nulls_first, palloc(), TargetEntry::resno, SortGroupClause::sortop, and Plan::targetlist.
Referenced by create_unique_plan(), generate_nonunion_plan(), and make_union_unique().
{
List *sub_tlist = lefttree->targetlist;
ListCell *l;
int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *collations;
bool *nullsFirst;
/* Convert list-ish representation to arrays wanted by executor */
numsortkeys = list_length(sortcls);
sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
collations = (Oid *) palloc(numsortkeys * sizeof(Oid));
nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
numsortkeys = 0;
foreach(l, sortcls)
{
SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
TargetEntry *tle = get_sortgroupclause_tle(sortcl, sub_tlist);
sortColIdx[numsortkeys] = tle->resno;
sortOperators[numsortkeys] = sortcl->sortop;
collations[numsortkeys] = exprCollation((Node *) tle->expr);
nullsFirst[numsortkeys] = sortcl->nulls_first;
numsortkeys++;
}
return make_sort(root, lefttree, numsortkeys,
sortColIdx, sortOperators, collations,
nullsFirst, -1.0);
}
| SubqueryScan* make_subqueryscan | ( | List * | qptlist, | |
| List * | qpqual, | |||
| Index | scanrelid, | |||
| Plan * | subplan | |||
| ) |
Definition at line 3357 of file createplan.c.
References copy_plan_costsize(), cpu_tuple_cost, Plan::lefttree, makeNode, Scan::plan, Plan::plan_rows, Plan::qual, Plan::righttree, SubqueryScan::scan, Scan::scanrelid, SubqueryScan::subplan, Plan::targetlist, and Plan::total_cost.
Referenced by create_append_plan(), create_subqueryscan_plan(), and recurse_set_operations().
{
SubqueryScan *node = makeNode(SubqueryScan);
Plan *plan = &node->scan.plan;
/*
* Cost is figured here for the convenience of prepunion.c. Note this is
* only correct for the case where qpqual is empty; otherwise caller
* should overwrite cost with a better estimate.
*/
copy_plan_costsize(plan, subplan);
plan->total_cost += cpu_tuple_cost * subplan->plan_rows;
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->subplan = subplan;
return node;
}
Definition at line 4451 of file createplan.c.
References Assert, copy_plan_costsize(), cpu_operator_cost, SortGroupClause::eqop, get_sortgroupclause_tle(), Plan::lefttree, lfirst, list_length(), makeNode, Unique::numCols, OidIsValid, palloc(), Unique::plan, Plan::plan_rows, Plan::qual, TargetEntry::resno, Plan::righttree, Plan::targetlist, Plan::total_cost, Unique::uniqColIdx, and Unique::uniqOperators.
Referenced by create_unique_plan(), grouping_planner(), and make_union_unique().
{
Unique *node = makeNode(Unique);
Plan *plan = &node->plan;
int numCols = list_length(distinctList);
int keyno = 0;
AttrNumber *uniqColIdx;
Oid *uniqOperators;
ListCell *slitem;
copy_plan_costsize(plan, lefttree);
/*
* Charge one cpu_operator_cost per comparison per input tuple. We assume
* all columns get compared at most of the tuples. (XXX probably this is
* an overestimate.)
*/
plan->total_cost += cpu_operator_cost * plan->plan_rows * numCols;
/*
* plan->plan_rows is left as a copy of the input subplan's plan_rows; ie,
* we assume the filter removes nothing. The caller must alter this if he
* has a better idea.
*/
plan->targetlist = lefttree->targetlist;
plan->qual = NIL;
plan->lefttree = lefttree;
plan->righttree = NULL;
/*
* convert SortGroupClause list into arrays of attr indexes and equality
* operators, as wanted by executor
*/
Assert(numCols > 0);
uniqColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
uniqOperators = (Oid *) palloc(sizeof(Oid) * numCols);
foreach(slitem, distinctList)
{
SortGroupClause *sortcl = (SortGroupClause *) lfirst(slitem);
TargetEntry *tle = get_sortgroupclause_tle(sortcl, plan->targetlist);
uniqColIdx[keyno] = tle->resno;
uniqOperators[keyno] = sortcl->eqop;
Assert(OidIsValid(uniqOperators[keyno]));
keyno++;
}
node->numCols = numCols;
node->uniqColIdx = uniqColIdx;
node->uniqOperators = uniqOperators;
return node;
}
| WindowAgg* make_windowagg | ( | PlannerInfo * | root, | |
| List * | tlist, | |||
| List * | windowFuncs, | |||
| Index | winref, | |||
| int | partNumCols, | |||
| AttrNumber * | partColIdx, | |||
| Oid * | partOperators, | |||
| int | ordNumCols, | |||
| AttrNumber * | ordColIdx, | |||
| Oid * | ordOperators, | |||
| int | frameOptions, | |||
| Node * | startOffset, | |||
| Node * | endOffset, | |||
| Plan * | lefttree | |||
| ) |
Definition at line 4337 of file createplan.c.
References add_tlist_costs_to_plan(), copy_plan_costsize(), cost_windowagg(), WindowAgg::endOffset, WindowAgg::frameOptions, Plan::lefttree, makeNode, WindowAgg::ordColIdx, WindowAgg::ordNumCols, WindowAgg::ordOperators, WindowAgg::partColIdx, WindowAgg::partNumCols, WindowAgg::partOperators, WindowAgg::plan, Plan::plan_rows, Plan::qual, Plan::righttree, WindowAgg::startOffset, Path::startup_cost, Plan::startup_cost, Plan::targetlist, Path::total_cost, Plan::total_cost, and WindowAgg::winref.
Referenced by grouping_planner().
{
WindowAgg *node = makeNode(WindowAgg);
Plan *plan = &node->plan;
Path windowagg_path; /* dummy for result of cost_windowagg */
node->winref = winref;
node->partNumCols = partNumCols;
node->partColIdx = partColIdx;
node->partOperators = partOperators;
node->ordNumCols = ordNumCols;
node->ordColIdx = ordColIdx;
node->ordOperators = ordOperators;
node->frameOptions = frameOptions;
node->startOffset = startOffset;
node->endOffset = endOffset;
copy_plan_costsize(plan, lefttree); /* only care about copying size */
cost_windowagg(&windowagg_path, root,
windowFuncs, partNumCols, ordNumCols,
lefttree->startup_cost,
lefttree->total_cost,
lefttree->plan_rows);
plan->startup_cost = windowagg_path.startup_cost;
plan->total_cost = windowagg_path.total_cost;
/*
* We also need to account for the cost of evaluation of the tlist.
*
* See notes in add_tlist_costs_to_plan about why only make_agg,
* make_windowagg and make_group worry about tlist eval cost.
*/
add_tlist_costs_to_plan(root, plan, tlist);
plan->targetlist = tlist;
plan->lefttree = lefttree;
plan->righttree = NULL;
/* WindowAgg nodes never have a qual clause */
plan->qual = NIL;
return node;
}
Definition at line 4248 of file createplan.c.
References Plan::allParam, bms_copy(), cost_material(), Plan::extParam, make_material(), Plan::plan_rows, Plan::plan_width, Path::startup_cost, Plan::startup_cost, Path::total_cost, and Plan::total_cost.
Referenced by build_subplan(), and standard_planner().
{
Plan *matplan;
Path matpath; /* dummy for result of cost_material */
matplan = (Plan *) make_material(subplan);
/* Set cost data */
cost_material(&matpath,
subplan->startup_cost,
subplan->total_cost,
subplan->plan_rows,
subplan->plan_width);
matplan->startup_cost = matpath.startup_cost;
matplan->total_cost = matpath.total_cost;
matplan->plan_rows = subplan->plan_rows;
matplan->plan_width = subplan->plan_width;
/* parameter kluge --- see comments above */
matplan->extParam = bms_copy(subplan->extParam);
matplan->allParam = bms_copy(subplan->allParam);
return matplan;
}
| Plan* optimize_minmax_aggregates | ( | PlannerInfo * | root, | |
| List * | tlist, | |||
| const AggClauseCosts * | aggcosts, | |||
| Path * | best_path | |||
| ) |
Definition at line 203 of file planagg.c.
References add_tlist_costs_to_plan(), AGG_PLAIN, cost_agg(), Query::havingQual, lfirst, make_agg_subplan(), make_result(), PlannerInfo::minmax_aggs, mutate_eclass_expressions(), NIL, NULL, Path::parent, PlannerInfo::parse, parse(), MinMaxAggInfo::pathcost, replace_aggs_with_params_mutator(), RelOptInfo::rows, Path::startup_cost, and Path::total_cost.
Referenced by grouping_planner().
{
Query *parse = root->parse;
Cost total_cost;
Path agg_p;
Plan *plan;
Node *hqual;
ListCell *lc;
/* Nothing to do if preprocess_minmax_aggs rejected the query */
if (root->minmax_aggs == NIL)
return NULL;
/*
* Now we have enough info to compare costs against the generic aggregate
* implementation.
*
* Note that we don't include evaluation cost of the tlist here; this is
* OK since it isn't included in best_path's cost either, and should be
* the same in either case.
*/
total_cost = 0;
foreach(lc, root->minmax_aggs)
{
MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
total_cost += mminfo->pathcost;
}
cost_agg(&agg_p, root, AGG_PLAIN, aggcosts,
0, 0,
best_path->startup_cost, best_path->total_cost,
best_path->parent->rows);
if (total_cost > agg_p.total_cost)
return NULL; /* too expensive */
/*
* OK, we are going to generate an optimized plan.
*
* First, generate a subplan and output Param node for each agg.
*/
foreach(lc, root->minmax_aggs)
{
MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
make_agg_subplan(root, mminfo);
}
/*
* Modify the targetlist and HAVING qual to reference subquery outputs
*/
tlist = (List *) replace_aggs_with_params_mutator((Node *) tlist, root);
hqual = replace_aggs_with_params_mutator(parse->havingQual, root);
/*
* We have to replace Aggrefs with Params in equivalence classes too, else
* ORDER BY or DISTINCT on an optimized aggregate will fail. We don't
* need to process child eclass members though, since they aren't of
* interest anymore --- and replace_aggs_with_params_mutator isn't able
* to handle Aggrefs containing translated child Vars, anyway.
*
* Note: at some point it might become necessary to mutate other data
* structures too, such as the query's sortClause or distinctClause. Right
* now, those won't be examined after this point.
*/
mutate_eclass_expressions(root,
replace_aggs_with_params_mutator,
(void *) root,
false);
/*
* Generate the output plan --- basically just a Result
*/
plan = (Plan *) make_result(root, tlist, hqual, NULL);
/* Account for evaluation cost of the tlist (make_result did the rest) */
add_tlist_costs_to_plan(root, plan, tlist);
return plan;
}
| void preprocess_minmax_aggregates | ( | PlannerInfo * | root, | |
| List * | tlist | |||
| ) |
Definition at line 69 of file planagg.c.
References MinMaxAggInfo::aggsortop, Assert, build_minmax_path(), elog, ERROR, find_minmax_aggs_walker(), FromExpr::fromlist, get_equality_op_for_ordering_op(), Query::groupClause, Query::hasAggs, Query::hasWindowFuncs, Query::havingQual, RangeTblEntry::inh, IsA, Query::jointree, lfirst, linitial, list_length(), PlannerInfo::minmax_aggs, NIL, OidIsValid, PlannerInfo::parse, parse(), planner_rt_fetch, Query::rowMarks, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblRef::rtindex, and Query::setOperations.
Referenced by grouping_planner().
{
Query *parse = root->parse;
FromExpr *jtnode;
RangeTblRef *rtr;
RangeTblEntry *rte;
List *aggs_list;
ListCell *lc;
/* minmax_aggs list should be empty at this point */
Assert(root->minmax_aggs == NIL);
/* Nothing to do if query has no aggregates */
if (!parse->hasAggs)
return;
Assert(!parse->setOperations); /* shouldn't get here if a setop */
Assert(parse->rowMarks == NIL); /* nor if FOR UPDATE */
/*
* Reject unoptimizable cases.
*
* We don't handle GROUP BY or windowing, because our current
* implementations of grouping require looking at all the rows anyway, and
* so there's not much point in optimizing MIN/MAX. (Note: relaxing this
* would likely require some restructuring in grouping_planner(), since it
* performs assorted processing related to these features between calling
* preprocess_minmax_aggregates and optimize_minmax_aggregates.)
*/
if (parse->groupClause || parse->hasWindowFuncs)
return;
/*
* We also restrict the query to reference exactly one table, since join
* conditions can't be handled reasonably. (We could perhaps handle a
* query containing cartesian-product joins, but it hardly seems worth the
* trouble.) However, the single table could be buried in several levels
* of FromExpr due to subqueries. Note the "single" table could be an
* inheritance parent, too, including the case of a UNION ALL subquery
* that's been flattened to an appendrel.
*/
jtnode = parse->jointree;
while (IsA(jtnode, FromExpr))
{
if (list_length(jtnode->fromlist) != 1)
return;
jtnode = linitial(jtnode->fromlist);
}
if (!IsA(jtnode, RangeTblRef))
return;
rtr = (RangeTblRef *) jtnode;
rte = planner_rt_fetch(rtr->rtindex, root);
if (rte->rtekind == RTE_RELATION)
/* ordinary relation, ok */ ;
else if (rte->rtekind == RTE_SUBQUERY && rte->inh)
/* flattened UNION ALL subquery, ok */ ;
else
return;
/*
* Scan the tlist and HAVING qual to find all the aggregates and verify
* all are MIN/MAX aggregates. Stop as soon as we find one that isn't.
*/
aggs_list = NIL;
if (find_minmax_aggs_walker((Node *) tlist, &aggs_list))
return;
if (find_minmax_aggs_walker(parse->havingQual, &aggs_list))
return;
/*
* OK, there is at least the possibility of performing the optimization.
* Build an access path for each aggregate. (We must do this now because
* we need to call query_planner with a pristine copy of the current query
* tree; it'll be too late when optimize_minmax_aggregates gets called.)
* If any of the aggregates prove to be non-indexable, give up; there is
* no point in optimizing just some of them.
*/
foreach(lc, aggs_list)
{
MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
Oid eqop;
bool reverse;
/*
* We'll need the equality operator that goes with the aggregate's
* ordering operator.
*/
eqop = get_equality_op_for_ordering_op(mminfo->aggsortop, &reverse);
if (!OidIsValid(eqop)) /* shouldn't happen */
elog(ERROR, "could not find equality operator for ordering operator %u",
mminfo->aggsortop);
/*
* We can use either an ordering that gives NULLS FIRST or one that
* gives NULLS LAST; furthermore there's unlikely to be much
* performance difference between them, so it doesn't seem worth
* costing out both ways if we get a hit on the first one. NULLS
* FIRST is more likely to be available if the operator is a
* reverse-sort operator, so try that first if reverse.
*/
if (build_minmax_path(root, mminfo, eqop, mminfo->aggsortop, reverse))
continue;
if (build_minmax_path(root, mminfo, eqop, mminfo->aggsortop, !reverse))
continue;
/* No indexable path for this aggregate, so fail */
return;
}
/*
* We're done until path generation is complete. Save info for later.
* (Setting root->minmax_aggs non-NIL signals we succeeded in making index
* access paths for all the aggregates.)
*/
root->minmax_aggs = aggs_list;
}
| void process_implied_equality | ( | PlannerInfo * | root, | |
| Oid | opno, | |||
| Oid | collation, | |||
| Expr * | item1, | |||
| Expr * | item2, | |||
| Relids | qualscope, | |||
| Relids | nullable_relids, | |||
| bool | below_outer_join, | |||
| bool | both_const | |||
| ) |
Definition at line 1741 of file initsplan.c.
References Assert, BOOLOID, Const::constisnull, Const::consttype, Const::constvalue, copyObject(), DatumGetBool, distribute_qual_to_rels(), eval_const_expressions(), InvalidOid, IsA, JOIN_INNER, make_opclause(), and NULL.
Referenced by generate_base_implied_equalities_const(), and generate_base_implied_equalities_no_const().
{
Expr *clause;
/*
* Build the new clause. Copy to ensure it shares no substructure with
* original (this is necessary in case there are subselects in there...)
*/
clause = make_opclause(opno,
BOOLOID, /* opresulttype */
false, /* opretset */
(Expr *) copyObject(item1),
(Expr *) copyObject(item2),
InvalidOid,
collation);
/* If both constant, try to reduce to a boolean constant. */
if (both_const)
{
clause = (Expr *) eval_const_expressions(root, (Node *) clause);
/* If we produced const TRUE, just drop the clause */
if (clause && IsA(clause, Const))
{
Const *cclause = (Const *) clause;
Assert(cclause->consttype == BOOLOID);
if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
return;
}
}
/*
* Push the new clause into all the appropriate restrictinfo lists.
*/
distribute_qual_to_rels(root, (Node *) clause,
true, below_outer_join, JOIN_INNER,
qualscope, NULL, NULL, nullable_relids);
}
| void query_planner | ( | PlannerInfo * | root, | |
| List * | tlist, | |||
| double | tuple_fraction, | |||
| double | limit_tuples, | |||
| query_pathkeys_callback | qp_callback, | |||
| void * | qp_extra, | |||
| Path ** | cheapest_path, | |||
| Path ** | sorted_path, | |||
| double * | num_groups | |||
| ) |
Definition at line 81 of file planmain.c.
References add_base_rels_to_query(), add_placeholders_to_base_rels(), Assert, build_base_rel_tlists(), PlannerInfo::canon_pathkeys, RelOptInfo::cheapest_total_path, compare_fractional_path_costs(), cost_sort(), create_lateral_join_info(), create_result_path(), deconstruct_jointree(), Query::distinctClause, elog, ERROR, estimate_num_groups(), find_lateral_references(), find_placeholders_in_jointree(), fix_placeholder_input_needed_levels(), FromExpr::fromlist, PlannerInfo::full_join_clauses, generate_base_implied_equalities(), get_cheapest_fractional_path_for_pathkeys(), get_sortgrouplist_exprs(), Query::groupClause, Query::hasAggs, PlannerInfo::initial_rels, PlannerInfo::join_cur_level, PlannerInfo::join_info_list, PlannerInfo::join_rel_hash, PlannerInfo::join_rel_level, PlannerInfo::join_rel_list, Query::jointree, PlannerInfo::lateral_info_list, PlannerInfo::left_join_clauses, PlannerInfo::limit_tuples, make_one_rel(), NIL, NULL, RelOptInfo::pages, Path::param_info, PlannerInfo::parse, parse(), Path::pathkeys, pathkeys_contained_in(), RelOptInfo::pathlist, PlannerInfo::placeholder_list, FromExpr::quals, reconsider_outer_join_clauses(), RelOptInfo::relid, RELOPT_BASEREL, RELOPT_OTHER_MEMBER_REL, RelOptInfo::reloptkind, remove_useless_joins(), PlannerInfo::right_join_clauses, RelOptInfo::rows, setup_simple_rel_arrays(), Path::startup_cost, Query::targetList, Path::total_cost, PlannerInfo::tuple_fraction, RelOptInfo::width, and work_mem.
Referenced by build_minmax_path(), and grouping_planner().
{
Query *parse = root->parse;
List *joinlist;
RelOptInfo *final_rel;
Path *cheapestpath;
Path *sortedpath;
Index rti;
double total_pages;
/* Make tuple_fraction, limit_tuples accessible to lower-level routines */
root->tuple_fraction = tuple_fraction;
root->limit_tuples = limit_tuples;
*num_groups = 1; /* default result */
/*
* If the query has an empty join tree, then it's something easy like
* "SELECT 2+2;" or "INSERT ... VALUES()". Fall through quickly.
*/
if (parse->jointree->fromlist == NIL)
{
/* We need a trivial path result */
*cheapest_path = (Path *)
create_result_path((List *) parse->jointree->quals);
*sorted_path = NULL;
/*
* We still are required to call qp_callback, in case it's something
* like "SELECT 2+2 ORDER BY 1".
*/
root->canon_pathkeys = NIL;
(*qp_callback) (root, qp_extra);
return;
}
/*
* Init planner lists to empty.
*
* NOTE: append_rel_list was set up by subquery_planner, so do not touch
* here; eq_classes and minmax_aggs may contain data already, too.
*/
root->join_rel_list = NIL;
root->join_rel_hash = NULL;
root->join_rel_level = NULL;
root->join_cur_level = 0;
root->canon_pathkeys = NIL;
root->left_join_clauses = NIL;
root->right_join_clauses = NIL;
root->full_join_clauses = NIL;
root->join_info_list = NIL;
root->lateral_info_list = NIL;
root->placeholder_list = NIL;
root->initial_rels = NIL;
/*
* Make a flattened version of the rangetable for faster access (this is
* OK because the rangetable won't change any more), and set up an empty
* array for indexing base relations.
*/
setup_simple_rel_arrays(root);
/*
* Construct RelOptInfo nodes for all base relations in query, and
* indirectly for all appendrel member relations ("other rels"). This
* will give us a RelOptInfo for every "simple" (non-join) rel involved in
* the query.
*
* Note: the reason we find the rels by searching the jointree and
* appendrel list, rather than just scanning the rangetable, is that the
* rangetable may contain RTEs for rels not actively part of the query,
* for example views. We don't want to make RelOptInfos for them.
*/
add_base_rels_to_query(root, (Node *) parse->jointree);
/*
* Examine the targetlist and join tree, adding entries to baserel
* targetlists for all referenced Vars, and generating PlaceHolderInfo
* entries for all referenced PlaceHolderVars. Restrict and join clauses
* are added to appropriate lists belonging to the mentioned relations. We
* also build EquivalenceClasses for provably equivalent expressions. The
* SpecialJoinInfo list is also built to hold information about join order
* restrictions. Finally, we form a target joinlist for make_one_rel() to
* work from.
*/
build_base_rel_tlists(root, tlist);
find_placeholders_in_jointree(root);
find_lateral_references(root);
joinlist = deconstruct_jointree(root);
/*
* Create the LateralJoinInfo list now that we have finalized
* PlaceHolderVar eval levels.
*/
create_lateral_join_info(root);
/*
* Reconsider any postponed outer-join quals now that we have built up
* equivalence classes. (This could result in further additions or
* mergings of classes.)
*/
reconsider_outer_join_clauses(root);
/*
* If we formed any equivalence classes, generate additional restriction
* clauses as appropriate. (Implied join clauses are formed on-the-fly
* later.)
*/
generate_base_implied_equalities(root);
/*
* We have completed merging equivalence sets, so it's now possible to
* generate pathkeys in canonical form; so compute query_pathkeys and
* other pathkeys fields in PlannerInfo.
*/
(*qp_callback) (root, qp_extra);
/*
* Examine any "placeholder" expressions generated during subquery pullup.
* Make sure that the Vars they need are marked as needed at the relevant
* join level. This must be done before join removal because it might
* cause Vars or placeholders to be needed above a join when they weren't
* so marked before.
*/
fix_placeholder_input_needed_levels(root);
/*
* Remove any useless outer joins. Ideally this would be done during
* jointree preprocessing, but the necessary information isn't available
* until we've built baserel data structures and classified qual clauses.
*/
joinlist = remove_useless_joins(root, joinlist);
/*
* Now distribute "placeholders" to base rels as needed. This has to be
* done after join removal because removal could change whether a
* placeholder is evaluatable at a base rel.
*/
add_placeholders_to_base_rels(root);
/*
* We should now have size estimates for every actual table involved in
* the query, and we also know which if any have been deleted from the
* query by join removal; so we can compute total_table_pages.
*
* Note that appendrels are not double-counted here, even though we don't
* bother to distinguish RelOptInfos for appendrel parents, because the
* parents will still have size zero.
*
* XXX if a table is self-joined, we will count it once per appearance,
* which perhaps is the wrong thing ... but that's not completely clear,
* and detecting self-joins here is difficult, so ignore it for now.
*/
total_pages = 0;
for (rti = 1; rti < root->simple_rel_array_size; rti++)
{
RelOptInfo *brel = root->simple_rel_array[rti];
if (brel == NULL)
continue;
Assert(brel->relid == rti); /* sanity check on array */
if (brel->reloptkind == RELOPT_BASEREL ||
brel->reloptkind == RELOPT_OTHER_MEMBER_REL)
total_pages += (double) brel->pages;
}
root->total_table_pages = total_pages;
/*
* Ready to do the primary planning.
*/
final_rel = make_one_rel(root, joinlist);
if (!final_rel || !final_rel->cheapest_total_path ||
final_rel->cheapest_total_path->param_info != NULL)
elog(ERROR, "failed to construct the join relation");
/*
* If there's grouping going on, estimate the number of result groups. We
* couldn't do this any earlier because it depends on relation size
* estimates that were set up above.
*
* Then convert tuple_fraction to fractional form if it is absolute, and
* adjust it based on the knowledge that grouping_planner will be doing
* grouping or aggregation work with our result.
*
* This introduces some undesirable coupling between this code and
* grouping_planner, but the alternatives seem even uglier; we couldn't
* pass back completed paths without making these decisions here.
*/
if (parse->groupClause)
{
List *groupExprs;
groupExprs = get_sortgrouplist_exprs(parse->groupClause,
parse->targetList);
*num_groups = estimate_num_groups(root,
groupExprs,
final_rel->rows);
/*
* In GROUP BY mode, an absolute LIMIT is relative to the number of
* groups not the number of tuples. If the caller gave us a fraction,
* keep it as-is. (In both cases, we are effectively assuming that
* all the groups are about the same size.)
*/
if (tuple_fraction >= 1.0)
tuple_fraction /= *num_groups;
/*
* If both GROUP BY and ORDER BY are specified, we will need two
* levels of sort --- and, therefore, certainly need to read all the
* tuples --- unless ORDER BY is a subset of GROUP BY. Likewise if we
* have both DISTINCT and GROUP BY, or if we have a window
* specification not compatible with the GROUP BY.
*/
if (!pathkeys_contained_in(root->sort_pathkeys, root->group_pathkeys) ||
!pathkeys_contained_in(root->distinct_pathkeys, root->group_pathkeys) ||
!pathkeys_contained_in(root->window_pathkeys, root->group_pathkeys))
tuple_fraction = 0.0;
/* In any case, limit_tuples shouldn't be specified here */
Assert(limit_tuples < 0);
}
else if (parse->hasAggs || root->hasHavingQual)
{
/*
* Ungrouped aggregate will certainly want to read all the tuples, and
* it will deliver a single result row (so leave *num_groups 1).
*/
tuple_fraction = 0.0;
/* limit_tuples shouldn't be specified here */
Assert(limit_tuples < 0);
}
else if (parse->distinctClause)
{
/*
* Since there was no grouping or aggregation, it's reasonable to
* assume the UNIQUE filter has effects comparable to GROUP BY. Return
* the estimated number of output rows for use by caller. (If DISTINCT
* is used with grouping, we ignore its effects for rowcount
* estimation purposes; this amounts to assuming the grouped rows are
* distinct already.)
*/
List *distinctExprs;
distinctExprs = get_sortgrouplist_exprs(parse->distinctClause,
parse->targetList);
*num_groups = estimate_num_groups(root,
distinctExprs,
final_rel->rows);
/*
* Adjust tuple_fraction the same way as for GROUP BY, too.
*/
if (tuple_fraction >= 1.0)
tuple_fraction /= *num_groups;
/* limit_tuples shouldn't be specified here */
Assert(limit_tuples < 0);
}
else
{
/*
* Plain non-grouped, non-aggregated query: an absolute tuple fraction
* can be divided by the number of tuples.
*/
if (tuple_fraction >= 1.0)
tuple_fraction /= final_rel->rows;
}
/*
* Pick out the cheapest-total path and the cheapest presorted path for
* the requested pathkeys (if there is one). We should take the tuple
* fraction into account when selecting the cheapest presorted path, but
* not when selecting the cheapest-total path, since if we have to sort
* then we'll have to fetch all the tuples. (But there's a special case:
* if query_pathkeys is NIL, meaning order doesn't matter, then the
* "cheapest presorted" path will be the cheapest overall for the tuple
* fraction.)
*
* The cheapest-total path is also the one to use if grouping_planner
* decides to use hashed aggregation, so we return it separately even if
* this routine thinks the presorted path is the winner.
*/
cheapestpath = final_rel->cheapest_total_path;
sortedpath =
get_cheapest_fractional_path_for_pathkeys(final_rel->pathlist,
root->query_pathkeys,
NULL,
tuple_fraction);
/* Don't return same path in both guises; just wastes effort */
if (sortedpath == cheapestpath)
sortedpath = NULL;
/*
* Forget about the presorted path if it would be cheaper to sort the
* cheapest-total path. Here we need consider only the behavior at the
* tuple fraction point.
*/
if (sortedpath)
{
Path sort_path; /* dummy for result of cost_sort */
if (root->query_pathkeys == NIL ||
pathkeys_contained_in(root->query_pathkeys,
cheapestpath->pathkeys))
{
/* No sort needed for cheapest path */
sort_path.startup_cost = cheapestpath->startup_cost;
sort_path.total_cost = cheapestpath->total_cost;
}
else
{
/* Figure cost for sorting */
cost_sort(&sort_path, root, root->query_pathkeys,
cheapestpath->total_cost,
final_rel->rows, final_rel->width,
0.0, work_mem, limit_tuples);
}
if (compare_fractional_path_costs(sortedpath, &sort_path,
tuple_fraction) > 0)
{
/* Presorted path is a loser */
sortedpath = NULL;
}
}
*cheapest_path = cheapestpath;
*sorted_path = sortedpath;
}
| void record_plan_function_dependency | ( | PlannerInfo * | root, | |
| Oid | funcid | |||
| ) |
Definition at line 1867 of file setrefs.c.
References PlanInvalItem::cacheId, FirstBootstrapObjectId, GetSysCacheHashValue1, PlannerInfo::glob, PlanInvalItem::hashValue, PlannerGlobal::invalItems, lappend(), makeNode, ObjectIdGetDatum, and PROCOID.
Referenced by fix_expr_common(), inline_function(), and inline_set_returning_function().
{
/*
* For performance reasons, we don't bother to track built-in functions;
* we just assume they'll never change (or at least not in ways that'd
* invalidate plans using them). For this purpose we can consider a
* built-in function to be one with OID less than FirstBootstrapObjectId.
* Note that the OID generator guarantees never to generate such an OID
* after startup, even at OID wraparound.
*/
if (funcid >= (Oid) FirstBootstrapObjectId)
{
PlanInvalItem *inval_item = makeNode(PlanInvalItem);
/*
* It would work to use any syscache on pg_proc, but the easiest is
* PROCOID since we already have the function's OID at hand. Note
* that plancache.c knows we use PROCOID.
*/
inval_item->cacheId = PROCOID;
inval_item->hashValue = GetSysCacheHashValue1(PROCOID,
ObjectIdGetDatum(funcid));
root->glob->invalItems = lappend(root->glob->invalItems, inval_item);
}
}
| List* remove_useless_joins | ( | PlannerInfo * | root, | |
| List * | joinlist | |||
| ) |
Definition at line 47 of file analyzejoins.c.
References bms_singleton_member(), bms_union(), elog, ERROR, PlannerInfo::join_info_list, join_is_removable(), lfirst, list_delete_ptr(), SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, remove_rel_from_joinlist(), and remove_rel_from_query().
Referenced by query_planner().
{
ListCell *lc;
/*
* We are only interested in relations that are left-joined to, so we can
* scan the join_info_list to find them easily.
*/
restart:
foreach(lc, root->join_info_list)
{
SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
int innerrelid;
int nremoved;
/* Skip if not removable */
if (!join_is_removable(root, sjinfo))
continue;
/*
* Currently, join_is_removable can only succeed when the sjinfo's
* righthand is a single baserel. Remove that rel from the query and
* joinlist.
*/
innerrelid = bms_singleton_member(sjinfo->min_righthand);
remove_rel_from_query(root, innerrelid,
bms_union(sjinfo->min_lefthand,
sjinfo->min_righthand));
/* We verify that exactly one reference gets removed from joinlist */
nremoved = 0;
joinlist = remove_rel_from_joinlist(joinlist, innerrelid, &nremoved);
if (nremoved != 1)
elog(ERROR, "failed to find relation %d in joinlist", innerrelid);
/*
* We can delete this SpecialJoinInfo from the list too, since it's no
* longer of interest.
*/
root->join_info_list = list_delete_ptr(root->join_info_list, sjinfo);
/*
* Restart the scan. This is necessary to ensure we find all
* removable joins independently of ordering of the join_info_list
* (note that removal of attr_needed bits may make a join appear
* removable that did not before). Also, since we just deleted the
* current list cell, we'd have to have some kluge to continue the
* list scan anyway.
*/
goto restart;
}
return joinlist;
}
| void set_opfuncid | ( | OpExpr * | opexpr | ) |
Definition at line 1838 of file setrefs.c.
References get_opcode(), InvalidOid, OpExpr::opfuncid, and OpExpr::opno.
Referenced by contain_leaky_functions_walker(), contain_mutable_functions_walker(), contain_nonstrict_functions_walker(), contain_volatile_functions_walker(), cost_qual_eval_walker(), eval_const_expressions_mutator(), expression_returns_set_rows_walker(), find_nonnullable_rels_walker(), find_nonnullable_vars_walker(), fix_expr_common(), and fix_opfuncids_walker().
{
if (opexpr->opfuncid == InvalidOid)
opexpr->opfuncid = get_opcode(opexpr->opno);
}
| Plan* set_plan_references | ( | PlannerInfo * | root, | |
| Plan * | plan | |||
| ) |
Definition at line 192 of file setrefs.c.
References Assert, RangeTblEntry::ctecolcollations, RangeTblEntry::ctecoltypes, RangeTblEntry::ctecoltypmods, ereport, errcode(), errmsg(), ERROR, PlannerGlobal::finalrowmarks, PlannerGlobal::finalrtable, RangeTblEntry::funccolcollations, RangeTblEntry::funccoltypes, RangeTblEntry::funccoltypmods, RangeTblEntry::funcexpr, PlannerInfo::glob, IS_SPECIAL_VARNO, IsA, RangeTblEntry::joinaliasvars, lappend(), lappend_oid(), lfirst, list_length(), palloc(), PlannerInfo::parse, PlanRowMark::prti, PlannerGlobal::relationOids, RangeTblEntry::relid, PlannerInfo::rowMarks, Query::rtable, RTE_RELATION, RangeTblEntry::rtekind, PlanRowMark::rti, set_plan_refs(), RangeTblEntry::subquery, RangeTblEntry::values_collations, and RangeTblEntry::values_lists.
Referenced by set_subqueryscan_references(), and standard_planner().
{
PlannerGlobal *glob = root->glob;
int rtoffset = list_length(glob->finalrtable);
ListCell *lc;
/*
* In the flat rangetable, we zero out substructure pointers that are not
* needed by the executor; this reduces the storage space and copying cost
* for cached plans. We keep only the alias and eref Alias fields, which
* are needed by EXPLAIN, and the selectedCols and modifiedCols bitmaps,
* which are needed for executor-startup permissions checking and for
* trigger event checking.
*/
foreach(lc, root->parse->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
RangeTblEntry *newrte;
/* flat copy to duplicate all the scalar fields */
newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));
memcpy(newrte, rte, sizeof(RangeTblEntry));
/* zap unneeded sub-structure */
newrte->subquery = NULL;
newrte->joinaliasvars = NIL;
newrte->funcexpr = NULL;
newrte->funccoltypes = NIL;
newrte->funccoltypmods = NIL;
newrte->funccolcollations = NIL;
newrte->values_lists = NIL;
newrte->values_collations = NIL;
newrte->ctecoltypes = NIL;
newrte->ctecoltypmods = NIL;
newrte->ctecolcollations = NIL;
glob->finalrtable = lappend(glob->finalrtable, newrte);
/*
* If it's a plain relation RTE, add the table to relationOids.
*
* We do this even though the RTE might be unreferenced in the plan
* tree; this would correspond to cases such as views that were
* expanded, child tables that were eliminated by constraint
* exclusion, etc. Schema invalidation on such a rel must still force
* rebuilding of the plan.
*
* Note we don't bother to avoid duplicate list entries. We could,
* but it would probably cost more cycles than it would save.
*/
if (newrte->rtekind == RTE_RELATION)
glob->relationOids = lappend_oid(glob->relationOids,
newrte->relid);
}
/*
* Check for RT index overflow; it's very unlikely, but if it did happen,
* the executor would get confused by varnos that match the special varno
* values.
*/
if (IS_SPECIAL_VARNO(list_length(glob->finalrtable)))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("too many range table entries")));
/*
* Adjust RT indexes of PlanRowMarks and add to final rowmarks list
*/
foreach(lc, root->rowMarks)
{
PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
PlanRowMark *newrc;
Assert(IsA(rc, PlanRowMark));
/* flat copy is enough since all fields are scalars */
newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark));
memcpy(newrc, rc, sizeof(PlanRowMark));
/* adjust indexes ... but *not* the rowmarkId */
newrc->rti += rtoffset;
newrc->prti += rtoffset;
glob->finalrowmarks = lappend(glob->finalrowmarks, newrc);
}
/* Now fix the Plan tree */
return set_plan_refs(root, plan, rtoffset);
}
| void set_sa_opfuncid | ( | ScalarArrayOpExpr * | opexpr | ) |
Definition at line 1849 of file setrefs.c.
References get_opcode(), InvalidOid, ScalarArrayOpExpr::opfuncid, and ScalarArrayOpExpr::opno.
Referenced by contain_leaky_functions_walker(), contain_mutable_functions_walker(), contain_volatile_functions_walker(), cost_qual_eval_walker(), fix_expr_common(), fix_opfuncids_walker(), and is_strict_saop().
{
if (opexpr->opfuncid == InvalidOid)
opexpr->opfuncid = get_opcode(opexpr->opno);
}
| double cursor_tuple_fraction |
Definition at line 45 of file planner.c.
Referenced by standard_planner().
Definition at line 34 of file initsplan.c.
Referenced by deconstruct_recurse().
Definition at line 35 of file initsplan.c.
Referenced by deconstruct_recurse().
1.7.1