summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/allpaths.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/allpaths.c')
-rw-r--r--src/backend/optimizer/path/allpaths.c150
1 files changed, 77 insertions, 73 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 19b1cfcaad..90add90e4e 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.139 2005/12/20 02:30:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.140 2006/01/31 21:39:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -44,9 +44,8 @@ int geqo_threshold;
static void set_base_rel_pathlists(PlannerInfo *root);
static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
RangeTblEntry *rte);
-static void set_inherited_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
- Index rti, RangeTblEntry *rte,
- List *inheritlist);
+static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
+ Index rti, RangeTblEntry *rte);
static void set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte);
static void set_function_pathlist(PlannerInfo *root, RelOptInfo *rel,
@@ -96,9 +95,9 @@ make_one_rel(PlannerInfo *root, List *joinlist)
int num_base_rels = 0;
Index rti;
- for (rti = 1; rti < root->base_rel_array_size; rti++)
+ for (rti = 1; rti < root->simple_rel_array_size; rti++)
{
- RelOptInfo *brel = root->base_rel_array[rti];
+ RelOptInfo *brel = root->simple_rel_array[rti];
if (brel == NULL)
continue;
@@ -131,16 +130,10 @@ set_base_rel_pathlists(PlannerInfo *root)
{
Index rti;
- /*
- * Note: because we call expand_inherited_rtentry inside the loop, it's
- * quite possible for the base_rel_array to be enlarged while the loop
- * runs. Hence don't try to optimize the loop.
- */
- for (rti = 1; rti < root->base_rel_array_size; rti++)
+ for (rti = 1; rti < root->simple_rel_array_size; rti++)
{
- RelOptInfo *rel = root->base_rel_array[rti];
+ RelOptInfo *rel = root->simple_rel_array[rti];
RangeTblEntry *rte;
- List *inheritlist;
/* there may be empty slots corresponding to non-baserel RTEs */
if (rel == NULL)
@@ -154,7 +147,12 @@ set_base_rel_pathlists(PlannerInfo *root)
rte = rt_fetch(rti, root->parse->rtable);
- if (rel->rtekind == RTE_SUBQUERY)
+ if (rte->inh)
+ {
+ /* It's an "append relation", process accordingly */
+ set_append_rel_pathlist(root, rel, rti, rte);
+ }
+ else if (rel->rtekind == RTE_SUBQUERY)
{
/* Subquery --- generate a separate plan for it */
set_subquery_pathlist(root, rel, rti, rte);
@@ -164,11 +162,6 @@ set_base_rel_pathlists(PlannerInfo *root)
/* RangeFunction --- generate a separate plan for it */
set_function_pathlist(root, rel, rte);
}
- else if ((inheritlist = expand_inherited_rtentry(root, rti)) != NIL)
- {
- /* Relation is root of an inheritance tree, process specially */
- set_inherited_rel_pathlist(root, rel, rti, rte, inheritlist);
- }
else
{
/* Plain relation */
@@ -188,6 +181,9 @@ set_base_rel_pathlists(PlannerInfo *root)
static void
set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
{
+ Assert(rel->rtekind == RTE_RELATION);
+ Assert(!rte->inh);
+
/* Mark rel with estimated output rows, width, etc */
set_baserel_size_estimates(root, rel);
@@ -224,37 +220,29 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
}
/*
- * set_inherited_rel_pathlist
- * Build access paths for a inheritance tree rooted at rel
- *
- * inheritlist is a list of RT indexes of all tables in the inheritance tree,
- * including a duplicate of the parent itself. Note we will not come here
- * unless there's at least one child in addition to the parent.
+ * set_append_rel_pathlist
+ * Build access paths for an "append relation"
*
- * NOTE: the passed-in rel and RTE will henceforth represent the appended
- * result of the whole inheritance tree. The members of inheritlist represent
- * the individual tables --- in particular, the inheritlist member that is a
- * duplicate of the parent RTE represents the parent table alone.
- * We will generate plans to scan the individual tables that refer to
- * the inheritlist RTEs, whereas Vars elsewhere in the plan tree that
- * refer to the original RTE are taken to refer to the append output.
- * In particular, this means we have separate RelOptInfos for the parent
- * table and for the append output, which is a good thing because they're
- * not the same size.
+ * The passed-in rel and RTE represent the entire append relation. The
+ * relation's contents are computed by appending together the output of
+ * the individual member relations. Note that in the inheritance case,
+ * the first member relation is actually the same table as is mentioned in
+ * the parent RTE ... but it has a different RTE and RelOptInfo. This is
+ * a good thing because their outputs are not the same size.
*/
static void
-set_inherited_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
- Index rti, RangeTblEntry *rte,
- List *inheritlist)
+set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
+ Index rti, RangeTblEntry *rte)
{
int parentRTindex = rti;
- Oid parentOID = rte->relid;
List *subpaths = NIL;
- ListCell *il;
+ ListCell *l;
/*
* XXX for now, can't handle inherited expansion of FOR UPDATE/SHARE; can
- * we do better?
+ * we do better? (This will take some redesign because the executor
+ * currently supposes that every rowMark relation is involved in every
+ * row returned by the query.)
*/
if (list_member_int(root->parse->rowMarks, parentRTindex))
ereport(ERROR,
@@ -262,64 +250,79 @@ set_inherited_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
errmsg("SELECT FOR UPDATE/SHARE is not supported for inheritance queries")));
/*
- * Initialize to compute size estimates for whole inheritance tree
+ * Initialize to compute size estimates for whole append relation
*/
rel->rows = 0;
rel->width = 0;
/*
- * Generate access paths for each table in the tree (parent AND children),
- * and pick the cheapest path for each table.
+ * Generate access paths for each member relation, and pick the cheapest
+ * path for each one.
*/
- foreach(il, inheritlist)
+ foreach(l, root->append_rel_list)
{
- int childRTindex = lfirst_int(il);
- RangeTblEntry *childrte;
- Oid childOID;
+ AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
+ int childRTindex;
RelOptInfo *childrel;
+ RangeTblEntry *childrte;
ListCell *parentvars;
ListCell *childvars;
- childrte = rt_fetch(childRTindex, root->parse->rtable);
- childOID = childrte->relid;
+ /* append_rel_list contains all append rels; ignore others */
+ if (appinfo->parent_relid != parentRTindex)
+ continue;
+
+ childRTindex = appinfo->child_relid;
/*
* Make a RelOptInfo for the child so we can do planning. Mark it as
* an "other rel" since it will not be part of the main join tree.
*/
- childrel = build_other_rel(root, childRTindex);
+ childrel = build_simple_rel(root, childRTindex,
+ RELOPT_OTHER_MEMBER_REL);
/*
- * Copy the parent's targetlist and restriction quals to the child,
- * with attribute-number adjustment as needed. We don't bother to
- * copy the join quals, since we can't do any joining of the
- * individual tables. Also, we just zap attr_needed rather than
- * trying to adjust it; it won't be looked at in the child.
+ * Copy the parent's targetlist and quals to the child, with
+ * appropriate substitution of variables.
*/
childrel->reltargetlist = (List *)
- adjust_inherited_attrs((Node *) rel->reltargetlist,
- parentRTindex,
- parentOID,
- childRTindex,
- childOID);
- childrel->attr_needed = NULL;
+ adjust_appendrel_attrs((Node *) rel->reltargetlist,
+ appinfo);
childrel->baserestrictinfo = (List *)
- adjust_inherited_attrs((Node *) rel->baserestrictinfo,
- parentRTindex,
- parentOID,
- childRTindex,
- childOID);
+ adjust_appendrel_attrs((Node *) rel->baserestrictinfo,
+ appinfo);
+ childrel->joininfo = (List *)
+ adjust_appendrel_attrs((Node *) rel->joininfo,
+ appinfo);
+
+ /*
+ * Copy the parent's attr_needed data as well, with appropriate
+ * adjustment of relids and attribute numbers.
+ */
+ pfree(childrel->attr_needed);
+ childrel->attr_needed =
+ adjust_appendrel_attr_needed(rel, appinfo,
+ childrel->min_attr,
+ childrel->max_attr);
/*
* If we can prove we don't need to scan this child via constraint
* exclusion, just ignore it. (We have to have converted the
* baserestrictinfo Vars before we can make the test.)
+ *
+ * XXX it'd probably be better to give the child some kind of dummy
+ * cheapest path, or otherwise explicitly mark it as ignorable.
+ * Currently there is an ugly check in join_before_append() to handle
+ * excluded children.
*/
- if (constraint_exclusion)
+ childrte = rt_fetch(childRTindex, root->parse->rtable);
+ if (constraint_exclusion &&
+ childrte->rtekind == RTE_RELATION)
{
List *constraint_pred;
- constraint_pred = get_relation_constraints(childOID, childrel);
+ constraint_pred = get_relation_constraints(childrte->relid,
+ childrel);
/*
* We do not currently enforce that CHECK constraints contain only
@@ -363,7 +366,8 @@ set_inherited_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
Var *parentvar = (Var *) lfirst(parentvars);
Var *childvar = (Var *) lfirst(childvars);
- if (IsA(parentvar, Var) &&IsA(childvar, Var))
+ if (IsA(parentvar, Var) &&
+ IsA(childvar, Var))
{
int pndx = parentvar->varattno - rel->min_attr;
int cndx = childvar->varattno - childrel->min_attr;
@@ -392,9 +396,9 @@ has_multiple_baserels(PlannerInfo *root)
int num_base_rels = 0;
Index rti;
- for (rti = 1; rti < root->base_rel_array_size; rti++)
+ for (rti = 1; rti < root->simple_rel_array_size; rti++)
{
- RelOptInfo *brel = root->base_rel_array[rti];
+ RelOptInfo *brel = root->simple_rel_array[rti];
if (brel == NULL)
continue;