Header And Logo

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

Functions

pathnode.h File Reference

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

Go to the source code of this file.

Functions

int compare_path_costs (Path *path1, Path *path2, CostSelector criterion)
int compare_fractional_path_costs (Path *path1, Path *path2, double fraction)
void set_cheapest (RelOptInfo *parent_rel)
void add_path (RelOptInfo *parent_rel, Path *new_path)
bool add_path_precheck (RelOptInfo *parent_rel, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer)
Pathcreate_seqscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
IndexPathcreate_index_path (PlannerInfo *root, IndexOptInfo *index, List *indexclauses, List *indexclausecols, List *indexorderbys, List *indexorderbycols, List *pathkeys, ScanDirection indexscandir, bool indexonly, Relids required_outer, double loop_count)
BitmapHeapPathcreate_bitmap_heap_path (PlannerInfo *root, RelOptInfo *rel, Path *bitmapqual, Relids required_outer, double loop_count)
BitmapAndPathcreate_bitmap_and_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
BitmapOrPathcreate_bitmap_or_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
TidPathcreate_tidscan_path (PlannerInfo *root, RelOptInfo *rel, List *tidquals, Relids required_outer)
AppendPathcreate_append_path (RelOptInfo *rel, List *subpaths, Relids required_outer)
MergeAppendPathcreate_merge_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *pathkeys, Relids required_outer)
ResultPathcreate_result_path (List *quals)
MaterialPathcreate_material_path (RelOptInfo *rel, Path *subpath)
UniquePathcreate_unique_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, SpecialJoinInfo *sjinfo)
Pathcreate_subqueryscan_path (PlannerInfo *root, RelOptInfo *rel, List *pathkeys, Relids required_outer)
Pathcreate_functionscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
Pathcreate_valuesscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
Pathcreate_ctescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
Pathcreate_worktablescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
ForeignPathcreate_foreignscan_path (PlannerInfo *root, RelOptInfo *rel, double rows, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, List *fdw_private)
Relids calc_nestloop_required_outer (Path *outer_path, Path *inner_path)
Relids calc_non_nestloop_required_outer (Path *outer_path, Path *inner_path)
NestPathcreate_nestloop_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, SpecialJoinInfo *sjinfo, SemiAntiJoinFactors *semifactors, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer)
MergePathcreate_mergejoin_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, SpecialJoinInfo *sjinfo, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer, List *mergeclauses, List *outersortkeys, List *innersortkeys)
HashPathcreate_hashjoin_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, SpecialJoinInfo *sjinfo, SemiAntiJoinFactors *semifactors, Path *outer_path, Path *inner_path, List *restrict_clauses, Relids required_outer, List *hashclauses)
Pathreparameterize_path (PlannerInfo *root, Path *path, Relids required_outer, double loop_count)
void setup_simple_rel_arrays (PlannerInfo *root)
RelOptInfobuild_simple_rel (PlannerInfo *root, int relid, RelOptKind reloptkind)
RelOptInfofind_base_rel (PlannerInfo *root, int relid)
RelOptInfofind_join_rel (PlannerInfo *root, Relids relids)
RelOptInfobuild_join_rel (PlannerInfo *root, Relids joinrelids, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List **restrictlist_ptr)
AppendRelInfofind_childrel_appendrelinfo (PlannerInfo *root, RelOptInfo *rel)
ParamPathInfoget_baserel_parampathinfo (PlannerInfo *root, RelOptInfo *baserel, Relids required_outer)
ParamPathInfoget_joinrel_parampathinfo (PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, SpecialJoinInfo *sjinfo, Relids required_outer, List **restrict_clauses)
ParamPathInfoget_appendrel_parampathinfo (RelOptInfo *appendrel, Relids required_outer)

Function Documentation

void add_path ( RelOptInfo parent_rel,
Path new_path 
)

Definition at line 395 of file pathnode.c.

References BMS_EQUAL, BMS_SUBSET1, BMS_SUBSET2, bms_subset_compare(), CHECK_FOR_INTERRUPTS, compare_path_costs_fuzzily(), compare_pathkeys(), RelOptInfo::consider_startup, COSTS_BETTER1, COSTS_BETTER2, COSTS_DIFFERENT, COSTS_EQUAL, IsA, lappend_cell(), lcons(), lfirst, list_delete_cell(), list_head(), lnext, NIL, NULL, Path::param_info, PATH_REQ_OUTER, Path::pathkeys, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, RelOptInfo::pathlist, pfree(), Path::rows, and Path::total_cost.

Referenced by create_index_paths(), create_tidscan_paths(), fileGetForeignPaths(), generate_mergeappend_paths(), get_index_paths(), mark_dummy_rel(), postgresGetForeignPaths(), set_append_rel_pathlist(), set_cte_pathlist(), set_dummy_rel_pathlist(), set_function_pathlist(), set_plain_rel_pathlist(), set_subquery_pathlist(), set_values_pathlist(), set_worktable_pathlist(), try_hashjoin_path(), try_mergejoin_path(), and try_nestloop_path().

{
    bool        accept_new = true;      /* unless we find a superior old path */
    ListCell   *insert_after = NULL;    /* where to insert new item */
    List       *new_path_pathkeys;
    ListCell   *p1;
    ListCell   *p1_prev;
    ListCell   *p1_next;

    /*
     * This is a convenient place to check for query cancel --- no part of the
     * planner goes very long without calling add_path().
     */
    CHECK_FOR_INTERRUPTS();

    /* Pretend parameterized paths have no pathkeys, per comment above */
    new_path_pathkeys = new_path->param_info ? NIL : new_path->pathkeys;

    /*
     * Loop to check proposed new path against old paths.  Note it is possible
     * for more than one old path to be tossed out because new_path dominates
     * it.
     *
     * We can't use foreach here because the loop body may delete the current
     * list cell.
     */
    p1_prev = NULL;
    for (p1 = list_head(parent_rel->pathlist); p1 != NULL; p1 = p1_next)
    {
        Path       *old_path = (Path *) lfirst(p1);
        bool        remove_old = false; /* unless new proves superior */
        PathCostComparison costcmp;
        PathKeysComparison keyscmp;
        BMS_Comparison outercmp;

        p1_next = lnext(p1);

        /*
         * Do a fuzzy cost comparison with 1% fuzziness limit.  (XXX does this
         * percentage need to be user-configurable?)
         */
        costcmp = compare_path_costs_fuzzily(new_path, old_path, 1.01,
                                             parent_rel->consider_startup);

        /*
         * If the two paths compare differently for startup and total cost,
         * then we want to keep both, and we can skip comparing pathkeys and
         * required_outer rels.  If they compare the same, proceed with the
         * other comparisons.  Row count is checked last.  (We make the tests
         * in this order because the cost comparison is most likely to turn
         * out "different", and the pathkeys comparison next most likely.  As
         * explained above, row count very seldom makes a difference, so even
         * though it's cheap to compare there's not much point in checking it
         * earlier.)
         */
        if (costcmp != COSTS_DIFFERENT)
        {
            /* Similarly check to see if either dominates on pathkeys */
            List       *old_path_pathkeys;

            old_path_pathkeys = old_path->param_info ? NIL : old_path->pathkeys;
            keyscmp = compare_pathkeys(new_path_pathkeys,
                                       old_path_pathkeys);
            if (keyscmp != PATHKEYS_DIFFERENT)
            {
                switch (costcmp)
                {
                    case COSTS_EQUAL:
                        outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
                                                   PATH_REQ_OUTER(old_path));
                        if (keyscmp == PATHKEYS_BETTER1)
                        {
                            if ((outercmp == BMS_EQUAL ||
                                 outercmp == BMS_SUBSET1) &&
                                new_path->rows <= old_path->rows)
                                remove_old = true;      /* new dominates old */
                        }
                        else if (keyscmp == PATHKEYS_BETTER2)
                        {
                            if ((outercmp == BMS_EQUAL ||
                                 outercmp == BMS_SUBSET2) &&
                                new_path->rows >= old_path->rows)
                                accept_new = false;     /* old dominates new */
                        }
                        else    /* keyscmp == PATHKEYS_EQUAL */
                        {
                            if (outercmp == BMS_EQUAL)
                            {
                                /*
                                 * Same pathkeys and outer rels, and fuzzily
                                 * the same cost, so keep just one; to decide
                                 * which, first check rows and then do a fuzzy
                                 * cost comparison with very small fuzz limit.
                                 * (We used to do an exact cost comparison,
                                 * but that results in annoying
                                 * platform-specific plan variations due to
                                 * roundoff in the cost estimates.)  If things
                                 * are still tied, arbitrarily keep only the
                                 * old path.  Notice that we will keep only
                                 * the old path even if the less-fuzzy
                                 * comparison decides the startup and total
                                 * costs compare differently.
                                 */
                                if (new_path->rows < old_path->rows)
                                    remove_old = true;  /* new dominates old */
                                else if (new_path->rows > old_path->rows)
                                    accept_new = false; /* old dominates new */
                                else if (compare_path_costs_fuzzily(new_path,
                                                                    old_path,
                                                                    1.0000000001,
                                                                    parent_rel->consider_startup) == COSTS_BETTER1)
                                    remove_old = true;  /* new dominates old */
                                else
                                    accept_new = false; /* old equals or
                                                         * dominates new */
                            }
                            else if (outercmp == BMS_SUBSET1 &&
                                     new_path->rows <= old_path->rows)
                                remove_old = true;      /* new dominates old */
                            else if (outercmp == BMS_SUBSET2 &&
                                     new_path->rows >= old_path->rows)
                                accept_new = false;     /* old dominates new */
                            /* else different parameterizations, keep both */
                        }
                        break;
                    case COSTS_BETTER1:
                        if (keyscmp != PATHKEYS_BETTER2)
                        {
                            outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
                                                   PATH_REQ_OUTER(old_path));
                            if ((outercmp == BMS_EQUAL ||
                                 outercmp == BMS_SUBSET1) &&
                                new_path->rows <= old_path->rows)
                                remove_old = true;      /* new dominates old */
                        }
                        break;
                    case COSTS_BETTER2:
                        if (keyscmp != PATHKEYS_BETTER1)
                        {
                            outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
                                                   PATH_REQ_OUTER(old_path));
                            if ((outercmp == BMS_EQUAL ||
                                 outercmp == BMS_SUBSET2) &&
                                new_path->rows >= old_path->rows)
                                accept_new = false;     /* old dominates new */
                        }
                        break;
                    case COSTS_DIFFERENT:

                        /*
                         * can't get here, but keep this case to keep compiler
                         * quiet
                         */
                        break;
                }
            }
        }

        /*
         * Remove current element from pathlist if dominated by new.
         */
        if (remove_old)
        {
            parent_rel->pathlist = list_delete_cell(parent_rel->pathlist,
                                                    p1, p1_prev);

            /*
             * Delete the data pointed-to by the deleted cell, if possible
             */
            if (!IsA(old_path, IndexPath))
                pfree(old_path);
            /* p1_prev does not advance */
        }
        else
        {
            /* new belongs after this old path if it has cost >= old's */
            if (new_path->total_cost >= old_path->total_cost)
                insert_after = p1;
            /* p1_prev advances */
            p1_prev = p1;
        }

        /*
         * If we found an old path that dominates new_path, we can quit
         * scanning the pathlist; we will not add new_path, and we assume
         * new_path cannot dominate any other elements of the pathlist.
         */
        if (!accept_new)
            break;
    }

    if (accept_new)
    {
        /* Accept the new path: insert it at proper place in pathlist */
        if (insert_after)
            lappend_cell(parent_rel->pathlist, insert_after, new_path);
        else
            parent_rel->pathlist = lcons(new_path, parent_rel->pathlist);
    }
    else
    {
        /* Reject and recycle the new path */
        if (!IsA(new_path, IndexPath))
            pfree(new_path);
    }
}

bool add_path_precheck ( RelOptInfo parent_rel,
Cost  startup_cost,
Cost  total_cost,
List pathkeys,
Relids  required_outer 
)

Definition at line 620 of file pathnode.c.

References bms_equal(), compare_pathkeys(), lfirst, NIL, Path::param_info, PATH_REQ_OUTER, Path::pathkeys, PATHKEYS_BETTER2, PATHKEYS_EQUAL, RelOptInfo::pathlist, Path::startup_cost, and Path::total_cost.

Referenced by try_hashjoin_path(), try_mergejoin_path(), and try_nestloop_path().

{
    List       *new_path_pathkeys;
    ListCell   *p1;

    /* Pretend parameterized paths have no pathkeys, per add_path policy */
    new_path_pathkeys = required_outer ? NIL : pathkeys;

    foreach(p1, parent_rel->pathlist)
    {
        Path       *old_path = (Path *) lfirst(p1);
        PathKeysComparison keyscmp;

        /*
         * We are looking for an old_path with the same parameterization (and
         * by assumption the same rowcount) that dominates the new path on
         * pathkeys as well as both cost metrics.  If we find one, we can
         * reject the new path.
         *
         * For speed, we make exact rather than fuzzy cost comparisons. If an
         * old path dominates the new path exactly on both costs, it will
         * surely do so fuzzily.
         */
        if (total_cost >= old_path->total_cost)
        {
            /* can win on startup cost only if unparameterized */
            if (startup_cost >= old_path->startup_cost || required_outer)
            {
                /* new path does not win on cost, so check pathkeys... */
                List       *old_path_pathkeys;

                old_path_pathkeys = old_path->param_info ? NIL : old_path->pathkeys;
                keyscmp = compare_pathkeys(new_path_pathkeys,
                                           old_path_pathkeys);
                if (keyscmp == PATHKEYS_EQUAL ||
                    keyscmp == PATHKEYS_BETTER2)
                {
                    /* new path does not win on pathkeys... */
                    if (bms_equal(required_outer, PATH_REQ_OUTER(old_path)))
                    {
                        /* Found an old path that dominates the new one */
                        return false;
                    }
                }
            }
        }
        else
        {
            /*
             * Since the pathlist is sorted by total_cost, we can stop looking
             * once we reach a path with a total_cost larger than the new
             * path's.
             */
            break;
        }
    }

    return true;
}

RelOptInfo* build_join_rel ( PlannerInfo root,
Relids  joinrelids,
RelOptInfo outer_rel,
RelOptInfo inner_rel,
SpecialJoinInfo sjinfo,
List **  restrictlist_ptr 
)

Definition at line 323 of file relnode.c.

References add_placeholders_to_joinrel(), RelOptInfo::allvisfrac, Assert, RelOptInfo::attr_needed, RelOptInfo::attr_widths, RelOptInfo::baserestrictcost, RelOptInfo::baserestrictinfo, bms_copy(), bms_num_members(), build_joinrel_joinlist(), build_joinrel_restrictlist(), build_joinrel_tlist(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_path, RelOptInfo::consider_startup, RelOptInfo::fdw_private, RelOptInfo::fdwroutine, find_join_rel(), RelOptInfo::has_eclass_joins, has_relevant_eclass_joinclause(), hash_search(), RelOptInfo::indexlist, PlannerInfo::join_cur_level, JoinHashEntry::join_rel, PlannerInfo::join_rel_hash, PlannerInfo::join_rel_level, PlannerInfo::join_rel_list, RelOptInfo::joininfo, lappend(), RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, makeNode, RelOptInfo::max_attr, RelOptInfo::min_attr, RelOptInfo::pages, RelOptInfo::pathlist, QualCost::per_tuple, RelOptInfo::ppilist, RelOptInfo::relid, RelOptInfo::relids, RelOptInfo::reloptkind, RelOptInfo::reltargetlist, RelOptInfo::rows, RelOptInfo::rtekind, set_joinrel_size_estimates(), QualCost::startup, RelOptInfo::subplan, RelOptInfo::subplan_params, RelOptInfo::subroot, PlannerInfo::tuple_fraction, RelOptInfo::tuples, and RelOptInfo::width.

Referenced by make_join_rel().

{
    RelOptInfo *joinrel;
    List       *restrictlist;

    /*
     * See if we already have a joinrel for this set of base rels.
     */
    joinrel = find_join_rel(root, joinrelids);

    if (joinrel)
    {
        /*
         * Yes, so we only need to figure the restrictlist for this particular
         * pair of component relations.
         */
        if (restrictlist_ptr)
            *restrictlist_ptr = build_joinrel_restrictlist(root,
                                                           joinrel,
                                                           outer_rel,
                                                           inner_rel);
        return joinrel;
    }

    /*
     * Nope, so make one.
     */
    joinrel = makeNode(RelOptInfo);
    joinrel->reloptkind = RELOPT_JOINREL;
    joinrel->relids = bms_copy(joinrelids);
    joinrel->rows = 0;
    joinrel->width = 0;
    /* cheap startup cost is interesting iff not all tuples to be retrieved */
    joinrel->consider_startup = (root->tuple_fraction > 0);
    joinrel->reltargetlist = NIL;
    joinrel->pathlist = NIL;
    joinrel->ppilist = NIL;
    joinrel->cheapest_startup_path = NULL;
    joinrel->cheapest_total_path = NULL;
    joinrel->cheapest_unique_path = NULL;
    joinrel->cheapest_parameterized_paths = NIL;
    joinrel->relid = 0;         /* indicates not a baserel */
    joinrel->rtekind = RTE_JOIN;
    joinrel->min_attr = 0;
    joinrel->max_attr = 0;
    joinrel->attr_needed = NULL;
    joinrel->attr_widths = NULL;
    joinrel->lateral_vars = NIL;
    joinrel->lateral_relids = NULL;
    joinrel->indexlist = NIL;
    joinrel->pages = 0;
    joinrel->tuples = 0;
    joinrel->allvisfrac = 0;
    joinrel->subplan = NULL;
    joinrel->subroot = NULL;
    joinrel->subplan_params = NIL;
    joinrel->fdwroutine = NULL;
    joinrel->fdw_private = NULL;
    joinrel->baserestrictinfo = NIL;
    joinrel->baserestrictcost.startup = 0;
    joinrel->baserestrictcost.per_tuple = 0;
    joinrel->joininfo = NIL;
    joinrel->has_eclass_joins = false;

    /*
     * Create a new tlist containing just the vars that need to be output from
     * this join (ie, are needed for higher joinclauses or final output).
     *
     * NOTE: the tlist order for a join rel will depend on which pair of outer
     * and inner rels we first try to build it from.  But the contents should
     * be the same regardless.
     */
    build_joinrel_tlist(root, joinrel, outer_rel);
    build_joinrel_tlist(root, joinrel, inner_rel);
    add_placeholders_to_joinrel(root, joinrel);

    /*
     * Construct restrict and join clause lists for the new joinrel. (The
     * caller might or might not need the restrictlist, but I need it anyway
     * for set_joinrel_size_estimates().)
     */
    restrictlist = build_joinrel_restrictlist(root, joinrel,
                                              outer_rel, inner_rel);
    if (restrictlist_ptr)
        *restrictlist_ptr = restrictlist;
    build_joinrel_joinlist(joinrel, outer_rel, inner_rel);

    /*
     * This is also the right place to check whether the joinrel has any
     * pending EquivalenceClass joins.
     */
    joinrel->has_eclass_joins = has_relevant_eclass_joinclause(root, joinrel);

    /*
     * Set estimates of the joinrel's size.
     */
    set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
                               sjinfo, restrictlist);

    /*
     * Add the joinrel to the query's joinrel list, and store it into the
     * auxiliary hashtable if there is one.  NB: GEQO requires us to append
     * the new joinrel to the end of the list!
     */
    root->join_rel_list = lappend(root->join_rel_list, joinrel);

    if (root->join_rel_hash)
    {
        JoinHashEntry *hentry;
        bool        found;

        hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
                                               &(joinrel->relids),
                                               HASH_ENTER,
                                               &found);
        Assert(!found);
        hentry->join_rel = joinrel;
    }

    /*
     * Also, if dynamic-programming join search is active, add the new joinrel
     * to the appropriate sublist.  Note: you might think the Assert on number
     * of members should be for equality, but some of the level 1 rels might
     * have been joinrels already, so we can only assert <=.
     */
    if (root->join_rel_level)
    {
        Assert(root->join_cur_level > 0);
        Assert(root->join_cur_level <= bms_num_members(joinrel->relids));
        root->join_rel_level[root->join_cur_level] =
            lappend(root->join_rel_level[root->join_cur_level], joinrel);
    }

    return joinrel;
}

RelOptInfo* build_simple_rel ( PlannerInfo root,
int  relid,
RelOptKind  reloptkind 
)

Definition at line 83 of file relnode.c.

References RelOptInfo::allvisfrac, PlannerInfo::append_rel_list, Assert, RelOptInfo::attr_needed, RelOptInfo::attr_widths, RelOptInfo::baserestrictcost, RelOptInfo::baserestrictinfo, bms_make_singleton(), build_simple_rel(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_path, AppendRelInfo::child_relid, Alias::colnames, RelOptInfo::consider_startup, elog, RangeTblEntry::eref, ERROR, RelOptInfo::fdw_private, RelOptInfo::fdwroutine, get_relation_info(), RelOptInfo::has_eclass_joins, RelOptInfo::indexlist, RangeTblEntry::inh, RelOptInfo::joininfo, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, lfirst, list_length(), makeNode, RelOptInfo::max_attr, RelOptInfo::min_attr, NULL, RelOptInfo::pages, palloc0(), AppendRelInfo::parent_relid, RelOptInfo::pathlist, QualCost::per_tuple, RelOptInfo::ppilist, RangeTblEntry::relid, RelOptInfo::relid, RelOptInfo::relids, RELOPT_OTHER_MEMBER_REL, RelOptInfo::reloptkind, RelOptInfo::reltargetlist, RelOptInfo::rows, RTE_CTE, RTE_FUNCTION, RTE_RELATION, RTE_SUBQUERY, RTE_VALUES, RangeTblEntry::rtekind, RelOptInfo::rtekind, PlannerInfo::simple_rel_array, PlannerInfo::simple_rte_array, QualCost::startup, RelOptInfo::subplan, RelOptInfo::subplan_params, RelOptInfo::subroot, PlannerInfo::tuple_fraction, RelOptInfo::tuples, and RelOptInfo::width.

Referenced by add_base_rels_to_query(), build_simple_rel(), plan_cluster_use_sort(), and recurse_set_operations().

{
    RelOptInfo *rel;
    RangeTblEntry *rte;

    /* Rel should not exist already */
    Assert(relid > 0 && relid < root->simple_rel_array_size);
    if (root->simple_rel_array[relid] != NULL)
        elog(ERROR, "rel %d already exists", relid);

    /* Fetch RTE for relation */
    rte = root->simple_rte_array[relid];
    Assert(rte != NULL);

    rel = makeNode(RelOptInfo);
    rel->reloptkind = reloptkind;
    rel->relids = bms_make_singleton(relid);
    rel->rows = 0;
    rel->width = 0;
    /* cheap startup cost is interesting iff not all tuples to be retrieved */
    rel->consider_startup = (root->tuple_fraction > 0);
    rel->reltargetlist = NIL;
    rel->pathlist = NIL;
    rel->ppilist = NIL;
    rel->cheapest_startup_path = NULL;
    rel->cheapest_total_path = NULL;
    rel->cheapest_unique_path = NULL;
    rel->cheapest_parameterized_paths = NIL;
    rel->relid = relid;
    rel->rtekind = rte->rtekind;
    /* min_attr, max_attr, attr_needed, attr_widths are set below */
    rel->lateral_vars = NIL;
    rel->lateral_relids = NULL;
    rel->indexlist = NIL;
    rel->pages = 0;
    rel->tuples = 0;
    rel->allvisfrac = 0;
    rel->subplan = NULL;
    rel->subroot = NULL;
    rel->subplan_params = NIL;
    rel->fdwroutine = NULL;
    rel->fdw_private = NULL;
    rel->baserestrictinfo = NIL;
    rel->baserestrictcost.startup = 0;
    rel->baserestrictcost.per_tuple = 0;
    rel->joininfo = NIL;
    rel->has_eclass_joins = false;

    /* Check type of rtable entry */
    switch (rte->rtekind)
    {
        case RTE_RELATION:
            /* Table --- retrieve statistics from the system catalogs */
            get_relation_info(root, rte->relid, rte->inh, rel);
            break;
        case RTE_SUBQUERY:
        case RTE_FUNCTION:
        case RTE_VALUES:
        case RTE_CTE:

            /*
             * Subquery, function, or values list --- set up attr range and
             * arrays
             *
             * Note: 0 is included in range to support whole-row Vars
             */
            rel->min_attr = 0;
            rel->max_attr = list_length(rte->eref->colnames);
            rel->attr_needed = (Relids *)
                palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));
            rel->attr_widths = (int32 *)
                palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));
            break;
        default:
            elog(ERROR, "unrecognized RTE kind: %d",
                 (int) rte->rtekind);
            break;
    }

    /* Save the finished struct in the query's simple_rel_array */
    root->simple_rel_array[relid] = rel;

    /*
     * If this rel is an appendrel parent, recurse to build "other rel"
     * RelOptInfos for its children.  They are "other rels" because they are
     * not in the main join tree, but we will need RelOptInfos to plan access
     * to them.
     */
    if (rte->inh)
    {
        ListCell   *l;

        foreach(l, root->append_rel_list)
        {
            AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);

            /* append_rel_list contains all append rels; ignore others */
            if (appinfo->parent_relid != relid)
                continue;

            (void) build_simple_rel(root, appinfo->child_relid,
                                    RELOPT_OTHER_MEMBER_REL);
        }
    }

    return rel;
}

Relids calc_nestloop_required_outer ( Path outer_path,
Path inner_path 
)

Definition at line 1746 of file pathnode.c.

References Assert, bms_copy(), bms_del_members(), bms_free(), bms_is_empty(), bms_overlap(), bms_union(), Path::parent, PATH_REQ_OUTER, and RelOptInfo::relids.

Referenced by try_nestloop_path().

{
    Relids      outer_paramrels = PATH_REQ_OUTER(outer_path);
    Relids      inner_paramrels = PATH_REQ_OUTER(inner_path);
    Relids      required_outer;

    /* inner_path can require rels from outer path, but not vice versa */
    Assert(!bms_overlap(outer_paramrels, inner_path->parent->relids));
    /* easy case if inner path is not parameterized */
    if (!inner_paramrels)
        return bms_copy(outer_paramrels);
    /* else, form the union ... */
    required_outer = bms_union(outer_paramrels, inner_paramrels);
    /* ... and remove any mention of now-satisfied outer rels */
    required_outer = bms_del_members(required_outer,
                                     outer_path->parent->relids);
    /* maintain invariant that required_outer is exactly NULL if empty */
    if (bms_is_empty(required_outer))
    {
        bms_free(required_outer);
        required_outer = NULL;
    }
    return required_outer;
}

Relids calc_non_nestloop_required_outer ( Path outer_path,
Path inner_path 
)

Definition at line 1778 of file pathnode.c.

References Assert, bms_overlap(), bms_union(), Path::parent, PATH_REQ_OUTER, and RelOptInfo::relids.

Referenced by try_hashjoin_path(), and try_mergejoin_path().

{
    Relids      outer_paramrels = PATH_REQ_OUTER(outer_path);
    Relids      inner_paramrels = PATH_REQ_OUTER(inner_path);
    Relids      required_outer;

    /* neither path can require rels from the other */
    Assert(!bms_overlap(outer_paramrels, inner_path->parent->relids));
    Assert(!bms_overlap(inner_paramrels, outer_path->parent->relids));
    /* form the union ... */
    required_outer = bms_union(outer_paramrels, inner_paramrels);
    /* we do not need an explicit test for empty; bms_union gets it right */
    return required_outer;
}

int compare_fractional_path_costs ( Path path1,
Path path2,
double  fraction 
)

Definition at line 101 of file pathnode.c.

References compare_path_costs(), Path::startup_cost, Path::total_cost, and TOTAL_COST.

Referenced by choose_hashed_distinct(), choose_hashed_grouping(), choose_hashed_setop(), get_cheapest_fractional_path_for_pathkeys(), and query_planner().

{
    Cost        cost1,
                cost2;

    if (fraction <= 0.0 || fraction >= 1.0)
        return compare_path_costs(path1, path2, TOTAL_COST);
    cost1 = path1->startup_cost +
        fraction * (path1->total_cost - path1->startup_cost);
    cost2 = path2->startup_cost +
        fraction * (path2->total_cost - path2->startup_cost);
    if (cost1 < cost2)
        return -1;
    if (cost1 > cost2)
        return +1;
    return 0;
}

int compare_path_costs ( Path path1,
Path path2,
CostSelector  criterion 
)

Definition at line 55 of file pathnode.c.

References Path::startup_cost, STARTUP_COST, and Path::total_cost.

Referenced by compare_fractional_path_costs(), get_cheapest_path_for_pathkeys(), match_unsorted_outer(), and set_cheapest().

{
    if (criterion == STARTUP_COST)
    {
        if (path1->startup_cost < path2->startup_cost)
            return -1;
        if (path1->startup_cost > path2->startup_cost)
            return +1;

        /*
         * If paths have the same startup cost (not at all unlikely), order
         * them by total cost.
         */
        if (path1->total_cost < path2->total_cost)
            return -1;
        if (path1->total_cost > path2->total_cost)
            return +1;
    }
    else
    {
        if (path1->total_cost < path2->total_cost)
            return -1;
        if (path1->total_cost > path2->total_cost)
            return +1;

        /*
         * If paths have the same total cost, order them by startup cost.
         */
        if (path1->startup_cost < path2->startup_cost)
            return -1;
        if (path1->startup_cost > path2->startup_cost)
            return +1;
    }
    return 0;
}

AppendPath* create_append_path ( RelOptInfo rel,
List subpaths,
Relids  required_outer 
)

Definition at line 890 of file pathnode.c.

References Assert, bms_equal(), get_appendrel_parampathinfo(), lfirst, list_head(), makeNode, Path::param_info, Path::parent, AppendPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, Path::rows, Path::startup_cost, subpath(), AppendPath::subpaths, and Path::total_cost.

Referenced by mark_dummy_rel(), set_append_rel_pathlist(), and set_dummy_rel_pathlist().

{
    AppendPath *pathnode = makeNode(AppendPath);
    ListCell   *l;

    pathnode->path.pathtype = T_Append;
    pathnode->path.parent = rel;
    pathnode->path.param_info = get_appendrel_parampathinfo(rel,
                                                            required_outer);
    pathnode->path.pathkeys = NIL;      /* result is always considered
                                         * unsorted */
    pathnode->subpaths = subpaths;

    /*
     * We don't bother with inventing a cost_append(), but just do it here.
     *
     * Compute rows and costs as sums of subplan rows and 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 make_append().
     */
    pathnode->path.rows = 0;
    pathnode->path.startup_cost = 0;
    pathnode->path.total_cost = 0;
    foreach(l, subpaths)
    {
        Path       *subpath = (Path *) lfirst(l);

        pathnode->path.rows += subpath->rows;

        if (l == list_head(subpaths))   /* first node? */
            pathnode->path.startup_cost = subpath->startup_cost;
        pathnode->path.total_cost += subpath->total_cost;

        /* All child paths must have same parameterization */
        Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer));
    }

    return pathnode;
}

BitmapAndPath* create_bitmap_and_path ( PlannerInfo root,
RelOptInfo rel,
List bitmapquals 
)

Definition at line 815 of file pathnode.c.

References BitmapAndPath::bitmapquals, cost_bitmap_and_node(), makeNode, Path::param_info, Path::parent, BitmapAndPath::path, Path::pathkeys, and Path::pathtype.

Referenced by choose_bitmap_and().

{
    BitmapAndPath *pathnode = makeNode(BitmapAndPath);

    pathnode->path.pathtype = T_BitmapAnd;
    pathnode->path.parent = rel;
    pathnode->path.param_info = NULL;   /* not used in bitmap trees */
    pathnode->path.pathkeys = NIL;      /* always unordered */

    pathnode->bitmapquals = bitmapquals;

    /* this sets bitmapselectivity as well as the regular cost fields: */
    cost_bitmap_and_node(pathnode, root);

    return pathnode;
}

BitmapHeapPath* create_bitmap_heap_path ( PlannerInfo root,
RelOptInfo rel,
Path bitmapqual,
Relids  required_outer,
double  loop_count 
)

Definition at line 787 of file pathnode.c.

References BitmapHeapPath::bitmapqual, cost_bitmap_heap_scan(), get_baserel_parampathinfo(), makeNode, Path::param_info, Path::parent, BitmapHeapPath::path, Path::pathkeys, and Path::pathtype.

Referenced by create_index_paths(), and reparameterize_path().

{
    BitmapHeapPath *pathnode = makeNode(BitmapHeapPath);

    pathnode->path.pathtype = T_BitmapHeapScan;
    pathnode->path.parent = rel;
    pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
                                                          required_outer);
    pathnode->path.pathkeys = NIL;      /* always unordered */

    pathnode->bitmapqual = bitmapqual;

    cost_bitmap_heap_scan(&pathnode->path, root, rel,
                          pathnode->path.param_info,
                          bitmapqual, loop_count);

    return pathnode;
}

BitmapOrPath* create_bitmap_or_path ( PlannerInfo root,
RelOptInfo rel,
List bitmapquals 
)

Definition at line 839 of file pathnode.c.

References BitmapOrPath::bitmapquals, cost_bitmap_or_node(), makeNode, Path::param_info, Path::parent, BitmapOrPath::path, Path::pathkeys, and Path::pathtype.

Referenced by generate_bitmap_or_paths().

{
    BitmapOrPath *pathnode = makeNode(BitmapOrPath);

    pathnode->path.pathtype = T_BitmapOr;
    pathnode->path.parent = rel;
    pathnode->path.param_info = NULL;   /* not used in bitmap trees */
    pathnode->path.pathkeys = NIL;      /* always unordered */

    pathnode->bitmapquals = bitmapquals;

    /* this sets bitmapselectivity as well as the regular cost fields: */
    cost_bitmap_or_node(pathnode, root);

    return pathnode;
}

Path* create_ctescan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer 
)

Definition at line 1668 of file pathnode.c.

References cost_ctescan(), get_baserel_parampathinfo(), makeNode, Path::param_info, Path::parent, Path::pathkeys, and Path::pathtype.

Referenced by set_cte_pathlist().

{
    Path       *pathnode = makeNode(Path);

    pathnode->pathtype = T_CteScan;
    pathnode->parent = rel;
    pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                     required_outer);
    pathnode->pathkeys = NIL;   /* XXX for now, result is always unordered */

    cost_ctescan(pathnode, root, rel, pathnode->param_info);

    return pathnode;
}

ForeignPath* create_foreignscan_path ( PlannerInfo root,
RelOptInfo rel,
double  rows,
Cost  startup_cost,
Cost  total_cost,
List pathkeys,
Relids  required_outer,
List fdw_private 
)

Definition at line 1717 of file pathnode.c.

References ForeignPath::fdw_private, get_baserel_parampathinfo(), makeNode, Path::param_info, Path::parent, ForeignPath::path, Path::pathkeys, Path::pathtype, Path::rows, Path::startup_cost, and Path::total_cost.

Referenced by fileGetForeignPaths(), and postgresGetForeignPaths().

{
    ForeignPath *pathnode = makeNode(ForeignPath);

    pathnode->path.pathtype = T_ForeignScan;
    pathnode->path.parent = rel;
    pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
                                                          required_outer);
    pathnode->path.rows = rows;
    pathnode->path.startup_cost = startup_cost;
    pathnode->path.total_cost = total_cost;
    pathnode->path.pathkeys = pathkeys;

    pathnode->fdw_private = fdw_private;

    return pathnode;
}

Path* create_functionscan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer 
)

Definition at line 1624 of file pathnode.c.

References cost_functionscan(), get_baserel_parampathinfo(), makeNode, Path::param_info, Path::parent, Path::pathkeys, and Path::pathtype.

Referenced by set_function_pathlist().

{
    Path       *pathnode = makeNode(Path);

    pathnode->pathtype = T_FunctionScan;
    pathnode->parent = rel;
    pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                     required_outer);
    pathnode->pathkeys = NIL;   /* for now, assume unordered result */

    cost_functionscan(pathnode, root, rel, pathnode->param_info);

    return pathnode;
}

HashPath* create_hashjoin_path ( PlannerInfo root,
RelOptInfo joinrel,
JoinType  jointype,
JoinCostWorkspace workspace,
SpecialJoinInfo sjinfo,
SemiAntiJoinFactors semifactors,
Path outer_path,
Path inner_path,
List restrict_clauses,
Relids  required_outer,
List hashclauses 
)

Definition at line 1952 of file pathnode.c.

References final_cost_hashjoin(), get_joinrel_parampathinfo(), JoinPath::innerjoinpath, JoinPath::joinrestrictinfo, JoinPath::jointype, HashPath::jpath, makeNode, JoinPath::outerjoinpath, Path::param_info, Path::parent, JoinPath::path, HashPath::path_hashclauses, Path::pathkeys, and Path::pathtype.

Referenced by try_hashjoin_path().

{
    HashPath   *pathnode = makeNode(HashPath);

    pathnode->jpath.path.pathtype = T_HashJoin;
    pathnode->jpath.path.parent = joinrel;
    pathnode->jpath.path.param_info =
        get_joinrel_parampathinfo(root,
                                  joinrel,
                                  outer_path,
                                  inner_path,
                                  sjinfo,
                                  required_outer,
                                  &restrict_clauses);

    /*
     * A hashjoin never has pathkeys, since its output ordering is
     * unpredictable due to possible batching.  XXX If the inner relation is
     * small enough, we could instruct the executor that it must not batch,
     * and then we could assume that the output inherits the outer relation's
     * ordering, which might save a sort step.  However there is considerable
     * downside if our estimate of the inner relation size is badly off. For
     * the moment we don't risk it.  (Note also that if we wanted to take this
     * seriously, joinpath.c would have to consider many more paths for the
     * outer rel than it does now.)
     */
    pathnode->jpath.path.pathkeys = NIL;
    pathnode->jpath.jointype = jointype;
    pathnode->jpath.outerjoinpath = outer_path;
    pathnode->jpath.innerjoinpath = inner_path;
    pathnode->jpath.joinrestrictinfo = restrict_clauses;
    pathnode->path_hashclauses = hashclauses;
    /* final_cost_hashjoin will fill in pathnode->num_batches */

    final_cost_hashjoin(root, pathnode, workspace, sjinfo, semifactors);

    return pathnode;
}

IndexPath* create_index_path ( PlannerInfo root,
IndexOptInfo index,
List indexclauses,
List indexclausecols,
List indexorderbys,
List indexorderbycols,
List pathkeys,
ScanDirection  indexscandir,
bool  indexonly,
Relids  required_outer,
double  loop_count 
)

Definition at line 733 of file pathnode.c.

References cost_index(), expand_indexqual_conditions(), get_baserel_parampathinfo(), IndexPath::indexclauses, IndexPath::indexinfo, IndexPath::indexorderbycols, IndexPath::indexorderbys, IndexPath::indexqualcols, IndexPath::indexquals, IndexPath::indexscandir, makeNode, Path::param_info, Path::parent, IndexPath::path, Path::pathkeys, Path::pathtype, IndexOptInfo::rel, and T_IndexOnlyScan.

Referenced by build_index_paths(), and plan_cluster_use_sort().

{
    IndexPath  *pathnode = makeNode(IndexPath);
    RelOptInfo *rel = index->rel;
    List       *indexquals,
               *indexqualcols;

    pathnode->path.pathtype = indexonly ? T_IndexOnlyScan : T_IndexScan;
    pathnode->path.parent = rel;
    pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
                                                          required_outer);
    pathnode->path.pathkeys = pathkeys;

    /* Convert clauses to indexquals the executor can handle */
    expand_indexqual_conditions(index, indexclauses, indexclausecols,
                                &indexquals, &indexqualcols);

    /* Fill in the pathnode */
    pathnode->indexinfo = index;
    pathnode->indexclauses = indexclauses;
    pathnode->indexquals = indexquals;
    pathnode->indexqualcols = indexqualcols;
    pathnode->indexorderbys = indexorderbys;
    pathnode->indexorderbycols = indexorderbycols;
    pathnode->indexscandir = indexscandir;

    cost_index(pathnode, root, loop_count);

    return pathnode;
}

MaterialPath* create_material_path ( RelOptInfo rel,
Path subpath 
)

Definition at line 1050 of file pathnode.c.

References Assert, cost_material(), makeNode, Path::param_info, Path::parent, MaterialPath::path, Path::pathkeys, Path::pathtype, Path::rows, Path::startup_cost, MaterialPath::subpath, Path::total_cost, and RelOptInfo::width.

Referenced by match_unsorted_outer().

{
    MaterialPath *pathnode = makeNode(MaterialPath);

    Assert(subpath->parent == rel);

    pathnode->path.pathtype = T_Material;
    pathnode->path.parent = rel;
    pathnode->path.param_info = subpath->param_info;
    pathnode->path.pathkeys = subpath->pathkeys;

    pathnode->subpath = subpath;

    cost_material(&pathnode->path,
                  subpath->startup_cost,
                  subpath->total_cost,
                  subpath->rows,
                  rel->width);

    return pathnode;
}

MergeAppendPath* create_merge_append_path ( PlannerInfo root,
RelOptInfo rel,
List subpaths,
List pathkeys,
Relids  required_outer 
)

Definition at line 937 of file pathnode.c.

References PlannerInfo::all_baserels, Assert, bms_equal(), cost_merge_append(), cost_sort(), get_appendrel_parampathinfo(), lfirst, PlannerInfo::limit_tuples, MergeAppendPath::limit_tuples, list_length(), makeNode, Path::param_info, Path::parent, MergeAppendPath::path, PATH_REQ_OUTER, Path::pathkeys, pathkeys_contained_in(), Path::pathtype, RelOptInfo::relids, Path::rows, Path::startup_cost, subpath(), MergeAppendPath::subpaths, Path::total_cost, RelOptInfo::tuples, RelOptInfo::width, and work_mem.

Referenced by generate_mergeappend_paths().

{
    MergeAppendPath *pathnode = makeNode(MergeAppendPath);
    Cost        input_startup_cost;
    Cost        input_total_cost;
    ListCell   *l;

    pathnode->path.pathtype = T_MergeAppend;
    pathnode->path.parent = rel;
    pathnode->path.param_info = get_appendrel_parampathinfo(rel,
                                                            required_outer);
    pathnode->path.pathkeys = pathkeys;
    pathnode->subpaths = subpaths;

    /*
     * Apply query-wide LIMIT if known and path is for sole base relation.
     * (Handling this at this low level is a bit klugy.)
     */
    if (bms_equal(rel->relids, root->all_baserels))
        pathnode->limit_tuples = root->limit_tuples;
    else
        pathnode->limit_tuples = -1.0;

    /*
     * Add up the sizes and costs of the input paths.
     */
    pathnode->path.rows = 0;
    input_startup_cost = 0;
    input_total_cost = 0;
    foreach(l, subpaths)
    {
        Path       *subpath = (Path *) lfirst(l);

        pathnode->path.rows += subpath->rows;

        if (pathkeys_contained_in(pathkeys, subpath->pathkeys))
        {
            /* Subpath is adequately ordered, we won't need to sort it */
            input_startup_cost += subpath->startup_cost;
            input_total_cost += subpath->total_cost;
        }
        else
        {
            /* We'll need to insert a Sort node, so include cost for that */
            Path        sort_path;      /* dummy for result of cost_sort */

            cost_sort(&sort_path,
                      root,
                      pathkeys,
                      subpath->total_cost,
                      subpath->parent->tuples,
                      subpath->parent->width,
                      0.0,
                      work_mem,
                      pathnode->limit_tuples);
            input_startup_cost += sort_path.startup_cost;
            input_total_cost += sort_path.total_cost;
        }

        /* All child paths must have same parameterization */
        Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer));
    }

    /* Now we can compute total costs of the MergeAppend */
    cost_merge_append(&pathnode->path, root,
                      pathkeys, list_length(subpaths),
                      input_startup_cost, input_total_cost,
                      rel->tuples);

    return pathnode;
}

MergePath* create_mergejoin_path ( PlannerInfo root,
RelOptInfo joinrel,
JoinType  jointype,
JoinCostWorkspace workspace,
SpecialJoinInfo sjinfo,
Path outer_path,
Path inner_path,
List restrict_clauses,
List pathkeys,
Relids  required_outer,
List mergeclauses,
List outersortkeys,
List innersortkeys 
)

Definition at line 1894 of file pathnode.c.

References final_cost_mergejoin(), get_joinrel_parampathinfo(), JoinPath::innerjoinpath, MergePath::innersortkeys, JoinPath::joinrestrictinfo, JoinPath::jointype, MergePath::jpath, makeNode, JoinPath::outerjoinpath, MergePath::outersortkeys, Path::param_info, Path::parent, JoinPath::path, MergePath::path_mergeclauses, Path::pathkeys, and Path::pathtype.

Referenced by try_mergejoin_path().

{
    MergePath  *pathnode = makeNode(MergePath);

    pathnode->jpath.path.pathtype = T_MergeJoin;
    pathnode->jpath.path.parent = joinrel;
    pathnode->jpath.path.param_info =
        get_joinrel_parampathinfo(root,
                                  joinrel,
                                  outer_path,
                                  inner_path,
                                  sjinfo,
                                  required_outer,
                                  &restrict_clauses);
    pathnode->jpath.path.pathkeys = pathkeys;
    pathnode->jpath.jointype = jointype;
    pathnode->jpath.outerjoinpath = outer_path;
    pathnode->jpath.innerjoinpath = inner_path;
    pathnode->jpath.joinrestrictinfo = restrict_clauses;
    pathnode->path_mergeclauses = mergeclauses;
    pathnode->outersortkeys = outersortkeys;
    pathnode->innersortkeys = innersortkeys;
    /* pathnode->materialize_inner will be set by final_cost_mergejoin */

    final_cost_mergejoin(root, pathnode, workspace, sjinfo);

    return pathnode;
}

NestPath* create_nestloop_path ( PlannerInfo root,
RelOptInfo joinrel,
JoinType  jointype,
JoinCostWorkspace workspace,
SpecialJoinInfo sjinfo,
SemiAntiJoinFactors semifactors,
Path outer_path,
Path inner_path,
List restrict_clauses,
List pathkeys,
Relids  required_outer 
)

Definition at line 1812 of file pathnode.c.

References bms_overlap(), bms_union(), final_cost_nestloop(), get_joinrel_parampathinfo(), JoinPath::innerjoinpath, join_clause_is_movable_into(), JoinPath::joinrestrictinfo, JoinPath::jointype, lappend(), lfirst, makeNode, JoinPath::outerjoinpath, Path::param_info, Path::parent, JoinPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, and RelOptInfo::relids.

Referenced by try_nestloop_path().

{
    NestPath   *pathnode = makeNode(NestPath);
    Relids      inner_req_outer = PATH_REQ_OUTER(inner_path);

    /*
     * If the inner path is parameterized by the outer, we must drop any
     * restrict_clauses that are due to be moved into the inner path.  We have
     * to do this now, rather than postpone the work till createplan time,
     * because the restrict_clauses list can affect the size and cost
     * estimates for this path.
     */
    if (bms_overlap(inner_req_outer, outer_path->parent->relids))
    {
        Relids      inner_and_outer = bms_union(inner_path->parent->relids,
                                                inner_req_outer);
        List       *jclauses = NIL;
        ListCell   *lc;

        foreach(lc, restrict_clauses)
        {
            RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);

            if (!join_clause_is_movable_into(rinfo,
                                             inner_path->parent->relids,
                                             inner_and_outer))
                jclauses = lappend(jclauses, rinfo);
        }
        restrict_clauses = jclauses;
    }

    pathnode->path.pathtype = T_NestLoop;
    pathnode->path.parent = joinrel;
    pathnode->path.param_info =
        get_joinrel_parampathinfo(root,
                                  joinrel,
                                  outer_path,
                                  inner_path,
                                  sjinfo,
                                  required_outer,
                                  &restrict_clauses);
    pathnode->path.pathkeys = pathkeys;
    pathnode->jointype = jointype;
    pathnode->outerjoinpath = outer_path;
    pathnode->innerjoinpath = inner_path;
    pathnode->joinrestrictinfo = restrict_clauses;

    final_cost_nestloop(root, pathnode, workspace, sjinfo, semifactors);

    return pathnode;
}

ResultPath* create_result_path ( List quals  ) 

Definition at line 1019 of file pathnode.c.

References cpu_tuple_cost, makeNode, Path::param_info, Path::parent, ResultPath::path, Path::pathkeys, Path::pathtype, ResultPath::quals, Path::rows, Path::startup_cost, and Path::total_cost.

Referenced by query_planner().

{
    ResultPath *pathnode = makeNode(ResultPath);

    pathnode->path.pathtype = T_Result;
    pathnode->path.parent = NULL;
    pathnode->path.param_info = NULL;       /* there are no other rels... */
    pathnode->path.pathkeys = NIL;
    pathnode->quals = quals;

    /* Hardly worth defining a cost_result() function ... just do it */
    pathnode->path.rows = 1;
    pathnode->path.startup_cost = 0;
    pathnode->path.total_cost = cpu_tuple_cost;

    /*
     * In theory we should include the qual eval cost as well, but at present
     * that doesn't accomplish much except duplicate work that will be done
     * again in make_result; since this is only used for degenerate cases,
     * nothing interesting will be done with the path cost values...
     */

    return pathnode;
}

Path* create_seqscan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer 
)

Definition at line 693 of file pathnode.c.

References cost_seqscan(), get_baserel_parampathinfo(), makeNode, Path::param_info, Path::parent, Path::pathkeys, and Path::pathtype.

Referenced by plan_cluster_use_sort(), reparameterize_path(), and set_plain_rel_pathlist().

{
    Path       *pathnode = makeNode(Path);

    pathnode->pathtype = T_SeqScan;
    pathnode->parent = rel;
    pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                     required_outer);
    pathnode->pathkeys = NIL;   /* seqscan has unordered result */

    cost_seqscan(pathnode, root, rel, pathnode->param_info);

    return pathnode;
}

Path* create_subqueryscan_path ( PlannerInfo root,
RelOptInfo rel,
List pathkeys,
Relids  required_outer 
)

Definition at line 1602 of file pathnode.c.

References cost_subqueryscan(), get_baserel_parampathinfo(), makeNode, Path::param_info, Path::parent, Path::pathkeys, and Path::pathtype.

Referenced by reparameterize_path(), and set_subquery_pathlist().

{
    Path       *pathnode = makeNode(Path);

    pathnode->pathtype = T_SubqueryScan;
    pathnode->parent = rel;
    pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                     required_outer);
    pathnode->pathkeys = pathkeys;

    cost_subqueryscan(pathnode, root, rel, pathnode->param_info);

    return pathnode;
}

TidPath* create_tidscan_path ( PlannerInfo root,
RelOptInfo rel,
List tidquals,
Relids  required_outer 
)

Definition at line 863 of file pathnode.c.

References cost_tidscan(), get_baserel_parampathinfo(), makeNode, Path::param_info, Path::parent, TidPath::path, Path::pathkeys, Path::pathtype, and TidPath::tidquals.

Referenced by create_tidscan_paths().

{
    TidPath    *pathnode = makeNode(TidPath);

    pathnode->path.pathtype = T_TidScan;
    pathnode->path.parent = rel;
    pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
                                                          required_outer);
    pathnode->path.pathkeys = NIL;      /* always unordered */

    pathnode->tidquals = tidquals;

    cost_tidscan(&pathnode->path, root, rel, tidquals,
                 pathnode->path.param_info);

    return pathnode;
}

UniquePath* create_unique_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
SpecialJoinInfo sjinfo 
)

Definition at line 1084 of file pathnode.c.

References AGG_HASHED, OpExpr::args, Assert, bms_equal(), bms_is_empty(), bms_is_subset(), bms_overlap(), bms_union(), RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_path, contain_volatile_functions(), copyObject(), cost_agg(), cost_sort(), cpu_operator_cost, enable_hashagg, estimate_num_groups(), exprType(), get_commutator(), get_mergejoin_opfamilies(), UniquePath::in_operators, IsA, SpecialJoinInfo::join_quals, JOIN_SEMI, SpecialJoinInfo::jointype, lappend(), lappend_oid(), lfirst, linitial, list_length(), lsecond, makeNode, MemoryContextSwitchTo(), NIL, NULL, OidIsValid, op_hashjoinable(), op_mergejoinable(), OpExpr::opno, Path::param_info, Path::parent, UniquePath::path, Path::pathkeys, Path::pathtype, PlannerInfo::planner_cxt, planner_rt_fetch, pull_varnos(), query_is_distinct_for(), relation_has_unique_index_for(), RelOptInfo::relid, RelOptInfo::relids, RelOptInfo::rows, Path::rows, RTE_RELATION, RTE_SUBQUERY, RelOptInfo::rtekind, Path::startup_cost, UniquePath::subpath, RangeTblEntry::subquery, SpecialJoinInfo::syn_righthand, Path::total_cost, translate_sub_tlist(), UniquePath::umethod, UniquePath::uniq_exprs, UNIQUE_PATH_HASH, RelOptInfo::width, and work_mem.

Referenced by hash_inner_and_outer(), join_is_legal(), make_join_rel(), match_unsorted_outer(), and sort_inner_and_outer().

{
    UniquePath *pathnode;
    Path        sort_path;      /* dummy for result of cost_sort */
    Path        agg_path;       /* dummy for result of cost_agg */
    MemoryContext oldcontext;
    List       *in_operators;
    List       *uniq_exprs;
    bool        all_btree;
    bool        all_hash;
    int         numCols;
    ListCell   *lc;

    /* Caller made a mistake if subpath isn't cheapest_total ... */
    Assert(subpath == rel->cheapest_total_path);
    Assert(subpath->parent == rel);
    /* ... or if SpecialJoinInfo is the wrong one */
    Assert(sjinfo->jointype == JOIN_SEMI);
    Assert(bms_equal(rel->relids, sjinfo->syn_righthand));

    /* If result already cached, return it */
    if (rel->cheapest_unique_path)
        return (UniquePath *) rel->cheapest_unique_path;

    /* If we previously failed, return NULL quickly */
    if (sjinfo->join_quals == NIL)
        return NULL;

    /*
     * We must ensure path struct and subsidiary data are allocated in main
     * planning context; otherwise GEQO memory management causes trouble.
     */
    oldcontext = MemoryContextSwitchTo(root->planner_cxt);

    /*----------
     * Look to see whether the semijoin's join quals consist of AND'ed
     * equality operators, with (only) RHS variables on only one side of
     * each one.  If so, we can figure out how to enforce uniqueness for
     * the RHS.
     *
     * Note that the input join_quals list is the list of quals that are
     * *syntactically* associated with the semijoin, which in practice means
     * the synthesized comparison list for an IN or the WHERE of an EXISTS.
     * Particularly in the latter case, it might contain clauses that aren't
     * *semantically* associated with the join, but refer to just one side or
     * the other.  We can ignore such clauses here, as they will just drop
     * down to be processed within one side or the other.  (It is okay to
     * consider only the syntactically-associated clauses here because for a
     * semijoin, no higher-level quals could refer to the RHS, and so there
     * can be no other quals that are semantically associated with this join.
     * We do things this way because it is useful to be able to run this test
     * before we have extracted the list of quals that are actually
     * semantically associated with the particular join.)
     *
     * Note that the in_operators list consists of the joinqual operators
     * themselves (but commuted if needed to put the RHS value on the right).
     * These could be cross-type operators, in which case the operator
     * actually needed for uniqueness is a related single-type operator.
     * We assume here that that operator will be available from the btree
     * or hash opclass when the time comes ... if not, create_unique_plan()
     * will fail.
     *----------
     */
    in_operators = NIL;
    uniq_exprs = NIL;
    all_btree = true;
    all_hash = enable_hashagg;  /* don't consider hash if not enabled */
    foreach(lc, sjinfo->join_quals)
    {
        OpExpr     *op = (OpExpr *) lfirst(lc);
        Oid         opno;
        Node       *left_expr;
        Node       *right_expr;
        Relids      left_varnos;
        Relids      right_varnos;
        Relids      all_varnos;
        Oid         opinputtype;

        /* Is it a binary opclause? */
        if (!IsA(op, OpExpr) ||
            list_length(op->args) != 2)
        {
            /* No, but does it reference both sides? */
            all_varnos = pull_varnos((Node *) op);
            if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
                bms_is_subset(all_varnos, sjinfo->syn_righthand))
            {
                /*
                 * Clause refers to only one rel, so ignore it --- unless it
                 * contains volatile functions, in which case we'd better
                 * punt.
                 */
                if (contain_volatile_functions((Node *) op))
                    goto no_unique_path;
                continue;
            }
            /* Non-operator clause referencing both sides, must punt */
            goto no_unique_path;
        }

        /* Extract data from binary opclause */
        opno = op->opno;
        left_expr = linitial(op->args);
        right_expr = lsecond(op->args);
        left_varnos = pull_varnos(left_expr);
        right_varnos = pull_varnos(right_expr);
        all_varnos = bms_union(left_varnos, right_varnos);
        opinputtype = exprType(left_expr);

        /* Does it reference both sides? */
        if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
            bms_is_subset(all_varnos, sjinfo->syn_righthand))
        {
            /*
             * Clause refers to only one rel, so ignore it --- unless it
             * contains volatile functions, in which case we'd better punt.
             */
            if (contain_volatile_functions((Node *) op))
                goto no_unique_path;
            continue;
        }

        /* check rel membership of arguments */
        if (!bms_is_empty(right_varnos) &&
            bms_is_subset(right_varnos, sjinfo->syn_righthand) &&
            !bms_overlap(left_varnos, sjinfo->syn_righthand))
        {
            /* typical case, right_expr is RHS variable */
        }
        else if (!bms_is_empty(left_varnos) &&
                 bms_is_subset(left_varnos, sjinfo->syn_righthand) &&
                 !bms_overlap(right_varnos, sjinfo->syn_righthand))
        {
            /* flipped case, left_expr is RHS variable */
            opno = get_commutator(opno);
            if (!OidIsValid(opno))
                goto no_unique_path;
            right_expr = left_expr;
        }
        else
            goto no_unique_path;

        /* all operators must be btree equality or hash equality */
        if (all_btree)
        {
            /* oprcanmerge is considered a hint... */
            if (!op_mergejoinable(opno, opinputtype) ||
                get_mergejoin_opfamilies(opno) == NIL)
                all_btree = false;
        }
        if (all_hash)
        {
            /* ... but oprcanhash had better be correct */
            if (!op_hashjoinable(opno, opinputtype))
                all_hash = false;
        }
        if (!(all_btree || all_hash))
            goto no_unique_path;

        /* so far so good, keep building lists */
        in_operators = lappend_oid(in_operators, opno);
        uniq_exprs = lappend(uniq_exprs, copyObject(right_expr));
    }

    /* Punt if we didn't find at least one column to unique-ify */
    if (uniq_exprs == NIL)
        goto no_unique_path;

    /*
     * The expressions we'd need to unique-ify mustn't be volatile.
     */
    if (contain_volatile_functions((Node *) uniq_exprs))
        goto no_unique_path;

    /*
     * If we get here, we can unique-ify using at least one of sorting and
     * hashing.  Start building the result Path object.
     */
    pathnode = makeNode(UniquePath);

    pathnode->path.pathtype = T_Unique;
    pathnode->path.parent = rel;
    pathnode->path.param_info = subpath->param_info;

    /*
     * Assume the output is unsorted, since we don't necessarily have pathkeys
     * to represent it.  (This might get overridden below.)
     */
    pathnode->path.pathkeys = NIL;

    pathnode->subpath = subpath;
    pathnode->in_operators = in_operators;
    pathnode->uniq_exprs = uniq_exprs;

    /*
     * If the input is a relation and it has a unique index that proves the
     * uniq_exprs are unique, then we don't need to do anything.  Note that
     * relation_has_unique_index_for automatically considers restriction
     * clauses for the rel, as well.
     */
    if (rel->rtekind == RTE_RELATION && all_btree &&
        relation_has_unique_index_for(root, rel, NIL,
                                      uniq_exprs, in_operators))
    {
        pathnode->umethod = UNIQUE_PATH_NOOP;
        pathnode->path.rows = rel->rows;
        pathnode->path.startup_cost = subpath->startup_cost;
        pathnode->path.total_cost = subpath->total_cost;
        pathnode->path.pathkeys = subpath->pathkeys;

        rel->cheapest_unique_path = (Path *) pathnode;

        MemoryContextSwitchTo(oldcontext);

        return pathnode;
    }

    /*
     * If the input is a subquery whose output must be unique already, then we
     * don't need to do anything.  The test for uniqueness has to consider
     * exactly which columns we are extracting; for example "SELECT DISTINCT
     * x,y" doesn't guarantee that x alone is distinct. So we cannot check for
     * this optimization unless uniq_exprs consists only of simple Vars
     * referencing subquery outputs.  (Possibly we could do something with
     * expressions in the subquery outputs, too, but for now keep it simple.)
     */
    if (rel->rtekind == RTE_SUBQUERY)
    {
        RangeTblEntry *rte = planner_rt_fetch(rel->relid, root);
        List       *sub_tlist_colnos;

        sub_tlist_colnos = translate_sub_tlist(uniq_exprs, rel->relid);

        if (sub_tlist_colnos &&
            query_is_distinct_for(rte->subquery,
                                  sub_tlist_colnos, in_operators))
        {
            pathnode->umethod = UNIQUE_PATH_NOOP;
            pathnode->path.rows = rel->rows;
            pathnode->path.startup_cost = subpath->startup_cost;
            pathnode->path.total_cost = subpath->total_cost;
            pathnode->path.pathkeys = subpath->pathkeys;

            rel->cheapest_unique_path = (Path *) pathnode;

            MemoryContextSwitchTo(oldcontext);

            return pathnode;
        }
    }

    /* Estimate number of output rows */
    pathnode->path.rows = estimate_num_groups(root, uniq_exprs, rel->rows);
    numCols = list_length(uniq_exprs);

    if (all_btree)
    {
        /*
         * Estimate cost for sort+unique implementation
         */
        cost_sort(&sort_path, root, NIL,
                  subpath->total_cost,
                  rel->rows,
                  rel->width,
                  0.0,
                  work_mem,
                  -1.0);

        /*
         * 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.)  This should agree with
         * make_unique.
         */
        sort_path.total_cost += cpu_operator_cost * rel->rows * numCols;
    }

    if (all_hash)
    {
        /*
         * Estimate the overhead per hashtable entry at 64 bytes (same as in
         * planner.c).
         */
        int         hashentrysize = rel->width + 64;

        if (hashentrysize * pathnode->path.rows > work_mem * 1024L)
            all_hash = false;   /* don't try to hash */
        else
            cost_agg(&agg_path, root,
                     AGG_HASHED, NULL,
                     numCols, pathnode->path.rows,
                     subpath->startup_cost,
                     subpath->total_cost,
                     rel->rows);
    }

    if (all_btree && all_hash)
    {
        if (agg_path.total_cost < sort_path.total_cost)
            pathnode->umethod = UNIQUE_PATH_HASH;
        else
            pathnode->umethod = UNIQUE_PATH_SORT;
    }
    else if (all_btree)
        pathnode->umethod = UNIQUE_PATH_SORT;
    else if (all_hash)
        pathnode->umethod = UNIQUE_PATH_HASH;
    else
        goto no_unique_path;

    if (pathnode->umethod == UNIQUE_PATH_HASH)
    {
        pathnode->path.startup_cost = agg_path.startup_cost;
        pathnode->path.total_cost = agg_path.total_cost;
    }
    else
    {
        pathnode->path.startup_cost = sort_path.startup_cost;
        pathnode->path.total_cost = sort_path.total_cost;
    }

    rel->cheapest_unique_path = (Path *) pathnode;

    MemoryContextSwitchTo(oldcontext);

    return pathnode;

no_unique_path:         /* failure exit */

    /* Mark the SpecialJoinInfo as not unique-able */
    sjinfo->join_quals = NIL;

    MemoryContextSwitchTo(oldcontext);

    return NULL;
}

Path* create_valuesscan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer 
)

Definition at line 1646 of file pathnode.c.

References cost_valuesscan(), get_baserel_parampathinfo(), makeNode, Path::param_info, Path::parent, Path::pathkeys, and Path::pathtype.

Referenced by set_values_pathlist().

{
    Path       *pathnode = makeNode(Path);

    pathnode->pathtype = T_ValuesScan;
    pathnode->parent = rel;
    pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                     required_outer);
    pathnode->pathkeys = NIL;   /* result is always unordered */

    cost_valuesscan(pathnode, root, rel, pathnode->param_info);

    return pathnode;
}

Path* create_worktablescan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer 
)

Definition at line 1689 of file pathnode.c.

References cost_ctescan(), get_baserel_parampathinfo(), makeNode, Path::param_info, Path::parent, Path::pathkeys, and Path::pathtype.

Referenced by set_worktable_pathlist().

{
    Path       *pathnode = makeNode(Path);

    pathnode->pathtype = T_WorkTableScan;
    pathnode->parent = rel;
    pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                     required_outer);
    pathnode->pathkeys = NIL;   /* result is always unordered */

    /* Cost is the same as for a regular CTE scan */
    cost_ctescan(pathnode, root, rel, pathnode->param_info);

    return pathnode;
}

RelOptInfo* find_base_rel ( PlannerInfo root,
int  relid 
)
AppendRelInfo* find_childrel_appendrelinfo ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 687 of file relnode.c.

References PlannerInfo::append_rel_list, Assert, AppendRelInfo::child_relid, elog, ERROR, lfirst, RelOptInfo::relid, RELOPT_OTHER_MEMBER_REL, and RelOptInfo::reloptkind.

Referenced by check_partial_indexes(), generate_implied_equalities_for_column(), and generate_join_implied_equalities().

{
    Index       relid = rel->relid;
    ListCell   *lc;

    /* Should only be called on child rels */
    Assert(rel->reloptkind == RELOPT_OTHER_MEMBER_REL);

    foreach(lc, root->append_rel_list)
    {
        AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);

        if (appinfo->child_relid == relid)
            return appinfo;
    }
    /* should have found the entry ... */
    elog(ERROR, "child rel %d not found in append_rel_list", relid);
    return NULL;                /* not reached */
}

RelOptInfo* find_join_rel ( PlannerInfo root,
Relids  relids 
)

Definition at line 261 of file relnode.c.

References bms_equal(), build_join_rel_hash(), HASH_FIND, hash_search(), JoinHashEntry::join_rel, PlannerInfo::join_rel_hash, PlannerInfo::join_rel_list, lfirst, list_length(), NULL, and RelOptInfo::relids.

Referenced by build_join_rel(), examine_variable(), and find_join_input_rel().

{
    /*
     * Switch to using hash lookup when list grows "too long".  The threshold
     * is arbitrary and is known only here.
     */
    if (!root->join_rel_hash && list_length(root->join_rel_list) > 32)
        build_join_rel_hash(root);

    /*
     * Use either hashtable lookup or linear search, as appropriate.
     *
     * Note: the seemingly redundant hashkey variable is used to avoid taking
     * the address of relids; unless the compiler is exceedingly smart, doing
     * so would force relids out of a register and thus probably slow down the
     * list-search case.
     */
    if (root->join_rel_hash)
    {
        Relids      hashkey = relids;
        JoinHashEntry *hentry;

        hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
                                               &hashkey,
                                               HASH_FIND,
                                               NULL);
        if (hentry)
            return hentry->join_rel;
    }
    else
    {
        ListCell   *l;

        foreach(l, root->join_rel_list)
        {
            RelOptInfo *rel = (RelOptInfo *) lfirst(l);

            if (bms_equal(rel->relids, relids))
                return rel;
        }
    }

    return NULL;
}

ParamPathInfo* get_appendrel_parampathinfo ( RelOptInfo appendrel,
Relids  required_outer 
)

Definition at line 942 of file relnode.c.

References Assert, bms_equal(), bms_is_empty(), bms_overlap(), lappend(), lfirst, makeNode, ParamPathInfo::ppi_clauses, ParamPathInfo::ppi_req_outer, ParamPathInfo::ppi_rows, RelOptInfo::ppilist, and RelOptInfo::relids.

Referenced by create_append_path(), and create_merge_append_path().

{
    ParamPathInfo *ppi;
    ListCell   *lc;

    /* Unparameterized paths have no ParamPathInfo */
    if (bms_is_empty(required_outer))
        return NULL;

    Assert(!bms_overlap(appendrel->relids, required_outer));

    /* If we already have a PPI for this parameterization, just return it */
    foreach(lc, appendrel->ppilist)
    {
        ppi = (ParamPathInfo *) lfirst(lc);
        if (bms_equal(ppi->ppi_req_outer, required_outer))
            return ppi;
    }

    /* Else build the ParamPathInfo */
    ppi = makeNode(ParamPathInfo);
    ppi->ppi_req_outer = required_outer;
    ppi->ppi_rows = 0;
    ppi->ppi_clauses = NIL;
    appendrel->ppilist = lappend(appendrel->ppilist, ppi);

    return ppi;
}

ParamPathInfo* get_baserel_parampathinfo ( PlannerInfo root,
RelOptInfo baserel,
Relids  required_outer 
)

Definition at line 720 of file relnode.c.

References Assert, bms_equal(), bms_is_empty(), bms_overlap(), bms_union(), generate_join_implied_equalities(), get_parameterized_baserel_size(), join_clause_is_movable_into(), RelOptInfo::joininfo, lappend(), lfirst, list_concat(), makeNode, ParamPathInfo::ppi_clauses, ParamPathInfo::ppi_req_outer, ParamPathInfo::ppi_rows, RelOptInfo::ppilist, and RelOptInfo::relids.

Referenced by bitmap_and_cost_est(), bitmap_scan_cost_est(), create_bitmap_heap_path(), create_ctescan_path(), create_foreignscan_path(), create_functionscan_path(), create_index_path(), create_seqscan_path(), create_subqueryscan_path(), create_tidscan_path(), create_valuesscan_path(), create_worktablescan_path(), and reparameterize_path().

{
    ParamPathInfo *ppi;
    Relids      joinrelids;
    List       *pclauses;
    double      rows;
    ListCell   *lc;

    /* Unparameterized paths have no ParamPathInfo */
    if (bms_is_empty(required_outer))
        return NULL;

    Assert(!bms_overlap(baserel->relids, required_outer));

    /* If we already have a PPI for this parameterization, just return it */
    foreach(lc, baserel->ppilist)
    {
        ppi = (ParamPathInfo *) lfirst(lc);
        if (bms_equal(ppi->ppi_req_outer, required_outer))
            return ppi;
    }

    /*
     * Identify all joinclauses that are movable to this base rel given this
     * parameterization.
     */
    joinrelids = bms_union(baserel->relids, required_outer);
    pclauses = NIL;
    foreach(lc, baserel->joininfo)
    {
        RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);

        if (join_clause_is_movable_into(rinfo,
                                        baserel->relids,
                                        joinrelids))
            pclauses = lappend(pclauses, rinfo);
    }

    /*
     * Add in joinclauses generated by EquivalenceClasses, too.  (These
     * necessarily satisfy join_clause_is_movable_into.)
     */
    pclauses = list_concat(pclauses,
                           generate_join_implied_equalities(root,
                                                            joinrelids,
                                                            required_outer,
                                                            baserel));

    /* Estimate the number of rows returned by the parameterized scan */
    rows = get_parameterized_baserel_size(root, baserel, pclauses);

    /* And now we can build the ParamPathInfo */
    ppi = makeNode(ParamPathInfo);
    ppi->ppi_req_outer = required_outer;
    ppi->ppi_rows = rows;
    ppi->ppi_clauses = pclauses;
    baserel->ppilist = lappend(baserel->ppilist, ppi);

    return ppi;
}

ParamPathInfo* get_joinrel_parampathinfo ( PlannerInfo root,
RelOptInfo joinrel,
Path outer_path,
Path inner_path,
SpecialJoinInfo sjinfo,
Relids  required_outer,
List **  restrict_clauses 
)

Definition at line 811 of file relnode.c.

References Assert, bms_equal(), bms_is_empty(), bms_overlap(), bms_union(), generate_join_implied_equalities(), get_parameterized_joinrel_size(), join_clause_is_movable_into(), RelOptInfo::joininfo, lappend(), lfirst, list_concat(), makeNode, Path::param_info, Path::parent, PATH_REQ_OUTER, ParamPathInfo::ppi_clauses, ParamPathInfo::ppi_req_outer, ParamPathInfo::ppi_rows, RelOptInfo::ppilist, RelOptInfo::relids, and Path::rows.

Referenced by create_hashjoin_path(), create_mergejoin_path(), and create_nestloop_path().

{
    ParamPathInfo *ppi;
    Relids      join_and_req;
    Relids      outer_and_req;
    Relids      inner_and_req;
    List       *pclauses;
    List       *eclauses;
    double      rows;
    ListCell   *lc;

    /* Unparameterized paths have no ParamPathInfo or extra join clauses */
    if (bms_is_empty(required_outer))
        return NULL;

    Assert(!bms_overlap(joinrel->relids, required_outer));

    /*
     * Identify all joinclauses that are movable to this join rel given this
     * parameterization.  These are the clauses that are movable into this
     * join, but not movable into either input path.  Treat an unparameterized
     * input path as not accepting parameterized clauses (because it won't,
     * per the shortcut exit above), even though the joinclause movement rules
     * might allow the same clauses to be moved into a parameterized path for
     * that rel.
     */
    join_and_req = bms_union(joinrel->relids, required_outer);
    if (outer_path->param_info)
        outer_and_req = bms_union(outer_path->parent->relids,
                                  PATH_REQ_OUTER(outer_path));
    else
        outer_and_req = NULL;   /* outer path does not accept parameters */
    if (inner_path->param_info)
        inner_and_req = bms_union(inner_path->parent->relids,
                                  PATH_REQ_OUTER(inner_path));
    else
        inner_and_req = NULL;   /* inner path does not accept parameters */

    pclauses = NIL;
    foreach(lc, joinrel->joininfo)
    {
        RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);

        if (join_clause_is_movable_into(rinfo,
                                        joinrel->relids,
                                        join_and_req) &&
            !join_clause_is_movable_into(rinfo,
                                         outer_path->parent->relids,
                                         outer_and_req) &&
            !join_clause_is_movable_into(rinfo,
                                         inner_path->parent->relids,
                                         inner_and_req))
            pclauses = lappend(pclauses, rinfo);
    }

    /* Consider joinclauses generated by EquivalenceClasses, too */
    eclauses = generate_join_implied_equalities(root,
                                                join_and_req,
                                                required_outer,
                                                joinrel);
    /* We only want ones that aren't movable to lower levels */
    foreach(lc, eclauses)
    {
        RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);

        Assert(join_clause_is_movable_into(rinfo,
                                           joinrel->relids,
                                           join_and_req));
        if (!join_clause_is_movable_into(rinfo,
                                         outer_path->parent->relids,
                                         outer_and_req) &&
            !join_clause_is_movable_into(rinfo,
                                         inner_path->parent->relids,
                                         inner_and_req))
            pclauses = lappend(pclauses, rinfo);
    }

    /*
     * Now, attach the identified moved-down clauses to the caller's
     * restrict_clauses list.  By using list_concat in this order, we leave
     * the original list structure of restrict_clauses undamaged.
     */
    *restrict_clauses = list_concat(pclauses, *restrict_clauses);

    /* If we already have a PPI for this parameterization, just return it */
    foreach(lc, joinrel->ppilist)
    {
        ppi = (ParamPathInfo *) lfirst(lc);
        if (bms_equal(ppi->ppi_req_outer, required_outer))
            return ppi;
    }

    /* Estimate the number of rows returned by the parameterized join */
    rows = get_parameterized_joinrel_size(root, joinrel,
                                          outer_path->rows,
                                          inner_path->rows,
                                          sjinfo,
                                          *restrict_clauses);

    /*
     * And now we can build the ParamPathInfo.  No point in saving the
     * input-pair-dependent clause list, though.
     *
     * Note: in GEQO mode, we'll be called in a temporary memory context, but
     * the joinrel structure is there too, so no problem.
     */
    ppi = makeNode(ParamPathInfo);
    ppi->ppi_req_outer = required_outer;
    ppi->ppi_rows = rows;
    ppi->ppi_clauses = NIL;
    joinrel->ppilist = lappend(joinrel->ppilist, ppi);

    return ppi;
}

Path* reparameterize_path ( PlannerInfo root,
Path path,
Relids  required_outer,
double  loop_count 
)

Definition at line 2019 of file pathnode.c.

References BitmapHeapPath::bitmapqual, bms_is_subset(), cost_index(), create_bitmap_heap_path(), create_seqscan_path(), create_subqueryscan_path(), get_baserel_parampathinfo(), makeNode, Path::param_info, Path::parent, IndexPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, T_BitmapHeapScan, T_IndexOnlyScan, T_IndexScan, T_SeqScan, and T_SubqueryScan.

Referenced by set_append_rel_pathlist().

{
    RelOptInfo *rel = path->parent;

    /* Can only increase, not decrease, path's parameterization */
    if (!bms_is_subset(PATH_REQ_OUTER(path), required_outer))
        return NULL;
    switch (path->pathtype)
    {
        case T_SeqScan:
            return create_seqscan_path(root, rel, required_outer);
        case T_IndexScan:
        case T_IndexOnlyScan:
            {
                IndexPath  *ipath = (IndexPath *) path;
                IndexPath  *newpath = makeNode(IndexPath);

                /*
                 * We can't use create_index_path directly, and would not want
                 * to because it would re-compute the indexqual conditions
                 * which is wasted effort.  Instead we hack things a bit:
                 * flat-copy the path node, revise its param_info, and redo
                 * the cost estimate.
                 */
                memcpy(newpath, ipath, sizeof(IndexPath));
                newpath->path.param_info =
                    get_baserel_parampathinfo(root, rel, required_outer);
                cost_index(newpath, root, loop_count);
                return (Path *) newpath;
            }
        case T_BitmapHeapScan:
            {
                BitmapHeapPath *bpath = (BitmapHeapPath *) path;

                return (Path *) create_bitmap_heap_path(root,
                                                        rel,
                                                        bpath->bitmapqual,
                                                        required_outer,
                                                        loop_count);
            }
        case T_SubqueryScan:
            return create_subqueryscan_path(root, rel, path->pathkeys,
                                            required_outer);
        default:
            break;
    }
    return NULL;
}

void set_cheapest ( RelOptInfo parent_rel  ) 

Definition at line 226 of file pathnode.c.

References Assert, BMS_DIFFERENT, BMS_EQUAL, BMS_SUBSET1, BMS_SUBSET2, bms_subset_compare(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_path, compare_path_costs(), compare_pathkeys(), elog, ERROR, IsA, lappend(), lcons(), lfirst, NIL, NULL, Path::param_info, PATH_REQ_OUTER, Path::pathkeys, PATHKEYS_BETTER2, RelOptInfo::pathlist, STARTUP_COST, and TOTAL_COST.

Referenced by mark_dummy_rel(), merge_clump(), set_append_rel_pathlist(), set_cte_pathlist(), set_dummy_rel_pathlist(), set_foreign_pathlist(), set_function_pathlist(), set_plain_rel_pathlist(), set_subquery_pathlist(), set_values_pathlist(), set_worktable_pathlist(), and standard_join_search().

{
    Path       *cheapest_startup_path;
    Path       *cheapest_total_path;
    Path       *best_param_path;
    List       *parameterized_paths;
    ListCell   *p;

    Assert(IsA(parent_rel, RelOptInfo));

    if (parent_rel->pathlist == NIL)
        elog(ERROR, "could not devise a query plan for the given query");

    cheapest_startup_path = cheapest_total_path = best_param_path = NULL;
    parameterized_paths = NIL;

    foreach(p, parent_rel->pathlist)
    {
        Path       *path = (Path *) lfirst(p);
        int         cmp;

        if (path->param_info)
        {
            /* Parameterized path, so add it to parameterized_paths */
            parameterized_paths = lappend(parameterized_paths, path);

            /*
             * If we have an unparameterized cheapest-total, we no longer care
             * about finding the best parameterized path, so move on.
             */
            if (cheapest_total_path)
                continue;

            /*
             * Otherwise, track the best parameterized path, which is the one
             * with least total cost among those of the minimum
             * parameterization.
             */
            if (best_param_path == NULL)
                best_param_path = path;
            else
            {
                switch (bms_subset_compare(PATH_REQ_OUTER(path),
                                           PATH_REQ_OUTER(best_param_path)))
                {
                    case BMS_EQUAL:
                        /* keep the cheaper one */
                        if (compare_path_costs(path, best_param_path,
                                               TOTAL_COST) < 0)
                            best_param_path = path;
                        break;
                    case BMS_SUBSET1:
                        /* new path is less-parameterized */
                        best_param_path = path;
                        break;
                    case BMS_SUBSET2:
                        /* old path is less-parameterized, keep it */
                        break;
                    case BMS_DIFFERENT:
                        /*
                         * This means that neither path has the least possible
                         * parameterization for the rel.  We'll sit on the old
                         * path until something better comes along.
                         */
                        break;
                }
            }
        }
        else
        {
            /* Unparameterized path, so consider it for cheapest slots */
            if (cheapest_total_path == NULL)
            {
                cheapest_startup_path = cheapest_total_path = path;
                continue;
            }

            /*
             * If we find two paths of identical costs, try to keep the
             * better-sorted one.  The paths might have unrelated sort
             * orderings, in which case we can only guess which might be
             * better to keep, but if one is superior then we definitely
             * should keep that one.
             */
            cmp = compare_path_costs(cheapest_startup_path, path, STARTUP_COST);
            if (cmp > 0 ||
                (cmp == 0 &&
                 compare_pathkeys(cheapest_startup_path->pathkeys,
                                  path->pathkeys) == PATHKEYS_BETTER2))
                cheapest_startup_path = path;

            cmp = compare_path_costs(cheapest_total_path, path, TOTAL_COST);
            if (cmp > 0 ||
                (cmp == 0 &&
                 compare_pathkeys(cheapest_total_path->pathkeys,
                                  path->pathkeys) == PATHKEYS_BETTER2))
                cheapest_total_path = path;
        }
    }

    /* Add cheapest unparameterized path, if any, to parameterized_paths */
    if (cheapest_total_path)
        parameterized_paths = lcons(cheapest_total_path, parameterized_paths);

    /*
     * If there is no unparameterized path, use the best parameterized path
     * as cheapest_total_path (but not as cheapest_startup_path).
     */
    if (cheapest_total_path == NULL)
        cheapest_total_path = best_param_path;
    Assert(cheapest_total_path != NULL);

    parent_rel->cheapest_startup_path = cheapest_startup_path;
    parent_rel->cheapest_total_path = cheapest_total_path;
    parent_rel->cheapest_unique_path = NULL;    /* computed only if needed */
    parent_rel->cheapest_parameterized_paths = parameterized_paths;
}

void setup_simple_rel_arrays ( PlannerInfo root  ) 

Definition at line 54 of file relnode.c.

References lfirst, list_length(), palloc0(), PlannerInfo::parse, Query::rtable, PlannerInfo::simple_rel_array, PlannerInfo::simple_rel_array_size, and PlannerInfo::simple_rte_array.

Referenced by plan_cluster_use_sort(), plan_set_operations(), and query_planner().

{
    Index       rti;
    ListCell   *lc;

    /* Arrays are accessed using RT indexes (1..N) */
    root->simple_rel_array_size = list_length(root->parse->rtable) + 1;

    /* simple_rel_array is initialized to all NULLs */
    root->simple_rel_array = (RelOptInfo **)
        palloc0(root->simple_rel_array_size * sizeof(RelOptInfo *));

    /* simple_rte_array is an array equivalent of the rtable list */
    root->simple_rte_array = (RangeTblEntry **)
        palloc0(root->simple_rel_array_size * sizeof(RangeTblEntry *));
    rti = 1;
    foreach(lc, root->parse->rtable)
    {
        RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);

        root->simple_rte_array[rti++] = rte;
    }
}