📄 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-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.157.2.3 2004/02/29 17:36:48 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/paths.h"#include "optimizer/plancat.h"#include "optimizer/planmain.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(Query *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(Query *root, JoinPath *best_path);static Append *create_append_plan(Query *root, AppendPath *best_path);static Result *create_result_plan(Query *root, ResultPath *best_path);static Material *create_material_plan(Query *root, MaterialPath *best_path);static Plan *create_unique_plan(Query *root, UniquePath *best_path);static SeqScan *create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses);static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path, List *tlist, List *scan_clauses);static TidScan *create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses);static SubqueryScan *create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses);static FunctionScan *create_functionscan_plan(Path *best_path, List *tlist, List *scan_clauses);static NestLoop *create_nestloop_plan(Query *root, NestPath *best_path, Plan *outer_plan, Plan *inner_plan);static MergeJoin *create_mergejoin_plan(Query *root, MergePath *best_path, Plan *outer_plan, Plan *inner_plan);static HashJoin *create_hashjoin_plan(Query *root, HashPath *best_path, Plan *outer_plan, Plan *inner_plan);static void fix_indxqual_references(List *indexquals, IndexPath *index_path, List **fixed_indexquals, List **recheck_indexquals);static void fix_indxqual_sublist(List *indexqual, Relids baserelids, int baserelid, IndexOptInfo *index, List **fixed_quals, List **recheck_quals);static Node *fix_indxqual_operand(Node *node, int baserelid, IndexOptInfo *index, Oid *opclass);static List *get_switched_clauses(List *clauses, Relids outerrelids);static List *order_qual_clauses(Query *root, List *clauses);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, List *indxid, List *indxqual, List *indxqualorig, ScanDirection indexscandir);static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid, List *tideval);static FunctionScan *make_functionscan(List *qptlist, List *qpqual, Index scanrelid);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(List *tlist, List *hashkeys, Plan *lefttree);static MergeJoin *make_mergejoin(List *tlist, List *joinclauses, List *otherclauses, List *mergeclauses, Plan *lefttree, Plan *righttree, JoinType jointype);static Sort *make_sort(Query *root, List *tlist, Plan *lefttree, int numCols, AttrNumber *sortColIdx, Oid *sortOperators);static Sort *make_sort_from_pathkeys(Query *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(Query *root, Path *best_path){ Plan *plan; switch (best_path->pathtype) { case T_IndexScan: case T_SeqScan: 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; }#ifdef NOT_USED /* fix xfunc */ /* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */ if (XfuncMode != XFUNC_OFF) { set_qpqual((Plan) plan, lisp_qsort(get_qpqual((Plan) plan), xfunc_clause_compare)); if (XfuncMode != XFUNC_NOR) /* sort the disjuncts within each clause by cost -- JMH 3/4/92 */ xfunc_disjunct_sort(plan->qpqual); }#endif 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(Query *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 = get_actual_clauses(rel->baserestrictinfo); /* Sort clauses into best execution order */ scan_clauses = order_qual_clauses(root, scan_clauses); switch (best_path->pathtype) { case T_SeqScan: plan = (Scan *) create_seqscan_plan(best_path, tlist, scan_clauses); break; case T_IndexScan: plan = (Scan *) create_indexscan_plan(root, (IndexPath *) best_path, tlist, scan_clauses); break; case T_TidScan: plan = (Scan *) create_tidscan_plan((TidPath *) best_path, tlist, scan_clauses); break; case T_SubqueryScan: plan = (Scan *) create_subqueryscan_plan(best_path, tlist, scan_clauses); break; case T_FunctionScan: plan = (Scan *) create_functionscan_plan(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){ FastList tlist; int resdomno = 1; List *v; FastListInit(&tlist); foreach(v, FastListValue(&rel->reltargetlist)) { /* Do we really need to copy here? Not sure */ Var *var = (Var *) copyObject(lfirst(v)); FastAppend(&tlist, create_tl_element(var, resdomno)); resdomno++; } return FastListValue(&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; /* * Currently, can't do this for subquery or function scans. (This is * mainly because we don't have an equivalent of build_physical_tlist * for them; worth adding?) */ if (rel->rtekind != RTE_RELATION) 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 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_IndexScan: case T_SeqScan: 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(Query *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, nconc(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 Append *create_append_plan(Query *root, AppendPath *best_path){ Append *plan; List *tlist = build_relation_tlist(best_path->path.parent); List *subplans = NIL; List *subpaths; foreach(subpaths, best_path->subpaths) { Path *subpath = (Path *) lfirst(subpaths); subplans = lappend(subplans, create_plan(root, subpath)); } plan = make_append(subplans, false, tlist); return plan;}/* * create_result_plan * Create a Result plan for 'best_path' and (recursively) plans * for its subpaths. * * Returns a Plan node. */static Result *create_result_plan(Query *root, ResultPath *best_path){ Result *plan; List *tlist; List *constclauses; Plan *subplan; if (best_path->path.parent) tlist = build_relation_tlist(best_path->path.parent); else tlist = NIL; /* will be filled in later */ if (best_path->subpath) subplan = create_plan(root, best_path->subpath); else subplan = NULL; constclauses = order_qual_clauses(root, best_path->constantqual);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -