diff options
Diffstat (limited to 'src/backend/optimizer/plan')
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 300 | ||||
-rw-r--r-- | src/backend/optimizer/plan/initsplan.c | 74 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planmain.c | 14 |
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); } |