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.c144
1 files changed, 143 insertions, 1 deletions
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index cedb8082271..ca258d5381a 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.75 2006/01/31 21:39:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.76 2006/02/03 21:08:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,6 +18,7 @@
#include "optimizer/joininfo.h"
#include "optimizer/pathnode.h"
#include "optimizer/plancat.h"
+#include "optimizer/prep.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
#include "parser/parsetree.h"
@@ -570,3 +571,144 @@ subbuild_joinrel_joinlist(RelOptInfo *joinrel,
}
}
}
+
+/*
+ * translate_join_rel
+ * Returns relation entry corresponding to the union of two given rels,
+ * creating a new relation entry if none already exists. This is used
+ * when one of the inputs is an append child relation. In addition to
+ * data about the input rels themselves, the corresponding joinrel for
+ * the append parent relation must be provided, plus the AppendRelInfo
+ * showing the parent-to-child translation.
+ *
+ * The reason for having this code, instead of just applying build_join_rel,
+ * is that we must have corresponding tlist orderings for all joinrels that
+ * are involved in an Append plan. So we generate the tlist for joinrels
+ * involving append child relations by translating the parent joinrel's tlist,
+ * rather than examining the input relations directly. (Another reason for
+ * doing it this way is that the base relation attr_needed info in relations
+ * being joined to the appendrel doesn't refer to the append child rel, but
+ * the append parent, and so couldn't be used directly anyway.) Otherwise
+ * this is exactly like build_join_rel.
+ */
+RelOptInfo *
+translate_join_rel(PlannerInfo *root,
+ RelOptInfo *oldjoinrel,
+ AppendRelInfo *appinfo,
+ RelOptInfo *outer_rel,
+ RelOptInfo *inner_rel,
+ JoinType jointype,
+ List **restrictlist_ptr)
+{
+ RelOptInfo *joinrel;
+ Relids joinrelids;
+ List *restrictlist;
+
+ /*
+ * Construct the Relids set for the translated joinrel, and see if
+ * we've already built it.
+ */
+ joinrelids = bms_copy(oldjoinrel->relids);
+ joinrelids = bms_del_member(joinrelids, appinfo->parent_relid);
+ joinrelids = bms_add_member(joinrelids, appinfo->child_relid);
+ joinrel = find_join_rel(root, joinrelids);
+ if (joinrel)
+ {
+ /*
+ * Yes, so we only need to figure the restrictlist for this particular
+ * pair of component relations.
+ */
+ bms_free(joinrelids);
+ if (restrictlist_ptr)
+ *restrictlist_ptr = build_joinrel_restrictlist(root,
+ joinrel,
+ outer_rel,
+ inner_rel,
+ jointype);
+ return joinrel;
+ }
+
+ /*
+ * Nope, so make one.
+ */
+ joinrel = makeNode(RelOptInfo);
+ joinrel->reloptkind = RELOPT_JOINREL;
+ joinrel->relids = joinrelids;
+ joinrel->rows = 0;
+ joinrel->width = 0;
+ joinrel->reltargetlist = NIL;
+ joinrel->pathlist = NIL;
+ joinrel->cheapest_startup_path = NULL;
+ joinrel->cheapest_total_path = NULL;
+ joinrel->cheapest_unique_path = NULL;
+ joinrel->relid = 0; /* indicates not a baserel */
+ joinrel->rtekind = RTE_JOIN;
+ joinrel->min_attr = 0;
+ joinrel->max_attr = 0;
+ joinrel->attr_needed = NULL;
+ joinrel->attr_widths = NULL;
+ joinrel->indexlist = NIL;
+ joinrel->pages = 0;
+ joinrel->tuples = 0;
+ joinrel->subplan = NULL;
+ joinrel->baserestrictinfo = NIL;
+ joinrel->baserestrictcost.startup = 0;
+ joinrel->baserestrictcost.per_tuple = 0;
+ joinrel->joininfo = NIL;
+ joinrel->index_outer_relids = NULL;
+ joinrel->index_inner_paths = NIL;
+
+ /*
+ * Make the tlist by translating oldjoinrel's tlist, to ensure they
+ * are in compatible orders. Since we don't call build_joinrel_tlist,
+ * we need another way to set the rel width; for the moment, just
+ * assume it is the same as oldjoinrel. (The correct value may well be
+ * less, but it's not clear it's worth the trouble to get it right.)
+ */
+ joinrel->reltargetlist = (List *)
+ adjust_appendrel_attrs((Node *) oldjoinrel->reltargetlist,
+ appinfo);
+ joinrel->width = oldjoinrel->width;
+
+ /*
+ * 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().)
+ */
+ restrictlist = build_joinrel_restrictlist(root,
+ joinrel,
+ outer_rel,
+ inner_rel,
+ jointype);
+ if (restrictlist_ptr)
+ *restrictlist_ptr = restrictlist;
+ build_joinrel_joinlist(joinrel, outer_rel, inner_rel);
+
+ /*
+ * Set estimates of the joinrel's size.
+ */
+ set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
+ jointype, restrictlist);
+
+ /*
+ * Add the joinrel to the query's joinrel list, and store it into the
+ * auxiliary hashtable if there is one. NB: GEQO requires us to append
+ * the new joinrel to the end of the list!
+ */
+ root->join_rel_list = lappend(root->join_rel_list, joinrel);
+
+ if (root->join_rel_hash)
+ {
+ JoinHashEntry *hentry;
+ bool found;
+
+ hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
+ &(joinrel->relids),
+ HASH_ENTER,
+ &found);
+ Assert(!found);
+ hentry->join_rel = joinrel;
+ }
+
+ return joinrel;
+}