#include "postgres.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/placeholder.h"
#include "optimizer/plancat.h"
#include "optimizer/restrictinfo.h"
#include "utils/hsearch.h"
Go to the source code of this file.
typedef struct JoinHashEntry JoinHashEntry |
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; }
static void build_join_rel_hash | ( | PlannerInfo * | root | ) | [static] |
Definition at line 219 of file relnode.c.
References Assert, CurrentMemoryContext, HASHCTL::entrysize, HASHCTL::hash, HASH_COMPARE, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_FUNCTION, hash_search(), HASHCTL::hcxt, JoinHashEntry::join_rel, PlannerInfo::join_rel_hash, PlannerInfo::join_rel_list, HASHCTL::keysize, lfirst, HASHCTL::match, MemSet, and RelOptInfo::relids.
Referenced by find_join_rel().
{ HTAB *hashtab; HASHCTL hash_ctl; ListCell *l; /* Create the hash table */ MemSet(&hash_ctl, 0, sizeof(hash_ctl)); hash_ctl.keysize = sizeof(Relids); hash_ctl.entrysize = sizeof(JoinHashEntry); hash_ctl.hash = bitmap_hash; hash_ctl.match = bitmap_match; hash_ctl.hcxt = CurrentMemoryContext; hashtab = hash_create("JoinRelHashTable", 256L, &hash_ctl, HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT); /* Insert all the already-existing joinrels */ foreach(l, root->join_rel_list) { RelOptInfo *rel = (RelOptInfo *) lfirst(l); JoinHashEntry *hentry; bool found; hentry = (JoinHashEntry *) hash_search(hashtab, &(rel->relids), HASH_ENTER, &found); Assert(!found); hentry->join_rel = rel; } root->join_rel_hash = hashtab; }
static void build_joinrel_joinlist | ( | RelOptInfo * | joinrel, | |
RelOptInfo * | outer_rel, | |||
RelOptInfo * | inner_rel | |||
) | [static] |
Definition at line 592 of file relnode.c.
References RelOptInfo::joininfo, NIL, and subbuild_joinrel_joinlist().
Referenced by build_join_rel().
{ List *result; /* * Collect all the clauses that syntactically belong above this level, * eliminating any duplicates (important since we will see many of the * same clauses arriving from both input relations). */ result = subbuild_joinrel_joinlist(joinrel, outer_rel->joininfo, NIL); result = subbuild_joinrel_joinlist(joinrel, inner_rel->joininfo, result); joinrel->joininfo = result; }
static List * build_joinrel_restrictlist | ( | PlannerInfo * | root, | |
RelOptInfo * | joinrel, | |||
RelOptInfo * | outer_rel, | |||
RelOptInfo * | inner_rel | |||
) | [static] |
Definition at line 562 of file relnode.c.
References generate_join_implied_equalities(), RelOptInfo::joininfo, list_concat(), NIL, RelOptInfo::relids, and subbuild_joinrel_restrictlist().
Referenced by build_join_rel().
{ List *result; /* * Collect all the clauses that syntactically belong at this level, * eliminating any duplicates (important since we will see many of the * same clauses arriving from both input relations). */ result = subbuild_joinrel_restrictlist(joinrel, outer_rel->joininfo, NIL); result = subbuild_joinrel_restrictlist(joinrel, inner_rel->joininfo, result); /* * Add on any clauses derived from EquivalenceClasses. These cannot be * redundant with the clauses in the joininfo lists, so don't bother * checking. */ result = list_concat(result, generate_join_implied_equalities(root, joinrel->relids, outer_rel->relids, inner_rel)); return result; }
static void build_joinrel_tlist | ( | PlannerInfo * | root, | |
RelOptInfo * | joinrel, | |||
RelOptInfo * | input_rel | |||
) | [static] |
Definition at line 477 of file relnode.c.
References RelOptInfo::attr_needed, RelOptInfo::attr_widths, bms_nonempty_difference(), elog, ERROR, find_base_rel(), IsA, lappend(), lfirst, RelOptInfo::min_attr, nodeTag, RelOptInfo::relids, RelOptInfo::reltargetlist, Var::varattno, Var::varno, and RelOptInfo::width.
Referenced by build_join_rel().
{ Relids relids = joinrel->relids; ListCell *vars; foreach(vars, input_rel->reltargetlist) { Var *var = (Var *) lfirst(vars); RelOptInfo *baserel; int ndx; /* * Ignore PlaceHolderVars in the input tlists; we'll make our own * decisions about whether to copy them. */ if (IsA(var, PlaceHolderVar)) continue; /* * Otherwise, anything in a baserel or joinrel targetlist ought to be * a Var. (More general cases can only appear in appendrel child * rels, which will never be seen here.) */ if (!IsA(var, Var)) elog(ERROR, "unexpected node type in reltargetlist: %d", (int) nodeTag(var)); /* Get the Var's original base rel */ baserel = find_base_rel(root, var->varno); /* Is it still needed above this joinrel? */ ndx = var->varattno - baserel->min_attr; if (bms_nonempty_difference(baserel->attr_needed[ndx], relids)) { /* Yup, add it to the output */ joinrel->reltargetlist = lappend(joinrel->reltargetlist, var); joinrel->width += baserel->attr_widths[ndx]; } } }
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; }
RelOptInfo* find_base_rel | ( | PlannerInfo * | root, | |
int | relid | |||
) |
Definition at line 196 of file relnode.c.
References Assert, elog, ERROR, and PlannerInfo::simple_rel_array.
Referenced by add_join_clause_to_rels(), add_placeholders_to_base_rels(), add_vars_to_targetlist(), build_joinrel_tlist(), clause_selectivity(), distribute_restrictinfo_to_rels(), examine_simple_variable(), examine_variable(), find_join_input_rel(), join_is_removable(), make_rel_from_joinlist(), remove_join_clause_from_rels(), remove_rel_from_query(), set_append_rel_size(), set_subquery_size_estimates(), and set_subqueryscan_references().
{ RelOptInfo *rel; Assert(relid > 0); if (relid < root->simple_rel_array_size) { rel = root->simple_rel_array[relid]; if (rel) return rel; } elog(ERROR, "no relation entry for relid %d", relid); return NULL; /* keep compiler quiet */ }
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; }
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; } }
static List * subbuild_joinrel_joinlist | ( | RelOptInfo * | joinrel, | |
List * | joininfo_list, | |||
List * | new_joininfo | |||
) | [static] |
Definition at line 644 of file relnode.c.
References bms_is_subset(), lfirst, list_append_unique_ptr(), RelOptInfo::relids, and RestrictInfo::required_relids.
Referenced by build_joinrel_joinlist().
{ ListCell *l; foreach(l, joininfo_list) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); if (bms_is_subset(rinfo->required_relids, joinrel->relids)) { /* * This clause becomes a restriction clause for the joinrel, since * it refers to no outside rels. So we can ignore it in this * routine. */ } else { /* * This clause is still a join clause at this level, so add it to * the new joininfo list, being careful to eliminate duplicates. * (Since RestrictInfo nodes in different joinlists will have been * multiply-linked rather than copied, pointer equality should be * a sufficient test.) */ new_joininfo = list_append_unique_ptr(new_joininfo, rinfo); } } return new_joininfo; }
static List * subbuild_joinrel_restrictlist | ( | RelOptInfo * | joinrel, | |
List * | joininfo_list, | |||
List * | new_restrictlist | |||
) | [static] |
Definition at line 610 of file relnode.c.
References bms_is_subset(), lfirst, list_append_unique_ptr(), RelOptInfo::relids, and RestrictInfo::required_relids.
Referenced by build_joinrel_restrictlist().
{ ListCell *l; foreach(l, joininfo_list) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); if (bms_is_subset(rinfo->required_relids, joinrel->relids)) { /* * This clause becomes a restriction clause for the joinrel, since * it refers to no outside rels. Add it to the list, being * careful to eliminate duplicates. (Since RestrictInfo nodes in * different joinlists will have been multiply-linked rather than * copied, pointer equality should be a sufficient test.) */ new_restrictlist = list_append_unique_ptr(new_restrictlist, rinfo); } else { /* * This clause is still a join clause at this level, so we ignore * it in this routine. */ } } return new_restrictlist; }