aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/relnode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/relnode.c')
-rw-r--r--src/backend/optimizer/util/relnode.c150
1 files changed, 119 insertions, 31 deletions
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 457826f5d31..0fad16fbdd0 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.35 2001/10/25 05:49:34 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.36 2002/03/12 00:51:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,26 +40,26 @@ static void subbuild_joinrel_joinlist(RelOptInfo *joinrel,
/*
* build_base_rel
- * Returns relation entry corresponding to 'relid', creating a new one
- * if necessary. This is for base relations.
+ * Construct a new base relation RelOptInfo, and put it in the query's
+ * base_rel_list.
*/
-RelOptInfo *
+void
build_base_rel(Query *root, int relid)
{
List *rels;
RelOptInfo *rel;
- /* Already made? */
+ /* Rel should not exist already */
foreach(rels, root->base_rel_list)
{
rel = (RelOptInfo *) lfirst(rels);
/* length(rel->relids) == 1 for all members of base_rel_list */
if (lfirsti(rel->relids) == relid)
- return rel;
+ elog(ERROR, "build_base_rel: rel already exists");
}
- /* It should not exist as an "other" rel */
+ /* It should not exist as an "other" rel, either */
foreach(rels, root->other_rel_list)
{
rel = (RelOptInfo *) lfirst(rels);
@@ -73,14 +73,12 @@ build_base_rel(Query *root, int relid)
/* and add it to the list */
root->base_rel_list = lcons(rel, root->base_rel_list);
-
- return rel;
}
/*
* build_other_rel
* Returns relation entry corresponding to 'relid', creating a new one
- * if necessary. This is for 'other' relations, which are just like
+ * if necessary. This is for 'other' relations, which are much like
* base relations except that they live in a different list.
*/
RelOptInfo *
@@ -111,6 +109,10 @@ build_other_rel(Query *root, int relid)
/* No existing RelOptInfo for this other rel, so make a new one */
rel = make_base_rel(root, relid);
+ /* if it's not a join rel, must be a child rel */
+ if (rel->reloptkind == RELOPT_BASEREL)
+ rel->reloptkind = RELOPT_OTHER_CHILD_REL;
+
/* and add it to the list */
root->other_rel_list = lcons(rel, root->other_rel_list);
@@ -127,8 +129,9 @@ static RelOptInfo *
make_base_rel(Query *root, int relid)
{
RelOptInfo *rel = makeNode(RelOptInfo);
- Oid relationObjectId;
+ RangeTblEntry *rte = rt_fetch(relid, root->rtable);
+ rel->reloptkind = RELOPT_BASEREL;
rel->relids = makeListi1(relid);
rel->rows = 0;
rel->width = 0;
@@ -142,29 +145,40 @@ make_base_rel(Query *root, int relid)
rel->pages = 0;
rel->tuples = 0;
rel->subplan = NULL;
+ rel->joinrti = 0;
+ rel->joinrteids = NIL;
rel->baserestrictinfo = NIL;
rel->baserestrictcost = 0;
rel->outerjoinset = NIL;
rel->joininfo = NIL;
rel->innerjoin = NIL;
- /* Check rtable to see if it's a plain relation or a subquery */
- relationObjectId = getrelid(relid, root->rtable);
-
- if (relationObjectId != InvalidOid)
- {
- /* Plain relation --- retrieve statistics from the system catalogs */
- bool indexed;
-
- get_relation_info(relationObjectId,
- &indexed, &rel->pages, &rel->tuples);
- if (indexed)
- rel->indexlist = find_secondary_indexes(relationObjectId);
- }
- else
+ /* Check type of rtable entry */
+ switch (rte->rtekind)
{
- /* subquery --- mark it as such for later processing */
- rel->issubquery = true;
+ case RTE_RELATION:
+ {
+ /* Table --- retrieve statistics from the system catalogs */
+ bool indexed;
+
+ get_relation_info(rte->relid,
+ &indexed, &rel->pages, &rel->tuples);
+ if (indexed)
+ rel->indexlist = find_secondary_indexes(rte->relid);
+ break;
+ }
+ case RTE_SUBQUERY:
+ /* Subquery --- mark it as such for later processing */
+ rel->issubquery = true;
+ break;
+ case RTE_JOIN:
+ /* Join --- must be an otherrel */
+ rel->reloptkind = RELOPT_OTHER_JOIN_REL;
+ break;
+ default:
+ elog(ERROR, "make_base_rel: unsupported RTE kind %d",
+ (int) rte->rtekind);
+ break;
}
return rel;
@@ -204,6 +218,47 @@ find_base_rel(Query *root, int relid)
}
/*
+ * find_other_rel
+ * Find an otherrel entry, if one exists for the given relid.
+ * Return NULL if no entry.
+ */
+RelOptInfo *
+find_other_rel(Query *root, int relid)
+{
+ List *rels;
+
+ foreach(rels, root->other_rel_list)
+ {
+ RelOptInfo *rel = (RelOptInfo *) lfirst(rels);
+
+ if (lfirsti(rel->relids) == relid)
+ return rel;
+ }
+ return NULL;
+}
+
+/*
+ * find_other_rel_for_join
+ * Look for an otherrel for a join RTE matching the given baserel set.
+ * Return NULL if no entry.
+ */
+RelOptInfo *
+find_other_rel_for_join(Query *root, List *relids)
+{
+ List *rels;
+
+ foreach(rels, root->other_rel_list)
+ {
+ RelOptInfo *rel = (RelOptInfo *) lfirst(rels);
+
+ if (rel->reloptkind == RELOPT_OTHER_JOIN_REL
+ && sameseti(relids, rel->outerjoinset))
+ return rel;
+ }
+ return NULL;
+}
+
+/*
* find_join_rel
* Returns relation entry corresponding to 'relids' (a list of RT indexes),
* or NULL if none exists. This is for join relations.
@@ -252,6 +307,7 @@ build_join_rel(Query *root,
{
List *joinrelids;
RelOptInfo *joinrel;
+ RelOptInfo *joinrterel;
List *restrictlist;
List *new_outer_tlist;
List *new_inner_tlist;
@@ -286,6 +342,7 @@ build_join_rel(Query *root,
* Nope, so make one.
*/
joinrel = makeNode(RelOptInfo);
+ joinrel->reloptkind = RELOPT_JOINREL;
joinrel->relids = joinrelids;
joinrel->rows = 0;
joinrel->width = 0;
@@ -299,24 +356,38 @@ build_join_rel(Query *root,
joinrel->pages = 0;
joinrel->tuples = 0;
joinrel->subplan = NULL;
+ joinrel->joinrti = 0;
+ joinrel->joinrteids = nconc(listCopy(outer_rel->joinrteids),
+ inner_rel->joinrteids);
joinrel->baserestrictinfo = NIL;
joinrel->baserestrictcost = 0;
joinrel->outerjoinset = NIL;
joinrel->joininfo = NIL;
joinrel->innerjoin = NIL;
+ /* Is there a join RTE matching this join? */
+ joinrterel = find_other_rel_for_join(root, joinrelids);
+ if (joinrterel)
+ {
+ /* Yes, remember its RT index */
+ joinrel->joinrti = lfirsti(joinrterel->relids);
+ joinrel->joinrteids = lconsi(joinrel->joinrti, joinrel->joinrteids);
+ }
+
/*
* Create a new tlist by removing irrelevant elements from both tlists
* of the outer and inner join relations and then merging the results
* together.
*
+ * XXX right now we don't remove any irrelevant elements, we just
+ * append the two tlists together. Someday consider pruning vars from the
+ * join's targetlist if they are needed only to evaluate restriction
+ * clauses of this join, and will never be accessed at higher levels of
+ * the plantree.
+ *
* NOTE: the tlist order for a join rel will depend on which pair of
* outer and inner rels we first try to build it from. But the
* contents should be the same regardless.
- *
- * XXX someday: consider pruning vars from the join's targetlist if they
- * are needed only to evaluate restriction clauses of this join, and
- * will never be accessed at higher levels of the plantree.
*/
new_outer_tlist = new_join_tlist(outer_rel->targetlist, 1);
new_inner_tlist = new_join_tlist(inner_rel->targetlist,
@@ -324,6 +395,23 @@ build_join_rel(Query *root,
joinrel->targetlist = nconc(new_outer_tlist, new_inner_tlist);
/*
+ * If there are any alias variables attached to the matching join RTE,
+ * attach them to the tlist too, so that they will be evaluated for use
+ * at higher plan levels.
+ */
+ if (joinrterel)
+ {
+ List *jrtetl;
+
+ foreach(jrtetl, joinrterel->targetlist)
+ {
+ TargetEntry *jrtete = lfirst(jrtetl);
+
+ add_var_to_tlist(joinrel, (Var *) jrtete->expr);
+ }
+ }
+
+ /*
* Construct restrict and join clause lists for the new joinrel. (The
* caller might or might not need the restrictlist, but I need it
* anyway for set_joinrel_size_estimates().)