#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().