📄 createplan.c
字号:
/*------------------------------------------------------------------------- * * createplan.c * Routines to create the desired plan for processing a query. * Planning is complete, we just need to convert the selected * Path into a Plan. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.202.2.4 2006/05/18 18:57:37 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <limits.h>#include "nodes/makefuncs.h"#include "nodes/nodeFuncs.h"#include "optimizer/clauses.h"#include "optimizer/cost.h"#include "optimizer/plancat.h"#include "optimizer/planmain.h"#include "optimizer/predtest.h"#include "optimizer/restrictinfo.h"#include "optimizer/tlist.h"#include "optimizer/var.h"#include "parser/parsetree.h"#include "parser/parse_clause.h"#include "parser/parse_expr.h"#include "utils/lsyscache.h"#include "utils/syscache.h"static Scan *create_scan_plan(PlannerInfo *root, Path *best_path);static List *build_relation_tlist(RelOptInfo *rel);static bool use_physical_tlist(RelOptInfo *rel);static void disuse_physical_tlist(Plan *plan, Path *path);static Join *create_join_plan(PlannerInfo *root, JoinPath *best_path);static Plan *create_append_plan(PlannerInfo *root, AppendPath *best_path);static Result *create_result_plan(PlannerInfo *root, ResultPath *best_path);static Material *create_material_plan(PlannerInfo *root, MaterialPath *best_path);static Plan *create_unique_plan(PlannerInfo *root, UniquePath *best_path);static SeqScan *create_seqscan_plan(PlannerInfo *root, Path *best_path, List *tlist, List *scan_clauses);static IndexScan *create_indexscan_plan(PlannerInfo *root, IndexPath *best_path, List *tlist, List *scan_clauses, List **nonlossy_clauses);static BitmapHeapScan *create_bitmap_scan_plan(PlannerInfo *root, BitmapHeapPath *best_path, List *tlist, List *scan_clauses);static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, List **qual, List **indexqual);static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path, List *tlist, List *scan_clauses);static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root, Path *best_path, List *tlist, List *scan_clauses);static FunctionScan *create_functionscan_plan(PlannerInfo *root, Path *best_path, List *tlist, List *scan_clauses);static NestLoop *create_nestloop_plan(PlannerInfo *root, NestPath *best_path, Plan *outer_plan, Plan *inner_plan);static MergeJoin *create_mergejoin_plan(PlannerInfo *root, MergePath *best_path, Plan *outer_plan, Plan *inner_plan);static HashJoin *create_hashjoin_plan(PlannerInfo *root, HashPath *best_path, Plan *outer_plan, Plan *inner_plan);static void fix_indexqual_references(List *indexquals, IndexPath *index_path, List **fixed_indexquals, List **nonlossy_indexquals, List **indexstrategy, List **indexsubtype);static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass);static List *get_switched_clauses(List *clauses, Relids outerrelids);static void copy_path_costsize(Plan *dest, Path *src);static void copy_plan_costsize(Plan *dest, Plan *src);static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid, Oid indexid, List *indexqual, List *indexqualorig, List *indexstrategy, List *indexsubtype, ScanDirection indexscandir);static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indexid, List *indexqual, List *indexqualorig, List *indexstrategy, List *indexsubtype);static BitmapHeapScan *make_bitmap_heapscan(List *qptlist, List *qpqual, Plan *lefttree, List *bitmapqualorig, Index scanrelid);static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid, List *tideval);static FunctionScan *make_functionscan(List *qptlist, List *qpqual, Index scanrelid);static BitmapAnd *make_bitmap_and(List *bitmapplans);static BitmapOr *make_bitmap_or(List *bitmapplans);static NestLoop *make_nestloop(List *tlist, List *joinclauses, List *otherclauses, Plan *lefttree, Plan *righttree, JoinType jointype);static HashJoin *make_hashjoin(List *tlist, List *joinclauses, List *otherclauses, List *hashclauses, Plan *lefttree, Plan *righttree, JoinType jointype);static Hash *make_hash(Plan *lefttree);static MergeJoin *make_mergejoin(List *tlist, List *joinclauses, List *otherclauses, List *mergeclauses, Plan *lefttree, Plan *righttree, JoinType jointype);static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols, AttrNumber *sortColIdx, Oid *sortOperators);static Sort *make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys);/* * create_plan * Creates the access plan for a query by tracing backwards through the * desired chain of pathnodes, starting at the node 'best_path'. For * every pathnode found: * (1) Create a corresponding plan node containing appropriate id, * target list, and qualification information. * (2) Modify qual clauses of join nodes so that subplan attributes are * referenced using relative values. * (3) Target lists are not modified, but will be in setrefs.c. * * best_path is the best access path * * Returns a Plan tree. */Plan *create_plan(PlannerInfo *root, Path *best_path){ Plan *plan; switch (best_path->pathtype) { case T_SeqScan: case T_IndexScan: case T_BitmapHeapScan: case T_TidScan: case T_SubqueryScan: case T_FunctionScan: plan = (Plan *) create_scan_plan(root, best_path); break; case T_HashJoin: case T_MergeJoin: case T_NestLoop: plan = (Plan *) create_join_plan(root, (JoinPath *) best_path); break; case T_Append: plan = (Plan *) create_append_plan(root, (AppendPath *) best_path); break; case T_Result: plan = (Plan *) create_result_plan(root, (ResultPath *) best_path); break; case T_Material: plan = (Plan *) create_material_plan(root, (MaterialPath *) best_path); break; case T_Unique: plan = (Plan *) create_unique_plan(root, (UniquePath *) best_path); break; default: elog(ERROR, "unrecognized node type: %d", (int) best_path->pathtype); plan = NULL; /* keep compiler quiet */ break; } return plan;}/* * create_scan_plan * Create a scan plan for the parent relation of 'best_path'. * * Returns a Plan node. */static Scan *create_scan_plan(PlannerInfo *root, Path *best_path){ RelOptInfo *rel = best_path->parent; List *tlist; List *scan_clauses; Scan *plan; /* * For table scans, rather than using the relation targetlist (which is * only those Vars actually needed by the query), we prefer to generate a * tlist containing all Vars in order. This will allow the executor to * optimize away projection of the table tuples, if possible. (Note that * planner.c may replace the tlist we generate here, forcing projection to * occur.) */ if (use_physical_tlist(rel)) { tlist = build_physical_tlist(root, rel); /* if fail because of dropped cols, use regular method */ if (tlist == NIL) tlist = build_relation_tlist(rel); } else tlist = build_relation_tlist(rel); /* * Extract the relevant restriction clauses from the parent relation; the * executor must apply all these restrictions during the scan. */ scan_clauses = rel->baserestrictinfo; switch (best_path->pathtype) { case T_SeqScan: plan = (Scan *) create_seqscan_plan(root, best_path, tlist, scan_clauses); break; case T_IndexScan: plan = (Scan *) create_indexscan_plan(root, (IndexPath *) best_path, tlist, scan_clauses, NULL); break; case T_BitmapHeapScan: plan = (Scan *) create_bitmap_scan_plan(root, (BitmapHeapPath *) best_path, tlist, scan_clauses); break; case T_TidScan: plan = (Scan *) create_tidscan_plan(root, (TidPath *) best_path, tlist, scan_clauses); break; case T_SubqueryScan: plan = (Scan *) create_subqueryscan_plan(root, best_path, tlist, scan_clauses); break; case T_FunctionScan: plan = (Scan *) create_functionscan_plan(root, best_path, tlist, scan_clauses); break; default: elog(ERROR, "unrecognized node type: %d", (int) best_path->pathtype); plan = NULL; /* keep compiler quiet */ break; } return plan;}/* * Build a target list (ie, a list of TargetEntry) for a relation. */static List *build_relation_tlist(RelOptInfo *rel){ List *tlist = NIL; int resno = 1; ListCell *v; foreach(v, rel->reltargetlist) { /* Do we really need to copy here? Not sure */ Var *var = (Var *) copyObject(lfirst(v)); tlist = lappend(tlist, makeTargetEntry((Expr *) var, resno, NULL, false)); resno++; } return tlist;}/* * use_physical_tlist * Decide whether to use a tlist matching relation structure, * rather than only those Vars actually referenced. */static booluse_physical_tlist(RelOptInfo *rel){ int i; /* * We can do this for real relation scans, subquery scans, and function * scans (but not for, eg, joins). */ if (rel->rtekind != RTE_RELATION && rel->rtekind != RTE_SUBQUERY && rel->rtekind != RTE_FUNCTION) return false; /* * Can't do it with inheritance cases either (mainly because Append * doesn't project). */ if (rel->reloptkind != RELOPT_BASEREL) return false; /* * Can't do it if any system columns or whole-row Vars are requested, * either. (This could possibly be fixed but would take some fragile * assumptions in setrefs.c, I think.) */ for (i = rel->min_attr; i <= 0; i++) { if (!bms_is_empty(rel->attr_needed[i - rel->min_attr])) return false; } return true;}/* * disuse_physical_tlist * Switch a plan node back to emitting only Vars actually referenced. * * If the plan node immediately above a scan would prefer to get only * needed Vars and not a physical tlist, it must call this routine to * undo the decision made by use_physical_tlist(). Currently, Hash, Sort, * and Material nodes want this, so they don't have to store useless columns. */static voiddisuse_physical_tlist(Plan *plan, Path *path){ /* Only need to undo it for path types handled by create_scan_plan() */ switch (path->pathtype) { case T_SeqScan: case T_IndexScan: case T_BitmapHeapScan: case T_TidScan: case T_SubqueryScan: case T_FunctionScan: plan->targetlist = build_relation_tlist(path->parent); break; default: break; }}/* * create_join_plan * Create a join plan for 'best_path' and (recursively) plans for its * inner and outer paths. * * Returns a Plan node. */static Join *create_join_plan(PlannerInfo *root, JoinPath *best_path){ Plan *outer_plan; Plan *inner_plan; Join *plan; outer_plan = create_plan(root, best_path->outerjoinpath); inner_plan = create_plan(root, best_path->innerjoinpath); switch (best_path->path.pathtype) { case T_MergeJoin: plan = (Join *) create_mergejoin_plan(root, (MergePath *) best_path, outer_plan, inner_plan); break; case T_HashJoin: plan = (Join *) create_hashjoin_plan(root, (HashPath *) best_path, outer_plan, inner_plan); break; case T_NestLoop: plan = (Join *) create_nestloop_plan(root, (NestPath *) best_path, outer_plan, inner_plan); break; default: elog(ERROR, "unrecognized node type: %d", (int) best_path->path.pathtype); plan = NULL; /* keep compiler quiet */ break; }#ifdef NOT_USED /* * * Expensive function pullups may have pulled local predicates * into * this path node. Put them in the qpqual of the plan node. * JMH, * 6/15/92 */ if (get_loc_restrictinfo(best_path) != NIL) set_qpqual((Plan) plan, list_concat(get_qpqual((Plan) plan), get_actual_clauses(get_loc_restrictinfo(best_path))));#endif return plan;}/* * create_append_plan * Create an Append plan for 'best_path' and (recursively) plans * for its subpaths. * * Returns a Plan node. */static Plan *create_append_plan(PlannerInfo *root, AppendPath *best_path){ Append *plan; List *tlist = build_relation_tlist(best_path->path.parent); List *subplans = NIL; ListCell *subpaths; /* * It is possible for the subplans list to contain only one entry, or even * no entries. Handle these cases specially. * * XXX ideally, if there's just one entry, we'd not bother to generate an * Append node but just return the single child. At the moment this does * not work because the varno of the child scan plan won't match the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -