1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-02 09:02:37 +03:00

Further planner/optimizer cleanups. Move all set_tlist_references

and fix_opids processing to a single recursive pass over the plan tree
executed at the very tail end of planning, rather than haphazardly here
and there at different places.  Now that tlist Vars do not get modified
until the very end, it's possible to get rid of the klugy var_equal and
match_varid partial-matching routines, and just use plain equal()
throughout the optimizer.  This is a step towards allowing merge and
hash joins to be done on expressions instead of only Vars ...
This commit is contained in:
Tom Lane
1999-08-22 20:15:04 +00:00
parent db436adf76
commit 78114cd4d4
24 changed files with 662 additions and 963 deletions

View File

@ -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)