diff options
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 128 |
1 files changed, 87 insertions, 41 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index d1f756fc7c1..ae1e2d3266b 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1,13 +1,15 @@ /*------------------------------------------------------------------------- * * createplan.c - * Routines to create the desired plan for processing a query + * Routines to create the desired plan for processing a query. + * Planning is complete, we just need to convert the selected + * Path into a Plan. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.74 1999/08/21 03:49:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.75 1999/08/22 20:14:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -70,13 +72,13 @@ static void copy_costsize(Plan *dest, Plan *src); * every pathnode found: * (1) Create a corresponding plan node containing appropriate id, * target list, and qualification information. - * (2) Modify ALL clauses so that attributes are referenced using - * relative values. - * (3) Target lists are not modified, but will be in another routine. + * (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 the optimal(?) access plan. + * Returns the access plan. */ Plan * create_plan(Path *best_path) @@ -90,7 +92,7 @@ create_plan(Path *best_path) int tuples; parent_rel = best_path->parent; - tlist = get_actual_tlist(parent_rel->targetlist); + tlist = parent_rel->targetlist; size = parent_rel->size; width = parent_rel->width; pages = parent_rel->pages; @@ -152,9 +154,8 @@ create_scan_node(Path *best_path, List *tlist) /* * Extract the relevant restriction clauses from the parent relation; * the executor must apply all these restrictions during the scan. - * Fix regproc ids in the restriction clauses. */ - scan_clauses = fix_opids(get_actual_clauses(best_path->parent->restrictinfo)); + scan_clauses = get_actual_clauses(best_path->parent->restrictinfo); switch (best_path->pathtype) { @@ -235,7 +236,6 @@ create_join_node(JoinPath *best_path, List *tlist) inner_tlist); break; default: - /* do nothing */ elog(ERROR, "create_join_node: unknown node type", best_path->path.pathtype); } @@ -249,8 +249,7 @@ create_join_node(JoinPath *best_path, List *tlist) if (get_loc_restrictinfo(best_path) != NIL) set_qpqual((Plan) retval, nconc(get_qpqual((Plan) retval), - fix_opids(get_actual_clauses - (get_loc_restrictinfo(best_path))))); + get_actual_clauses(get_loc_restrictinfo(best_path)))); #endif return retval; @@ -282,8 +281,7 @@ create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses) scan_node = make_seqscan(tlist, scan_clauses, - scan_relid, - (Plan *) NULL); + scan_relid); scan_node->plan.cost = best_path->path_cost; @@ -386,17 +384,10 @@ create_indexscan_node(IndexPath *best_path, qpqual = NIL; /* The executor needs a copy with the indexkey on the left of each clause - * and with index attrs substituted for table ones. + * and with index attr numbers substituted for table ones. */ fixed_indxqual = fix_indxqual_references(indxqual, best_path); - /* - * Fix opids in the completed indxquals. - * XXX this ought to only happen at final exit from the planner... - */ - indxqual = fix_opids(indxqual); - fixed_indxqual = fix_opids(fixed_indxqual); - scan_node = make_indexscan(tlist, qpqual, lfirsti(best_path->path.parent->relids), @@ -413,6 +404,21 @@ create_indexscan_node(IndexPath *best_path, * * JOIN METHODS * + * A general note about join_references() processing in these routines: + * once we have changed a Var node to refer to a subplan output rather than + * the original relation, it is no longer equal() to an unmodified Var node + * for the same var. So, we cannot easily compare reference-adjusted qual + * clauses to clauses that have not been adjusted. Fortunately, that + * doesn't seem to be necessary; all the decisions are made before we do + * the reference adjustments. + * + * A cleaner solution would be to not call join_references() here at all, + * but leave it for setrefs.c to do at the end of plan tree construction. + * But that would make switch_outer() much more complicated, and some care + * would be needed to get setrefs.c to do the right thing with nestloop + * inner indexscan quals. So, we do subplan reference adjustment here for + * quals of join nodes (and *only* for quals of join nodes). + * *****************************************************************************/ static NestLoop * @@ -432,7 +438,7 @@ create_nestloop_node(NestPath *best_path, * An index is being used to reduce the number of tuples scanned * in the inner relation. If there are join clauses being used * with the index, we must update their outer-rel var nodes to - * refer to the outer relation. + * refer to the outer side of the join. * * We can also remove those join clauses from the list of clauses * that have to be checked as qpquals at the join node, but only @@ -442,7 +448,12 @@ create_nestloop_node(NestPath *best_path, * Note: if the index is lossy, the same clauses may also be getting * checked as qpquals in the indexscan. We can still remove them * from the nestloop's qpquals, but we gotta update the outer-rel - * vars in the indexscan's qpquals too... + * vars in the indexscan's qpquals too. + * + * Note: we can safely do set_difference() against my clauses and + * join_references() because the innerscan is a primitive plan, + * and therefore has not itself done join_references renumbering + * of the vars in its quals. */ IndexScan *innerscan = (IndexScan *) inner_node; List *indxqualorig = innerscan->indxqualorig; @@ -450,6 +461,8 @@ create_nestloop_node(NestPath *best_path, /* No work needed if indxqual refers only to its own relation... */ if (NumRelids((Node *) indxqualorig) > 1) { + Index innerrel = innerscan->scan.scanrelid; + /* Remove redundant tests from my clauses, if possible. * Note we must compare against indxqualorig not the "fixed" * indxqual (which has index attnos instead of relation attnos, @@ -461,20 +474,28 @@ create_nestloop_node(NestPath *best_path, /* only refs to outer vars get changed in the inner indexqual */ innerscan->indxqualorig = join_references(indxqualorig, outer_tlist, - NIL); + NIL, + innerrel); innerscan->indxqual = join_references(innerscan->indxqual, outer_tlist, - NIL); + NIL, + innerrel); /* fix the inner qpqual too, if it has join clauses */ if (NumRelids((Node *) inner_node->qual) > 1) inner_node->qual = join_references(inner_node->qual, outer_tlist, - NIL); + NIL, + innerrel); } } else if (IsA_Join(inner_node)) { - /* Materialize the inner join for speed reasons */ + /* + * Materialize the inner join for speed reasons. + * + * XXX It is probably *not* always fastest to materialize an inner + * join --- how can we estimate whether this is a good thing to do? + */ inner_node = (Plan *) make_noname(inner_tlist, NIL, inner_node); @@ -483,7 +504,8 @@ create_nestloop_node(NestPath *best_path, join_node = make_nestloop(tlist, join_references(clauses, outer_tlist, - inner_tlist), + inner_tlist, + (Index) 0), outer_node, inner_node); @@ -513,7 +535,8 @@ create_mergejoin_node(MergePath *best_path, qpqual = join_references(set_difference(clauses, best_path->path_mergeclauses), outer_tlist, - inner_tlist); + inner_tlist, + (Index) 0); /* * Now set the references in the mergeclauses and rearrange them so @@ -521,7 +544,8 @@ create_mergejoin_node(MergePath *best_path, */ mergeclauses = switch_outer(join_references(best_path->path_mergeclauses, outer_tlist, - inner_tlist)); + inner_tlist, + (Index) 0)); /* * Create explicit sort nodes for the outer and inner join paths if @@ -578,7 +602,8 @@ create_hashjoin_node(HashPath *best_path, qpqual = join_references(set_difference(clauses, best_path->path_hashclauses), outer_tlist, - inner_tlist); + inner_tlist, + (Index) 0); /* * Now set the references in the hashclauses and rearrange them so @@ -586,7 +611,8 @@ create_hashjoin_node(HashPath *best_path, */ hashclauses = switch_outer(join_references(best_path->path_hashclauses, outer_tlist, - inner_tlist)); + inner_tlist, + (Index) 0)); /* Now the righthand op of the sole hashclause is the inner hash key. */ innerhashkey = get_rightop(lfirst(hashclauses)); @@ -839,7 +865,7 @@ set_tlist_sort_info(List *tlist, List *pathkeys) { pathkey = lfirst(j); Assert(IsA(pathkey, PathKeyItem)); - resdom = tlist_member((Var *) pathkey->key, tlist); + resdom = tlist_member(pathkey->key, tlist); if (resdom) break; } @@ -939,17 +965,16 @@ make_noname(List *tlist, SeqScan * make_seqscan(List *qptlist, List *qpqual, - Index scanrelid, - Plan *lefttree) + Index scanrelid) { SeqScan *node = makeNode(SeqScan); Plan *plan = &node->plan; - copy_costsize(plan, lefttree); + copy_costsize(plan, NULL); plan->state = (EState *) NULL; plan->targetlist = qptlist; plan->qual = qpqual; - plan->lefttree = lefttree; + plan->lefttree = NULL; plan->righttree = NULL; node->scanrelid = scanrelid; node->scanstate = (CommonScanState *) NULL; @@ -1158,9 +1183,7 @@ make_group(List *tlist, } /* - * A unique node always has a SORT node in the lefttree. - * - * the uniqueAttr argument must be a null-terminated string, + * The uniqueAttr argument must be a null-terminated string, * either the name of the attribute to select unique on * or "*" */ @@ -1186,6 +1209,29 @@ make_unique(List *tlist, Plan *lefttree, char *uniqueAttr) return node; } +Result * +make_result(List *tlist, + Node *resconstantqual, + Plan *subplan) +{ + Result *node = makeNode(Result); + Plan *plan = &node->plan; + +#ifdef NOT_USED + tlist = generate_fjoin(tlist); +#endif + copy_costsize(plan, subplan); + plan->state = (EState *) NULL; + plan->targetlist = tlist; + plan->qual = NIL; + plan->lefttree = subplan; + plan->righttree = NULL; + node->resconstantqual = resconstantqual; + node->resstate = NULL; + + return node; +} + #ifdef NOT_USED List * generate_fjoin(List *tlist) |