pathnode.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,297 行 · 第 1/3 页
C
1,297 行
IndexPath *pathnode = makeNode(IndexPath); RelOptInfo *rel = index->rel; List *indexquals, *allclauses; /* * For a join inner scan, there's no point in marking the path with any * pathkeys, since it will only ever be used as the inner path of a * nestloop, and so its ordering does not matter. For the same reason we * don't really care what order it's scanned in. (We could expect the * caller to supply the correct values, but it's easier to force it here.) */ if (outer_rel != NULL) { pathkeys = NIL; indexscandir = NoMovementScanDirection; } pathnode->path.pathtype = T_IndexScan; pathnode->path.parent = rel; pathnode->path.pathkeys = pathkeys; /* Convert clauses to indexquals the executor can handle */ indexquals = expand_indexqual_conditions(index, clause_groups); /* Flatten the clause-groups list to produce indexclauses list */ allclauses = flatten_clausegroups_list(clause_groups); /* Fill in the pathnode */ pathnode->indexinfo = index; pathnode->indexclauses = allclauses; pathnode->indexquals = indexquals; pathnode->isjoininner = (outer_rel != NULL); pathnode->indexscandir = indexscandir; if (outer_rel != NULL) { /* * We must compute the estimated number of output rows for the * indexscan. This is less than rel->rows because of the additional * selectivity of the join clauses. Since clause_groups may contain * both restriction and join clauses, we have to do a set union to get * the full set of clauses that must be considered to compute the * correct selectivity. (Without the union operation, we might have * some restriction clauses appearing twice, which'd mislead * clauselist_selectivity into double-counting their selectivity. * However, since RestrictInfo nodes aren't copied when linking them * into different lists, it should be sufficient to use pointer * comparison to remove duplicates.) * * Always assume the join type is JOIN_INNER; even if some of the join * clauses come from other contexts, that's not our problem. */ allclauses = list_union_ptr(rel->baserestrictinfo, allclauses); pathnode->rows = rel->tuples * clauselist_selectivity(root, allclauses, rel->relid, /* do not use 0! */ JOIN_INNER); /* Like costsize.c, force estimate to be at least one row */ pathnode->rows = clamp_row_est(pathnode->rows); } else { /* * The number of rows is the same as the parent rel's estimate, since * this isn't a join inner indexscan. */ pathnode->rows = rel->rows; } cost_index(pathnode, root, index, indexquals, outer_rel); return pathnode;}/* * create_bitmap_heap_path * Creates a path node for a bitmap scan. * * 'bitmapqual' is a tree of IndexPath, BitmapAndPath, and BitmapOrPath nodes. * * If this is a join inner indexscan path, 'outer_rel' is the outer relation, * and all the component IndexPaths should have been costed accordingly. */BitmapHeapPath *create_bitmap_heap_path(PlannerInfo *root, RelOptInfo *rel, Path *bitmapqual, RelOptInfo *outer_rel){ BitmapHeapPath *pathnode = makeNode(BitmapHeapPath); pathnode->path.pathtype = T_BitmapHeapScan; pathnode->path.parent = rel; pathnode->path.pathkeys = NIL; /* always unordered */ pathnode->bitmapqual = bitmapqual; pathnode->isjoininner = (outer_rel != NULL); if (pathnode->isjoininner) { /* * We must compute the estimated number of output rows for the * indexscan. This is less than rel->rows because of the additional * selectivity of the join clauses. We make use of the selectivity * estimated for the bitmap to do this; this isn't really quite right * since there may be restriction conditions not included in the * bitmap ... */ Cost indexTotalCost; Selectivity indexSelectivity; cost_bitmap_tree_node(bitmapqual, &indexTotalCost, &indexSelectivity); pathnode->rows = rel->tuples * indexSelectivity; if (pathnode->rows > rel->rows) pathnode->rows = rel->rows; /* Like costsize.c, force estimate to be at least one row */ pathnode->rows = clamp_row_est(pathnode->rows); } else { /* * The number of rows is the same as the parent rel's estimate, since * this isn't a join inner indexscan. */ pathnode->rows = rel->rows; } cost_bitmap_heap_scan(&pathnode->path, root, rel, bitmapqual, outer_rel); return pathnode;}/* * create_bitmap_and_path * Creates a path node representing a BitmapAnd. */BitmapAndPath *create_bitmap_and_path(PlannerInfo *root, RelOptInfo *rel, List *bitmapquals){ BitmapAndPath *pathnode = makeNode(BitmapAndPath); pathnode->path.pathtype = T_BitmapAnd; pathnode->path.parent = rel; 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;}/* * create_bitmap_or_path * Creates a path node representing a BitmapOr. */BitmapOrPath *create_bitmap_or_path(PlannerInfo *root, RelOptInfo *rel, List *bitmapquals){ BitmapOrPath *pathnode = makeNode(BitmapOrPath); pathnode->path.pathtype = T_BitmapOr; pathnode->path.parent = rel; 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;}/* * create_tidscan_path * Creates a path corresponding to a scan by TID, returning the pathnode. */TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals){ TidPath *pathnode = makeNode(TidPath); pathnode->path.pathtype = T_TidScan; pathnode->path.parent = rel; pathnode->path.pathkeys = NIL; pathnode->tidquals = tidquals; cost_tidscan(&pathnode->path, root, rel, tidquals); return pathnode;}/* * create_append_path * Creates a path corresponding to an Append plan, returning the * pathnode. */AppendPath *create_append_path(RelOptInfo *rel, List *subpaths){ AppendPath *pathnode = makeNode(AppendPath); ListCell *l; pathnode->path.pathtype = T_Append; pathnode->path.parent = rel; pathnode->path.pathkeys = NIL; /* result is always considered * unsorted */ pathnode->subpaths = subpaths; pathnode->path.startup_cost = 0; pathnode->path.total_cost = 0; foreach(l, subpaths) { Path *subpath = (Path *) lfirst(l); if (l == list_head(subpaths)) /* first node? */ pathnode->path.startup_cost = subpath->startup_cost; pathnode->path.total_cost += subpath->total_cost; } return pathnode;}/* * create_result_path * Creates a path representing a Result-and-nothing-else plan. * This is only used for the case of a query with an empty jointree. */ResultPath *create_result_path(List *quals){ ResultPath *pathnode = makeNode(ResultPath); pathnode->path.pathtype = T_Result; pathnode->path.parent = NULL; pathnode->path.pathkeys = NIL; pathnode->quals = quals; /* Ideally should define cost_result(), but I'm too lazy */ 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;}/* * create_material_path * Creates a path corresponding to a Material plan, returning the * pathnode. */MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath){ MaterialPath *pathnode = makeNode(MaterialPath); pathnode->path.pathtype = T_Material; pathnode->path.parent = rel; pathnode->path.pathkeys = subpath->pathkeys; pathnode->subpath = subpath; cost_material(&pathnode->path, subpath->total_cost, rel->rows, rel->width); return pathnode;}/* * create_unique_path * Creates a path representing elimination of distinct rows from the * input data. * * If used at all, this is likely to be called repeatedly on the same rel; * and the input subpath should always be the same (the cheapest_total path * for the rel). So we cache the result. */UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath){ UniquePath *pathnode; Path sort_path; /* dummy for result of cost_sort */ Path agg_path; /* dummy for result of cost_agg */ MemoryContext oldcontext; List *sub_targetlist; List *in_operators; ListCell *l; int numCols; /* Caller made a mistake if subpath isn't cheapest_total */ Assert(subpath == rel->cheapest_total_path); /* If result already cached, return it */ if (rel->cheapest_unique_path) return (UniquePath *) rel->cheapest_unique_path; /* * We must ensure path struct is allocated in main planning context; * otherwise GEQO memory management causes trouble. (Compare * best_inner_indexscan().) */ oldcontext = MemoryContextSwitchTo(root->planner_cxt); pathnode = makeNode(UniquePath); /* There is no substructure to allocate, so can switch back right away */ MemoryContextSwitchTo(oldcontext); pathnode->path.pathtype = T_Unique; pathnode->path.parent = rel; /* * Treat the output as always unsorted, since we don't necessarily have * pathkeys to represent it. */ pathnode->path.pathkeys = NIL; pathnode->subpath = subpath; /* * Try to identify the targetlist that will actually be unique-ified. In * current usage, this routine is only used for sub-selects of IN clauses, * so we should be able to find the tlist in in_info_list. Get the IN * clause's operators, too, because they determine what "unique" means. */ sub_targetlist = NIL; in_operators = NIL; foreach(l, root->in_info_list) { InClauseInfo *ininfo = (InClauseInfo *) lfirst(l); if (bms_equal(ininfo->righthand, rel->relids)) { sub_targetlist = ininfo->sub_targetlist; in_operators = ininfo->in_operators; break; } } /* * 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 we found our own targetlist above, and it * 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 (sub_targetlist && rel->rtekind == RTE_SUBQUERY) { RangeTblEntry *rte = planner_rt_fetch(rel->relid, root); List *sub_tlist_colnos; sub_tlist_colnos = translate_sub_tlist(sub_targetlist, rel->relid); if (sub_tlist_colnos && query_is_distinct_for(rte->subquery, sub_tlist_colnos, in_operators)) { pathnode->umethod = UNIQUE_PATH_NOOP; pathnode->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; return pathnode; } } /* * If we know the targetlist, try to estimate number of result rows; * otherwise punt. */ if (sub_targetlist) { pathnode->rows = estimate_num_groups(root, sub_targetlist, rel->rows); numCols = list_length(sub_targetlist); } else { pathnode->rows = rel->rows; numCols = list_length(rel->reltargetlist); } /* * Estimate cost for sort+unique implementation */ cost_sort(&sort_path, root, NIL, subpath->total_cost, rel->rows, rel->width, -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; /* * Is it safe to use a hashed implementation? If so, estimate and compare * costs. We only try this if we know the IN operators, else we can't * check their hashability. */ pathnode->umethod = UNIQUE_PATH_SORT; if (enable_hashagg && in_operators && hash_safe_operators(in_operators)) { /* * Estimate the overhead per hashtable entry at 64 bytes (same as in * planner.c). */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?