aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan')
-rw-r--r--src/backend/optimizer/plan/createplan.c300
-rw-r--r--src/backend/optimizer/plan/initsplan.c74
-rw-r--r--src/backend/optimizer/plan/planmain.c14
3 files changed, 222 insertions, 166 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 6fda28aa747..fc476fe267d 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.77 1999/11/23 20:06:57 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.78 2000/01/09 00:26:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,6 +22,7 @@
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/internal.h"
+#include "optimizer/paths.h"
#include "optimizer/planmain.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
@@ -31,12 +32,12 @@
static List *switch_outer(List *clauses);
static int set_tlist_sort_info(List *tlist, List *pathkeys);
-static Scan *create_scan_node(Path *best_path, List *tlist);
-static Join *create_join_node(JoinPath *best_path, List *tlist);
+static Scan *create_scan_node(Query *root, Path *best_path, List *tlist);
+static Join *create_join_node(Query *root, JoinPath *best_path, List *tlist);
static SeqScan *create_seqscan_node(Path *best_path, List *tlist,
List *scan_clauses);
-static IndexScan *create_indexscan_node(IndexPath *best_path, List *tlist,
- List *scan_clauses);
+static IndexScan *create_indexscan_node(Query *root, IndexPath *best_path,
+ List *tlist, List *scan_clauses);
static TidScan *create_tidscan_node(TidPath *best_path, List *tlist,
List *scan_clauses);
static NestLoop *create_nestloop_node(NestPath *best_path, List *tlist,
@@ -49,10 +50,11 @@ static HashJoin *create_hashjoin_node(HashPath *best_path, List *tlist,
List *clauses, Plan *outer_node, List *outer_tlist,
Plan *inner_node, List *inner_tlist);
static List *fix_indxqual_references(List *indexquals, IndexPath *index_path);
-static List *fix_indxqual_sublist(List *indexqual, IndexPath *index_path,
- Form_pg_index index);
-static Node *fix_indxqual_operand(Node *node, IndexPath *index_path,
+static List *fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
Form_pg_index index);
+static Node *fix_indxqual_operand(Node *node, int baserelid,
+ Form_pg_index index,
+ Oid *opclass);
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
List *indxid, List *indxqual, List *indxqualorig);
static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
@@ -66,7 +68,8 @@ static MergeJoin *make_mergejoin(List *tlist, List *qpqual,
List *mergeclauses, Plan *righttree, Plan *lefttree);
static Material *make_material(List *tlist, Oid nonameid, Plan *lefttree,
int keycount);
-static void copy_costsize(Plan *dest, Plan *src);
+static void copy_path_costsize(Plan *dest, Path *src);
+static void copy_plan_costsize(Plan *dest, Plan *src);
/*
* create_plan
@@ -84,46 +87,31 @@ static void copy_costsize(Plan *dest, Plan *src);
* Returns the access plan.
*/
Plan *
-create_plan(Path *best_path)
+create_plan(Query *root, Path *best_path)
{
- List *tlist;
+ List *tlist = best_path->parent->targetlist;
Plan *plan_node = (Plan *) NULL;
- RelOptInfo *parent_rel;
- int size;
- int width;
- int pages;
- int tuples;
-
- parent_rel = best_path->parent;
- tlist = parent_rel->targetlist;
- size = parent_rel->size;
- width = parent_rel->width;
- pages = parent_rel->pages;
- tuples = parent_rel->tuples;
switch (best_path->pathtype)
{
case T_IndexScan:
case T_SeqScan:
case T_TidScan:
- plan_node = (Plan *) create_scan_node(best_path, tlist);
+ plan_node = (Plan *) create_scan_node(root, best_path, tlist);
break;
case T_HashJoin:
case T_MergeJoin:
case T_NestLoop:
- plan_node = (Plan *) create_join_node((JoinPath *) best_path, tlist);
+ plan_node = (Plan *) create_join_node(root,
+ (JoinPath *) best_path,
+ tlist);
break;
default:
- /* do nothing */
+ elog(ERROR, "create_plan: unknown pathtype %d",
+ best_path->pathtype);
break;
}
- plan_node->plan_size = size;
- plan_node->plan_width = width;
- if (pages == 0)
- pages = 1;
- plan_node->plan_tupperpage = tuples / pages;
-
#ifdef NOT_USED /* fix xfunc */
/* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */
if (XfuncMode != XFUNC_OFF)
@@ -149,9 +137,8 @@ create_plan(Path *best_path)
* Returns the scan node.
*/
static Scan *
-create_scan_node(Path *best_path, List *tlist)
+create_scan_node(Query *root, Path *best_path, List *tlist)
{
-
Scan *node = NULL;
List *scan_clauses;
@@ -168,7 +155,8 @@ create_scan_node(Path *best_path, List *tlist)
break;
case T_IndexScan:
- node = (Scan *) create_indexscan_node((IndexPath *) best_path,
+ node = (Scan *) create_indexscan_node(root,
+ (IndexPath *) best_path,
tlist,
scan_clauses);
break;
@@ -199,7 +187,7 @@ create_scan_node(Path *best_path, List *tlist)
* Returns the join node.
*/
static Join *
-create_join_node(JoinPath *best_path, List *tlist)
+create_join_node(Query *root, JoinPath *best_path, List *tlist)
{
Plan *outer_node;
List *outer_tlist;
@@ -208,13 +196,13 @@ create_join_node(JoinPath *best_path, List *tlist)
List *clauses;
Join *retval = NULL;
- outer_node = create_plan((Path *) best_path->outerjoinpath);
+ outer_node = create_plan(root, best_path->outerjoinpath);
outer_tlist = outer_node->targetlist;
- inner_node = create_plan((Path *) best_path->innerjoinpath);
+ inner_node = create_plan(root, best_path->innerjoinpath);
inner_tlist = inner_node->targetlist;
- clauses = get_actual_clauses(best_path->pathinfo);
+ clauses = get_actual_clauses(best_path->path.parent->restrictinfo);
switch (best_path->path.pathtype)
{
@@ -280,20 +268,19 @@ create_join_node(JoinPath *best_path, List *tlist)
static SeqScan *
create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
{
- SeqScan *scan_node = (SeqScan *) NULL;
- Index scan_relid = -1;
- List *temp;
+ SeqScan *scan_node;
+ Index scan_relid;
- temp = best_path->parent->relids;
/* there should be exactly one base rel involved... */
- Assert(length(temp) == 1);
- scan_relid = (Index) lfirsti(temp);
+ Assert(length(best_path->parent->relids) == 1);
+
+ scan_relid = (Index) lfirsti(best_path->parent->relids);
scan_node = make_seqscan(tlist,
scan_clauses,
scan_relid);
- scan_node->plan.cost = best_path->path_cost;
+ copy_path_costsize(&scan_node->plan, best_path);
return scan_node;
}
@@ -312,7 +299,8 @@ create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
* scan.
*/
static IndexScan *
-create_indexscan_node(IndexPath *best_path,
+create_indexscan_node(Query *root,
+ IndexPath *best_path,
List *tlist,
List *scan_clauses)
{
@@ -322,11 +310,12 @@ create_indexscan_node(IndexPath *best_path,
List *ixid;
IndexScan *scan_node;
bool lossy = false;
+ double plan_rows;
/* there should be exactly one base rel involved... */
Assert(length(best_path->path.parent->relids) == 1);
- /* check and see if any of the indices are lossy */
+ /* check to see if any of the indices are lossy */
foreach(ixid, best_path->indexid)
{
HeapTuple indexTuple;
@@ -354,44 +343,72 @@ create_indexscan_node(IndexPath *best_path,
*
* Since the indexquals were generated from the restriction clauses
* given by scan_clauses, there will normally be some duplications
- * between the lists. Get rid of the duplicates, then add back if lossy.
+ * between the lists. We get rid of the duplicates, then add back
+ * if lossy.
+ *
+ * If this indexscan is a nestloop-join inner indexscan (as indicated
+ * by having nonempty joinrelids), then it uses indexqual conditions
+ * that are not part of the relation's restriction clauses. The rows
+ * estimate stored in the relation's RelOptInfo will be an overestimate
+ * because it did not take these extra conditions into account. So,
+ * in this case we recompute the selectivity of the whole scan ---
+ * considering both indexqual and qpqual --- rather than using the
+ * RelOptInfo's rows value. Since clausesel.c assumes it's working on
+ * minimized (no duplicates) expressions, we have to do that while we
+ * have the duplicate-free qpqual available.
*/
+ plan_rows = best_path->path.parent->rows; /* OK unless nestloop inner */
+
if (length(indxqual) > 1)
{
/*
* Build an expression representation of the indexqual, expanding
* the implicit OR and AND semantics of the first- and second-level
- * lists. XXX Is it really necessary to do a deep copy here?
+ * lists.
*/
List *orclauses = NIL;
List *orclause;
Expr *indxqual_expr;
foreach(orclause, indxqual)
- {
orclauses = lappend(orclauses,
- make_ands_explicit((List *) copyObject(lfirst(orclause))));
- }
+ make_ands_explicit(lfirst(orclause)));
indxqual_expr = make_orclause(orclauses);
- /* this set_difference is almost certainly a waste of time... */
qpqual = set_difference(scan_clauses,
lcons(indxqual_expr, NIL));
+ if (best_path->joinrelids)
+ {
+ /* recompute output row estimate using all available quals */
+ plan_rows = best_path->path.parent->tuples *
+ clauselist_selec(root, lcons(indxqual_expr, qpqual));
+ }
+
if (lossy)
- qpqual = lappend(qpqual, indxqual_expr);
+ qpqual = lappend(qpqual, copyObject(indxqual_expr));
}
else if (indxqual != NIL)
{
/* Here, we can simply treat the first sublist as an independent
* set of qual expressions, since there is no top-level OR behavior.
*/
- qpqual = set_difference(scan_clauses, lfirst(indxqual));
+ List *indxqual_list = lfirst(indxqual);
+
+ qpqual = set_difference(scan_clauses, indxqual_list);
+
+ if (best_path->joinrelids)
+ {
+ /* recompute output row estimate using all available quals */
+ plan_rows = best_path->path.parent->tuples *
+ clauselist_selec(root, nconc(listCopy(indxqual_list), qpqual));
+ }
+
if (lossy)
- qpqual = nconc(qpqual, (List *) copyObject(lfirst(indxqual)));
+ qpqual = nconc(qpqual, (List *) copyObject(indxqual_list));
}
else
- qpqual = NIL;
+ qpqual = scan_clauses;
/* The executor needs a copy with the indexkey on the left of each clause
* and with index attr numbers substituted for table ones.
@@ -405,7 +422,8 @@ create_indexscan_node(IndexPath *best_path,
fixed_indxqual,
indxqual);
- scan_node->scan.plan.cost = best_path->path.path_cost;
+ copy_path_costsize(&scan_node->scan.plan, &best_path->path);
+ scan_node->scan.plan.plan_rows = plan_rows;
return scan_node;
}
@@ -416,11 +434,11 @@ make_tidscan(List *qptlist,
Index scanrelid,
List *tideval)
{
- TidScan *node = makeNode(TidScan);
+ TidScan *node = makeNode(TidScan);
Plan *plan = &node->scan.plan;
plan->cost = 0;
- plan->plan_size = 0;
+ plan->plan_rows = 0;
plan->plan_width = 0;
plan->state = (EState *) NULL;
plan->targetlist = qptlist;
@@ -428,7 +446,7 @@ make_tidscan(List *qptlist,
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
- node->tideval = copyObject(tideval);
+ node->tideval = copyObject(tideval); /* XXX do we really need a copy? */
node->needRescan = false;
node->scan.scanstate = (CommonScanState *) NULL;
@@ -443,25 +461,23 @@ make_tidscan(List *qptlist,
static TidScan *
create_tidscan_node(TidPath *best_path, List *tlist, List *scan_clauses)
{
- TidScan *scan_node = (TidScan *) NULL;
- Index scan_relid = -1;
- List *temp;
-
- temp = best_path->path.parent->relids;
- if (temp == NULL)
- elog(ERROR, "scanrelid is empty");
- else if (length(temp) != 1)
- return scan_node;
- else
- scan_relid = (Index) lfirsti(temp);
+ TidScan *scan_node;
+ Index scan_relid;
+
+ /* there should be exactly one base rel involved... */
+ Assert(length(best_path->path.parent->relids) == 1);
+
+ scan_relid = (Index) lfirsti(best_path->path.parent->relids);
+
scan_node = make_tidscan(tlist,
- scan_clauses,
- scan_relid,
- best_path->tideval);
+ scan_clauses,
+ scan_relid,
+ best_path->tideval);
if (best_path->unjoined_relids)
scan_node->needRescan = true;
- scan_node->scan.plan.cost = best_path->path.path_cost;
+
+ copy_path_costsize(&scan_node->scan.plan, &best_path->path);
return scan_node;
}
@@ -581,7 +597,7 @@ create_nestloop_node(NestPath *best_path,
outer_node,
inner_node);
- join_node->join.cost = best_path->path.path_cost;
+ copy_path_costsize(&join_node->join, &best_path->path);
return join_node;
}
@@ -639,7 +655,7 @@ create_mergejoin_node(MergePath *best_path,
inner_node,
outer_node);
- join_node->join.cost = best_path->jpath.path.path_cost;
+ copy_path_costsize(&join_node->join, &best_path->jpath.path);
return join_node;
}
@@ -699,7 +715,7 @@ create_hashjoin_node(HashPath *best_path,
outer_node,
(Plan *) hash_node);
- join_node->join.cost = best_path->jpath.path.path_cost;
+ copy_path_costsize(&join_node->join, &best_path->jpath.path);
return join_node;
}
@@ -713,10 +729,18 @@ create_hashjoin_node(HashPath *best_path,
/*
* fix_indxqual_references
- * Adjust indexqual clauses to refer to index attributes instead of the
- * attributes of the original relation. Also, commute clauses if needed
- * to put the indexkey on the left. (Someday the executor might not need
- * that, but for now it does.)
+ * Adjust indexqual clauses to the form the executor's indexqual
+ * machinery needs.
+ *
+ * We have three tasks here:
+ * * Var nodes representing index keys must have varattno equal to the
+ * index's attribute number, not the attribute number in the original rel.
+ * * indxpath.c may have selected an index that is binary-compatible with
+ * the actual expression operator, but not the same; we must replace the
+ * expression's operator with the binary-compatible equivalent operator
+ * that the index will recognize.
+ * * If the index key is on the right, commute the clause to put it on the
+ * left. (Someday the executor might not need this, but for now it does.)
*
* This code used to be entirely bogus for multi-index scans. Now it keeps
* track of which index applies to each subgroup of index qual clauses...
@@ -729,6 +753,7 @@ static List *
fix_indxqual_references(List *indexquals, IndexPath *index_path)
{
List *fixed_quals = NIL;
+ int baserelid = lfirsti(index_path->path.parent->relids);
List *indexids = index_path->indexid;
List *i;
@@ -737,19 +762,31 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
List *indexqual = lfirst(i);
Oid indexid = lfirsti(indexids);
HeapTuple indexTuple;
+ Oid relam;
Form_pg_index index;
+ /* Get the relam from the index's pg_class entry */
+ indexTuple = SearchSysCacheTuple(RELOID,
+ ObjectIdGetDatum(indexid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(indexTuple))
+ elog(ERROR, "fix_indxqual_references: index %u not found in pg_class",
+ indexid);
+ relam = ((Form_pg_class) GETSTRUCT(indexTuple))->relam;
+
+ /* Need the index's pg_index entry for other stuff */
indexTuple = SearchSysCacheTuple(INDEXRELID,
ObjectIdGetDatum(indexid),
0, 0, 0);
if (!HeapTupleIsValid(indexTuple))
- elog(ERROR, "fix_indxqual_references: index %u not found",
+ elog(ERROR, "fix_indxqual_references: index %u not found in pg_index",
indexid);
index = (Form_pg_index) GETSTRUCT(indexTuple);
fixed_quals = lappend(fixed_quals,
fix_indxqual_sublist(indexqual,
- index_path,
+ baserelid,
+ relam,
index));
indexids = lnext(indexids);
@@ -761,11 +798,11 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
* Fix the sublist of indexquals to be used in a particular scan.
*
* For each qual clause, commute if needed to put the indexkey operand on the
- * left, and then change its varno. We do not need to change the other side
- * of the clause.
+ * left, and then change its varno. (We do not need to change the other side
+ * of the clause.) Also change the operator if necessary.
*/
static List *
-fix_indxqual_sublist(List *indexqual, IndexPath *index_path,
+fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
Form_pg_index index)
{
List *fixed_qual = NIL;
@@ -779,6 +816,8 @@ fix_indxqual_sublist(List *indexqual, IndexPath *index_path,
Datum constval;
int flag;
Expr *newclause;
+ Oid opclass,
+ newopno;
if (!is_opclause((Node *) clause) ||
length(clause->args) != 2)
@@ -788,8 +827,7 @@ fix_indxqual_sublist(List *indexqual, IndexPath *index_path,
*
* get_relattval sets flag&SEL_RIGHT if the indexkey is on the LEFT.
*/
- get_relattval((Node *) clause,
- lfirsti(index_path->path.parent->relids),
+ get_relattval((Node *) clause, baserelid,
&relid, &attno, &constval, &flag);
/* Copy enough structure to allow commuting and replacing an operand
@@ -802,10 +840,27 @@ fix_indxqual_sublist(List *indexqual, IndexPath *index_path,
if ((flag & SEL_RIGHT) == 0)
CommuteClause(newclause);
- /* Now, change the indexkey operand as needed. */
+ /* Now, determine which index attribute this is,
+ * change the indexkey operand as needed,
+ * and get the index opclass.
+ */
lfirst(newclause->args) = fix_indxqual_operand(lfirst(newclause->args),
- index_path,
- index);
+ baserelid,
+ index,
+ &opclass);
+
+ /* Substitute the appropriate operator if the expression operator
+ * is merely binary-compatible with the index. This shouldn't fail,
+ * since indxpath.c found it before...
+ */
+ newopno = indexable_operator(newclause, opclass, relam, true);
+ if (newopno == InvalidOid)
+ elog(ERROR, "fix_indxqual_sublist: failed to find substitute op");
+ if (newopno != ((Oper *) newclause->oper)->opno)
+ {
+ newclause->oper = (Node *) copyObject(newclause->oper);
+ ((Oper *) newclause->oper)->opno = newopno;
+ }
fixed_qual = lappend(fixed_qual, newclause);
}
@@ -813,12 +868,12 @@ fix_indxqual_sublist(List *indexqual, IndexPath *index_path,
}
static Node *
-fix_indxqual_operand(Node *node, IndexPath *index_path,
- Form_pg_index index)
+fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index,
+ Oid *opclass)
{
if (IsA(node, Var))
{
- if (((Var *) node)->varno == lfirsti(index_path->path.parent->relids))
+ if (((Var *) node)->varno == baserelid)
{
int varatt = ((Var *) node)->varattno;
int pos;
@@ -829,6 +884,7 @@ fix_indxqual_operand(Node *node, IndexPath *index_path,
{
Node *newnode = copyObject(node);
((Var *) newnode)->varattno = pos + 1;
+ *opclass = index->indclass[pos];
return newnode;
}
}
@@ -851,6 +907,9 @@ fix_indxqual_operand(Node *node, IndexPath *index_path,
* misbehaves...)
*/
+ /* indclass[0] is the only class of a functional index */
+ *opclass = index->indclass[0];
+
/* return the unmodified node */
return node;
}
@@ -964,23 +1023,44 @@ set_tlist_sort_info(List *tlist, List *pathkeys)
}
/*
+ * Copy cost and size info from a Path node to the Plan node created from it.
+ * The executor won't use this info, but it's needed by EXPLAIN.
+ */
+static void
+copy_path_costsize(Plan *dest, Path *src)
+{
+ if (src)
+ {
+ dest->cost = src->path_cost;
+ dest->plan_rows = src->parent->rows;
+ dest->plan_width = src->parent->width;
+ }
+ else
+ {
+ dest->cost = 0;
+ dest->plan_rows = 0;
+ dest->plan_width = 0;
+ }
+}
+
+/*
* Copy cost and size info from a lower plan node to an inserted node.
* This is not critical, since the decisions have already been made,
* but it helps produce more reasonable-looking EXPLAIN output.
*/
static void
-copy_costsize(Plan *dest, Plan *src)
+copy_plan_costsize(Plan *dest, Plan *src)
{
if (src)
{
dest->cost = src->cost;
- dest->plan_size = src->plan_size;
+ dest->plan_rows = src->plan_rows;
dest->plan_width = src->plan_width;
}
else
{
dest->cost = 0;
- dest->plan_size = 0;
+ dest->plan_rows = 0;
dest->plan_width = 0;
}
}
@@ -1042,7 +1122,7 @@ make_seqscan(List *qptlist,
SeqScan *node = makeNode(SeqScan);
Plan *plan = &node->plan;
- copy_costsize(plan, NULL);
+ copy_plan_costsize(plan, NULL);
plan->state = (EState *) NULL;
plan->targetlist = qptlist;
plan->qual = qpqual;
@@ -1065,7 +1145,7 @@ make_indexscan(List *qptlist,
IndexScan *node = makeNode(IndexScan);
Plan *plan = &node->scan.plan;
- copy_costsize(plan, NULL);
+ copy_plan_costsize(plan, NULL);
plan->state = (EState *) NULL;
plan->targetlist = qptlist;
plan->qual = qpqual;
@@ -1140,7 +1220,7 @@ make_hash(List *tlist, Var *hashkey, Plan *lefttree)
Hash *node = makeNode(Hash);
Plan *plan = &node->plan;
- copy_costsize(plan, lefttree);
+ copy_plan_costsize(plan, lefttree);
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NULL;
@@ -1183,8 +1263,8 @@ make_sort(List *tlist, Oid nonameid, Plan *lefttree, int keycount)
Sort *node = makeNode(Sort);
Plan *plan = &node->plan;
- copy_costsize(plan, lefttree);
- plan->cost += cost_sort(NULL, plan->plan_size, plan->plan_width);
+ copy_plan_costsize(plan, lefttree);
+ plan->cost += cost_sort(NIL, plan->plan_rows, plan->plan_width);
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
@@ -1205,7 +1285,7 @@ make_material(List *tlist,
Material *node = makeNode(Material);
Plan *plan = &node->plan;
- copy_costsize(plan, lefttree);
+ copy_plan_costsize(plan, lefttree);
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
@@ -1222,7 +1302,7 @@ make_agg(List *tlist, Plan *lefttree)
{
Agg *node = makeNode(Agg);
- copy_costsize(&node->plan, lefttree);
+ copy_plan_costsize(&node->plan, lefttree);
node->plan.state = (EState *) NULL;
node->plan.qual = NULL;
node->plan.targetlist = tlist;
@@ -1241,7 +1321,7 @@ make_group(List *tlist,
{
Group *node = makeNode(Group);
- copy_costsize(&node->plan, lefttree);
+ copy_plan_costsize(&node->plan, lefttree);
node->plan.state = (EState *) NULL;
node->plan.qual = NULL;
node->plan.targetlist = tlist;
@@ -1266,7 +1346,7 @@ make_unique(List *tlist, Plan *lefttree, char *uniqueAttr)
Unique *node = makeNode(Unique);
Plan *plan = &node->plan;
- copy_costsize(plan, lefttree);
+ copy_plan_costsize(plan, lefttree);
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
@@ -1292,7 +1372,7 @@ make_result(List *tlist,
#ifdef NOT_USED
tlist = generate_fjoin(tlist);
#endif
- copy_costsize(plan, subplan);
+ copy_plan_costsize(plan, subplan);
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index ef219245aab..7316a794612 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.40 1999/10/07 04:23:06 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.41 2000/01/09 00:26:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,6 +30,7 @@ static void add_restrict_and_join_to_rel(Query *root, Node *clause);
static void add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
Relids join_relids);
static void add_vars_to_targetlist(Query *root, List *vars);
+static void set_restrictinfo_joininfo(RestrictInfo *restrictinfo);
static void check_mergejoinable(RestrictInfo *restrictinfo);
static void check_hashjoinable(RestrictInfo *restrictinfo);
@@ -165,12 +166,6 @@ add_restrict_and_join_to_rel(Query *root, Node *clause)
restrictinfo->hashjoinoperator = InvalidOid;
/*
- * The selectivity of the clause must be computed regardless of
- * whether it's a restriction or a join clause
- */
- restrictinfo->selectivity = compute_clause_selec(root, clause);
-
- /*
* Retrieve all relids and vars contained within the clause.
*/
clause_get_relids_vars(clause, &relids, &vars);
@@ -189,12 +184,20 @@ add_restrict_and_join_to_rel(Query *root, Node *clause)
{
/*
* 'clause' is a join clause, since there is more than one atom in
- * the relid list. Add it to the join lists of all the relevant
+ * the relid list. Set additional RestrictInfo fields for joining.
+ */
+ set_restrictinfo_joininfo(restrictinfo);
+ /*
+ * Add clause to the join lists of all the relevant
* relations. (If, perchance, 'clause' contains NO vars, then
* nothing will happen...)
*/
add_join_info_to_rels(root, restrictinfo, relids);
- /* we are going to be doing a join, so add vars to targetlists */
+ /*
+ * Add vars used in the join clause to targetlists of member relations,
+ * so that they will be emitted by the plan nodes that scan those
+ * relations (else they won't be available at the join node!).
+ */
add_vars_to_targetlist(root, vars);
}
}
@@ -202,7 +205,7 @@ add_restrict_and_join_to_rel(Query *root, Node *clause)
/*
* add_join_info_to_rels
* For every relation participating in a join clause, add 'restrictinfo' to
- * the appropriate joininfo list (creating a new one and adding it to the
+ * the appropriate joininfo list (creating a new list and adding it to the
* appropriate rel node if necessary).
*
* 'restrictinfo' describes the join clause
@@ -218,8 +221,8 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
foreach(join_relid, join_relids)
{
int cur_relid = lfirsti(join_relid);
- JoinInfo *joininfo;
Relids unjoined_relids = NIL;
+ JoinInfo *joininfo;
List *otherrel;
/* Get the relids not equal to the current relid */
@@ -230,18 +233,12 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
}
/*
- * Find or make the joininfo node for this combination of rels
+ * Find or make the joininfo node for this combination of rels,
+ * and add the restrictinfo node to it.
*/
joininfo = find_joininfo_node(get_base_rel(root, cur_relid),
unjoined_relids);
-
- /*
- * And add the restrictinfo node to it. NOTE that each joininfo
- * gets its own copy of the restrictinfo node! (Is this really
- * necessary? Possibly ... later parts of the optimizer destructively
- * modify restrict/join clauses...)
- */
- joininfo->jinfo_restrictinfo = lcons(copyObject((void *) restrictinfo),
+ joininfo->jinfo_restrictinfo = lcons(restrictinfo,
joininfo->jinfo_restrictinfo);
}
}
@@ -253,36 +250,17 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
*****************************************************************************/
/*
- * set_joininfo_mergeable_hashable
- * Examine each join clause used in a query and set the merge and hash
- * info fields in those that are mergejoinable or hashjoinable.
+ * set_restrictinfo_joininfo
+ * Examine a RestrictInfo that has been determined to be a join clause,
+ * and set the merge and hash info fields if it can be merge/hash joined.
*/
-void
-set_joininfo_mergeable_hashable(List *rel_list)
+static void
+set_restrictinfo_joininfo(RestrictInfo *restrictinfo)
{
- List *x;
-
- foreach(x, rel_list)
- {
- RelOptInfo *rel = (RelOptInfo *) lfirst(x);
- List *y;
-
- foreach(y, rel->joininfo)
- {
- JoinInfo *joininfo = (JoinInfo *) lfirst(y);
- List *z;
-
- foreach(z, joininfo->jinfo_restrictinfo)
- {
- RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(z);
-
- if (_enable_mergejoin_)
- check_mergejoinable(restrictinfo);
- if (_enable_hashjoin_)
- check_hashjoinable(restrictinfo);
- }
- }
- }
+ if (_enable_mergejoin_)
+ check_mergejoinable(restrictinfo);
+ if (_enable_hashjoin_)
+ check_hashjoinable(restrictinfo);
}
/*
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c
index 7dcafe35dce..fa1744ebb9e 100644
--- a/src/backend/optimizer/plan/planmain.c
+++ b/src/backend/optimizer/plan/planmain.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.48 1999/12/09 05:58:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.49 2000/01/09 00:26:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -218,8 +218,6 @@ subplanner(Query *root,
add_restrict_and_join_to_rels(root, qual);
add_missing_rels_to_query(root);
- set_joininfo_mergeable_hashable(root->base_rel_list);
-
final_rel = make_one_rel(root, root->base_rel_list);
if (! final_rel)
@@ -275,7 +273,7 @@ subplanner(Query *root,
final_rel->cheapestpath->pathkeys))
{
root->query_pathkeys = final_rel->cheapestpath->pathkeys;
- return create_plan(final_rel->cheapestpath);
+ return create_plan(root, final_rel->cheapestpath);
}
/*
@@ -283,7 +281,7 @@ subplanner(Query *root,
* cheaper than doing an explicit sort on cheapestpath.
*/
cheapest_cost = final_rel->cheapestpath->path_cost +
- cost_sort(root->query_pathkeys, final_rel->size, final_rel->width);
+ cost_sort(root->query_pathkeys, final_rel->rows, final_rel->width);
sortedpath = get_cheapest_path_for_pathkeys(final_rel->pathlist,
root->query_pathkeys,
@@ -294,7 +292,7 @@ subplanner(Query *root,
{
/* Found a better presorted path, use it */
root->query_pathkeys = sortedpath->pathkeys;
- return create_plan(sortedpath);
+ return create_plan(root, sortedpath);
}
/* otherwise, doing it the hard way is still cheaper */
}
@@ -322,7 +320,7 @@ subplanner(Query *root,
* backwards scan, we have to convert to Plan format and
* then poke the result.
*/
- Plan *sortedplan = create_plan(sortedpath);
+ Plan *sortedplan = create_plan(root, sortedpath);
List *sortedpathkeys;
Assert(IsA(sortedplan, IndexScan));
@@ -350,5 +348,5 @@ subplanner(Query *root,
* an aggregate function...)
*/
root->query_pathkeys = final_rel->cheapestpath->pathkeys;
- return create_plan(final_rel->cheapestpath);
+ return create_plan(root, final_rel->cheapestpath);
}