Header And Logo

PostgreSQL
| The world's most advanced open source database.

Defines | Typedefs | Functions | Variables

planmain.h File Reference

#include "nodes/plannodes.h"
#include "nodes/relation.h"
Include dependency graph for planmain.h:
This graph shows which files directly or indirectly include this file:

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)
Planoptimize_minmax_aggregates (PlannerInfo *root, List *tlist, const AggClauseCosts *aggcosts, Path *best_path)
Plancreate_plan (PlannerInfo *root, Path *best_path)
SubqueryScanmake_subqueryscan (List *qptlist, List *qpqual, Index scanrelid, Plan *subplan)
ForeignScanmake_foreignscan (List *qptlist, List *qpqual, Index scanrelid, List *fdw_exprs, List *fdw_private)
Appendmake_append (List *appendplans, List *tlist)
RecursiveUnionmake_recursive_union (List *tlist, Plan *lefttree, Plan *righttree, int wtParam, List *distinctList, long numGroups)
Sortmake_sort_from_pathkeys (PlannerInfo *root, Plan *lefttree, List *pathkeys, double limit_tuples)
Sortmake_sort_from_sortclauses (PlannerInfo *root, List *sortcls, Plan *lefttree)
Sortmake_sort_from_groupcols (PlannerInfo *root, List *groupcls, AttrNumber *grpColIdx, Plan *lefttree)
Aggmake_agg (PlannerInfo *root, List *tlist, List *qual, AggStrategy aggstrategy, const AggClauseCosts *aggcosts, int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators, long numGroups, Plan *lefttree)
WindowAggmake_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)
Groupmake_group (PlannerInfo *root, List *tlist, List *qual, int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators, double numGroups, Plan *lefttree)
Planmaterialize_finished_plan (Plan *subplan)
Uniquemake_unique (Plan *lefttree, List *distinctList)
LockRowsmake_lockrows (Plan *lefttree, List *rowMarks, int epqParam)
Limitmake_limit (Plan *lefttree, Node *limitOffset, Node *limitCount, int64 offset_est, int64 count_est)
SetOpmake_setop (SetOpCmd cmd, SetOpStrategy strategy, Plan *lefttree, List *distinctList, AttrNumber flagColIdx, int firstFlag, long numGroups, double outputRows)
Resultmake_result (PlannerInfo *root, List *tlist, Node *resconstantqual, Plan *subplan)
ModifyTablemake_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)
Listdeconstruct_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)
RestrictInfobuild_implied_join_equality (Oid opno, Oid collation, Expr *item1, Expr *item2, Relids qualscope, Relids nullable_relids)
Listremove_useless_joins (PlannerInfo *root, List *joinlist)
Planset_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 Documentation

#define DEFAULT_CURSOR_TUPLE_FRACTION   0.1

Definition at line 21 of file planmain.h.


Typedef Documentation

typedef void(* query_pathkeys_callback)(PlannerInfo *root, void *extra)

Definition at line 25 of file planmain.h.


Function Documentation

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

{
    Relids      qualscope;
    Relids      inner_join_rels;

    /* Start recursion at top of jointree */
    Assert(root->parse->jointree != NULL &&
           IsA(root->parse->jointree, FromExpr));

    return deconstruct_recurse(root, (Node *) root->parse->jointree, false,
                               &qualscope, &inner_join_rels);
}

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;
    }
}

void extract_query_dependencies ( Node query,
List **  relationOids,
List **  invalItems 
)

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);
}

bool is_projection_capable_plan ( Plan plan  ) 

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;
}

Append* make_append ( List appendplans,
List tlist 
)

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;
}

LockRows* make_lockrows ( Plan lefttree,
List rowMarks,
int  epqParam 
)

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;
}

Unique* make_unique ( Plan lefttree,
List distinctList 
)

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;
}

Plan* materialize_finished_plan ( Plan subplan  ) 

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  ) 
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  ) 

Variable Documentation

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