]> granicus.if.org Git - postgresql/commitdiff
Abstract logic to allow for multiple kinds of child rels.
authorRobert Haas <rhaas@postgresql.org>
Tue, 4 Apr 2017 02:41:31 +0000 (22:41 -0400)
committerRobert Haas <rhaas@postgresql.org>
Tue, 4 Apr 2017 02:41:31 +0000 (22:41 -0400)
Currently, the only type of child relation is an "other member rel",
which is the child of a baserel, but in the future joins and even
upper relations may have child rels.  To facilitate that, introduce
macros that test to test for particular RelOptKind values, and use
them in various places where they help to clarify the sense of a test.
(For example, a test may allow RELOPT_OTHER_MEMBER_REL either because
it intends to allow child rels, or because it intends to allow simple
rels.)

Also, remove find_childrel_top_parent, which will not work for a
child rel that is not a baserel.  Instead, add a new RelOptInfo
member top_parent_relids to track the same kind of information in a
more generic manner.

Ashutosh Bapat, slightly tweaked by me.  Review and testing of the
patch set from which this was taken by Rajkumar Raghuwanshi and Rafia
Sabih.

Discussion: http://postgr.es/m/CA+TgmoagTnF2yqR3PT2rv=om=wJiZ4-A+ATwdnriTGku1CLYxA@mail.gmail.com

16 files changed:
contrib/postgres_fdw/deparse.c
contrib/postgres_fdw/postgres_fdw.c
src/backend/foreign/foreign.c
src/backend/optimizer/path/allpaths.c
src/backend/optimizer/path/equivclass.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/initsplan.c
src/backend/optimizer/plan/planmain.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/plancat.c
src/backend/optimizer/util/relnode.c
src/backend/utils/adt/selfuncs.c
src/include/nodes/relation.h
src/include/optimizer/pathnode.h

index 1d7ec28806dff0d37180e6d9a7c62b619db1e946..129bdb549ffabdccb3f039781f0ab3ee757ddf9a 100644 (file)
@@ -243,7 +243,7 @@ is_foreign_expr(PlannerInfo *root,
         * because the upperrel's own relids currently aren't set to anything
         * meaningful by the core code.  For other relation, use their own relids.
         */
-       if (baserel->reloptkind == RELOPT_UPPER_REL)
+       if (IS_UPPER_REL(baserel))
                glob_cxt.relids = fpinfo->outerrel->relids;
        else
                glob_cxt.relids = baserel->relids;
@@ -677,7 +677,7 @@ foreign_expr_walker(Node *node,
                                ListCell   *lc;
 
                                /* Not safe to pushdown when not in grouping context */
-                               if (glob_cxt->foreignrel->reloptkind != RELOPT_UPPER_REL)
+                               if (!IS_UPPER_REL(glob_cxt->foreignrel))
                                        return false;
 
                                /* Only non-split aggregates are pushable. */
@@ -874,7 +874,7 @@ build_tlist_to_deparse(RelOptInfo *foreignrel)
         * For an upper relation, we have already built the target list while
         * checking shippability, so just return that.
         */
-       if (foreignrel->reloptkind == RELOPT_UPPER_REL)
+       if (IS_UPPER_REL(foreignrel))
                return fpinfo->grouped_tlist;
 
        /*
@@ -929,17 +929,13 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel,
         * We handle relations for foreign tables, joins between those and upper
         * relations.
         */
-       Assert(rel->reloptkind == RELOPT_JOINREL ||
-                  rel->reloptkind == RELOPT_BASEREL ||
-                  rel->reloptkind == RELOPT_OTHER_MEMBER_REL ||
-                  rel->reloptkind == RELOPT_UPPER_REL);
+       Assert(IS_JOIN_REL(rel) || IS_SIMPLE_REL(rel) || IS_UPPER_REL(rel));
 
        /* Fill portions of context common to upper, join and base relation */
        context.buf = buf;
        context.root = root;
        context.foreignrel = rel;
-       context.scanrel = (rel->reloptkind == RELOPT_UPPER_REL) ?
-               fpinfo->outerrel : rel;
+       context.scanrel = IS_UPPER_REL(rel) ? fpinfo->outerrel : rel;
        context.params_list = params_list;
 
        /* Construct SELECT clause */
@@ -950,7 +946,7 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel,
         * conditions of the underlying scan relation; otherwise, we can use the
         * supplied list of remote conditions directly.
         */
-       if (rel->reloptkind == RELOPT_UPPER_REL)
+       if (IS_UPPER_REL(rel))
        {
                PgFdwRelationInfo *ofpinfo;
 
@@ -963,7 +959,7 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel,
        /* Construct FROM and WHERE clauses */
        deparseFromExpr(quals, &context);
 
-       if (rel->reloptkind == RELOPT_UPPER_REL)
+       if (IS_UPPER_REL(rel))
        {
                /* Append GROUP BY clause */
                appendGroupByClause(tlist, &context);
@@ -1020,8 +1016,7 @@ deparseSelectSql(List *tlist, bool is_subquery, List **retrieved_attrs,
                 */
                deparseSubqueryTargetList(context);
        }
-       else if (foreignrel->reloptkind == RELOPT_JOINREL ||
-                        foreignrel->reloptkind == RELOPT_UPPER_REL)
+       else if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
        {
                /*
                 * For a join or upper relation the input tlist gives the list of
@@ -1062,9 +1057,8 @@ deparseFromExpr(List *quals, deparse_expr_cxt *context)
        RelOptInfo *scanrel = context->scanrel;
 
        /* For upper relations, scanrel must be either a joinrel or a baserel */
-       Assert(context->foreignrel->reloptkind != RELOPT_UPPER_REL ||
-                  scanrel->reloptkind == RELOPT_JOINREL ||
-                  scanrel->reloptkind == RELOPT_BASEREL);
+       Assert(!IS_UPPER_REL(context->foreignrel) ||
+                  IS_JOIN_REL(scanrel) || IS_SIMPLE_REL(scanrel));
 
        /* Construct FROM clause */
        appendStringInfoString(buf, " FROM ");
@@ -1219,7 +1213,7 @@ deparseLockingClause(deparse_expr_cxt *context)
                        appendStringInfoString(buf, " FOR UPDATE");
 
                        /* Add the relation alias if we are here for a join relation */
-                       if (rel->reloptkind == RELOPT_JOINREL)
+                       if (IS_JOIN_REL(rel))
                                appendStringInfo(buf, " OF %s%d", REL_ALIAS_PREFIX, relid);
                }
                else
@@ -1384,8 +1378,7 @@ deparseSubqueryTargetList(deparse_expr_cxt *context)
        ListCell   *lc;
 
        /* Should only be called in these cases. */
-       Assert(foreignrel->reloptkind == RELOPT_BASEREL ||
-                  foreignrel->reloptkind == RELOPT_JOINREL);
+       Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
 
        first = true;
        foreach(lc, foreignrel->reltarget->exprs)
@@ -1417,7 +1410,7 @@ deparseFromExprForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
 {
        PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
 
-       if (foreignrel->reloptkind == RELOPT_JOINREL)
+       if (IS_JOIN_REL(foreignrel))
        {
                StringInfoData join_sql_o;
                StringInfoData join_sql_i;
@@ -1495,8 +1488,7 @@ deparseRangeTblRef(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel,
        PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
 
        /* Should only be called in these cases. */
-       Assert(foreignrel->reloptkind == RELOPT_BASEREL ||
-                  foreignrel->reloptkind == RELOPT_JOINREL);
+       Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
 
        Assert(fpinfo->local_conds == NIL);
 
@@ -3097,15 +3089,13 @@ is_subquery_var(Var *node, RelOptInfo *foreignrel, int *relno, int *colno)
        RelOptInfo *innerrel = fpinfo->innerrel;
 
        /* Should only be called in these cases. */
-       Assert(foreignrel->reloptkind == RELOPT_BASEREL ||
-                  foreignrel->reloptkind == RELOPT_JOINREL ||
-                  foreignrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
+       Assert(IS_SIMPLE_REL(foreignrel) || IS_JOIN_REL(foreignrel));
 
        /*
         * If the given relation isn't a join relation, it doesn't have any lower
         * subqueries, so the Var isn't a subquery output column.
         */
-       if (foreignrel->reloptkind != RELOPT_JOINREL)
+       if (!IS_JOIN_REL(foreignrel))
                return false;
 
        /*
index 54b938734a87bced4659a41de2bc7c151a6a5017..2851869932dd1c55c4879d44f8345f8aa37710e6 100644 (file)
@@ -729,8 +729,11 @@ get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel)
                return useful_eclass_list;
 
        /* If this is a child rel, we must use the topmost parent rel to search. */
-       if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
-               relids = find_childrel_top_parent(root, rel)->relids;
+       if (IS_OTHER_REL(rel))
+       {
+               Assert(!bms_is_empty(rel->top_parent_relids));
+               relids = rel->top_parent_relids;
+       }
        else
                relids = rel->relids;
 
@@ -1129,8 +1132,7 @@ postgresGetForeignPlan(PlannerInfo *root,
         * For base relations, set scan_relid as the relid of the relation. For
         * other kinds of relations set it to 0.
         */
-       if (foreignrel->reloptkind == RELOPT_BASEREL ||
-               foreignrel->reloptkind == RELOPT_OTHER_MEMBER_REL)
+       if (IS_SIMPLE_REL(foreignrel))
                scan_relid = foreignrel->relid;
        else
        {
@@ -1189,8 +1191,7 @@ postgresGetForeignPlan(PlannerInfo *root,
                        local_exprs = lappend(local_exprs, rinfo->clause);
        }
 
-       if (foreignrel->reloptkind == RELOPT_JOINREL ||
-               foreignrel->reloptkind == RELOPT_UPPER_REL)
+       if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
        {
                /* For a join relation, get the conditions from fdw_private structure */
                remote_conds = fpinfo->remote_conds;
@@ -1216,7 +1217,7 @@ postgresGetForeignPlan(PlannerInfo *root,
                         * joins. Queries involving aggregates or grouping do not require
                         * EPQ mechanism, hence should not have an outer plan here.
                         */
-                       Assert(foreignrel->reloptkind != RELOPT_UPPER_REL);
+                       Assert(!IS_UPPER_REL(foreignrel));
 
                        outer_plan->targetlist = fdw_scan_tlist;
 
@@ -1255,8 +1256,7 @@ postgresGetForeignPlan(PlannerInfo *root,
                                                         remote_conds,
                                                         retrieved_attrs,
                                                         makeInteger(fpinfo->fetch_size));
-       if (foreignrel->reloptkind == RELOPT_JOINREL ||
-               foreignrel->reloptkind == RELOPT_UPPER_REL)
+       if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
                fdw_private = lappend(fdw_private,
                                                          makeString(fpinfo->relation_name->data));
 
@@ -2535,8 +2535,7 @@ estimate_path_cost_size(PlannerInfo *root,
                                                   &remote_param_join_conds, &local_param_join_conds);
 
                /* Build the list of columns to be fetched from the foreign server. */
-               if (foreignrel->reloptkind == RELOPT_JOINREL ||
-                       foreignrel->reloptkind == RELOPT_UPPER_REL)
+               if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
                        fdw_scan_tlist = build_tlist_to_deparse(foreignrel);
                else
                        fdw_scan_tlist = NIL;
@@ -2617,7 +2616,7 @@ estimate_path_cost_size(PlannerInfo *root,
                        startup_cost = fpinfo->rel_startup_cost;
                        run_cost = fpinfo->rel_total_cost - fpinfo->rel_startup_cost;
                }
-               else if (foreignrel->reloptkind == RELOPT_JOINREL)
+               else if (IS_JOIN_REL(foreignrel))
                {
                        PgFdwRelationInfo *fpinfo_i;
                        PgFdwRelationInfo *fpinfo_o;
@@ -2683,7 +2682,7 @@ estimate_path_cost_size(PlannerInfo *root,
                        run_cost += nrows * remote_conds_cost.per_tuple;
                        run_cost += fpinfo->local_conds_cost.per_tuple * retrieved_rows;
                }
-               else if (foreignrel->reloptkind == RELOPT_UPPER_REL)
+               else if (IS_UPPER_REL(foreignrel))
                {
                        PgFdwRelationInfo *ofpinfo;
                        PathTarget *ptarget = root->upper_targets[UPPERREL_GROUP_AGG];
index 5a45558b915f9c2e2dd6820c634dc7480dd19b75..a113bf540da29be78e79e46f3c0ca1df1c509029 100644 (file)
@@ -717,7 +717,7 @@ GetExistingLocalJoinPath(RelOptInfo *joinrel)
 {
        ListCell   *lc;
 
-       Assert(joinrel->reloptkind == RELOPT_JOINREL);
+       Assert(IS_JOIN_REL(joinrel));
 
        foreach(lc, joinrel->pathlist)
        {
@@ -782,7 +782,7 @@ GetExistingLocalJoinPath(RelOptInfo *joinrel)
                        ForeignPath *foreign_path;
 
                        foreign_path = (ForeignPath *) joinpath->outerjoinpath;
-                       if (foreign_path->path.parent->reloptkind == RELOPT_JOINREL)
+                       if (IS_JOIN_REL(foreign_path->path.parent))
                                joinpath->outerjoinpath = foreign_path->fdw_outerpath;
                }
 
@@ -791,7 +791,7 @@ GetExistingLocalJoinPath(RelOptInfo *joinrel)
                        ForeignPath *foreign_path;
 
                        foreign_path = (ForeignPath *) joinpath->innerjoinpath;
-                       if (foreign_path->path.parent->reloptkind == RELOPT_JOINREL)
+                       if (IS_JOIN_REL(foreign_path->path.parent))
                                joinpath->innerjoinpath = foreign_path->fdw_outerpath;
                }
 
index 343b35aa326a40e741c8970662f275d14c4ced64..b93b4fc77369a551636d418b9789bdbb553b0411 100644 (file)
@@ -539,8 +539,7 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
        Assert(root->glob->parallelModeOK);
 
        /* This should only be called for baserels and appendrel children. */
-       Assert(rel->reloptkind == RELOPT_BASEREL ||
-                  rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
+       Assert(IS_SIMPLE_REL(rel));
 
        /* Assorted checks based on rtekind. */
        switch (rte->rtekind)
@@ -846,7 +845,7 @@ set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
 
 /*
  * set_append_rel_size
- *       Set size estimates for an "append relation"
+ *       Set size estimates for a simple "append relation"
  *
  * The passed-in rel and RTE represent the entire append relation.  The
  * relation's contents are computed by appending together the output of
@@ -867,6 +866,8 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
        int                     nattrs;
        ListCell   *l;
 
+       Assert(IS_SIMPLE_REL(rel));
+
        /*
         * Initialize to compute size estimates for whole append relation.
         *
index a329dd1e10d70b11c302c0c1524d5ad29d6969a8..67bd760fb47f2fe564ff59336086d73bcb6e781e 100644 (file)
@@ -1060,10 +1060,12 @@ generate_join_implied_equalities_for_ecs(PlannerInfo *root,
        ListCell   *lc;
 
        /* If inner rel is a child, extra setup work is needed */
-       if (inner_rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
+       if (IS_OTHER_REL(inner_rel))
        {
+               Assert(!bms_is_empty(inner_rel->top_parent_relids));
+
                /* Fetch relid set for the topmost parent rel */
-               nominal_inner_relids = find_childrel_top_parent(root, inner_rel)->relids;
+               nominal_inner_relids = inner_rel->top_parent_relids;
                /* ECs will be marked with the parent's relid, not the child's */
                nominal_join_relids = bms_union(outer_relids, nominal_inner_relids);
        }
@@ -1324,8 +1326,7 @@ generate_join_implied_equalities_broken(PlannerInfo *root,
         * mentioned in the ec_sources clauses, we have to be prepared to apply
         * multiple levels of Var translation.
         */
-       if (inner_rel->reloptkind == RELOPT_OTHER_MEMBER_REL &&
-               result != NIL)
+       if (IS_OTHER_REL(inner_rel) && result != NIL)
                result = (List *) adjust_appendrel_attrs_multilevel(root,
                                                                                                                        (Node *) result,
                                                                                                                        inner_rel);
@@ -2180,6 +2181,9 @@ generate_implied_equalities_for_column(PlannerInfo *root,
        Relids          parent_relids;
        ListCell   *lc1;
 
+       /* Indexes are available only on base or "other" member relations. */
+       Assert(IS_SIMPLE_REL(rel));
+
        /* If it's a child rel, we'll need to know what its parent(s) are */
        if (is_child_rel)
                parent_relids = find_childrel_parents(root, rel);
@@ -2413,8 +2417,11 @@ eclass_useful_for_merging(PlannerInfo *root,
         */
 
        /* If specified rel is a child, we must consider the topmost parent rel */
-       if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
-               relids = find_childrel_top_parent(root, rel)->relids;
+       if (IS_OTHER_REL(rel))
+       {
+               Assert(!bms_is_empty(rel->top_parent_relids));
+               relids = rel->top_parent_relids;
+       }
        else
                relids = rel->relids;
 
index a5d19f9b1c58b212994730f69ab9306ae8c1991f..cec9822cb79ebc952faf2c49324c32f1311fc7cd 100644 (file)
@@ -2779,6 +2779,9 @@ check_index_predicates(PlannerInfo *root, RelOptInfo *rel)
        Relids          otherrels;
        ListCell   *lc;
 
+       /* Indexes are available only on base or "other" member relations. */
+       Assert(IS_SIMPLE_REL(rel));
+
        /*
         * Initialize the indrestrictinfo lists to be identical to
         * baserestrictinfo, and check whether there are any partial indexes.  If
index 2a78595e1f2cc76c8f0f0342972d752225a6ae6b..b121f40ff8cb129e8491272521e28b9875c211c3 100644 (file)
@@ -3461,7 +3461,7 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
         * upper rel doesn't have relids set, but it covers all the base relations
         * participating in the underlying scan, so use root's all_baserels.
         */
-       if (rel->reloptkind == RELOPT_UPPER_REL)
+       if (IS_UPPER_REL(rel))
                scan_plan->fs_relids = root->all_baserels;
        else
                scan_plan->fs_relids = best_path->path.parent->relids;
index 53aefbd1a3dea8fc56f89d15d6ce4aee83072ee2..ebd442ad4db8301b9b8e1f1ace34041f3d990c34 100644 (file)
@@ -109,7 +109,7 @@ add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
        {
                int                     varno = ((RangeTblRef *) jtnode)->rtindex;
 
-               (void) build_simple_rel(root, varno, RELOPT_BASEREL);
+               (void) build_simple_rel(root, varno, NULL);
        }
        else if (IsA(jtnode, FromExpr))
        {
index 3c58d0596c69c9fdad079e9d75e2a1a32ad56468..ef0de3fb1a99917f02e51a5568b7904e0f8464a8 100644 (file)
@@ -242,8 +242,7 @@ query_planner(PlannerInfo *root, List *tlist,
 
                Assert(brel->relid == rti);             /* sanity check on array */
 
-               if (brel->reloptkind == RELOPT_BASEREL ||
-                       brel->reloptkind == RELOPT_OTHER_MEMBER_REL)
+               if (IS_SIMPLE_REL(brel))
                        total_pages += (double) brel->pages;
        }
        root->total_table_pages = total_pages;
index 9d1a98220a7fce62bae6101cb845d05bf2602956..17cd683d8535ee28206c2a8ff35a8d6ec4507d41 100644 (file)
@@ -6001,7 +6001,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
        setup_simple_rel_arrays(root);
 
        /* Build RelOptInfo */
-       rel = build_simple_rel(root, 1, RELOPT_BASEREL);
+       rel = build_simple_rel(root, 1, NULL);
 
        /* Locate IndexOptInfo for the target index */
        indexInfo = NULL;
index e327e66f6b9ee5430ef96bd816ce4999bfbcc201..b5cb4de6a2618f84233e3449cc5699b7554b642d 100644 (file)
@@ -271,7 +271,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
                 * used for much here, but it carries the subroot data structures
                 * forward to setrefs.c processing.
                 */
-               rel = build_simple_rel(root, rtr->rtindex, RELOPT_BASEREL);
+               rel = build_simple_rel(root, rtr->rtindex, NULL);
 
                /* plan_params should not be in use in current query level */
                Assert(root->plan_params == NIL);
@@ -2143,7 +2143,7 @@ adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
        RelOptInfo *parent_rel = find_base_rel(root, appinfo->parent_relid);
 
        /* If parent is also a child, first recurse to apply its translations */
-       if (parent_rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
+       if (IS_OTHER_REL(parent_rel))
                node = adjust_appendrel_attrs_multilevel(root, node, parent_rel);
        else
                Assert(parent_rel->reloptkind == RELOPT_BASEREL);
index 1cd21c0fdcb1b10e30b108d2159d3dd3ddc483f5..19904b54bd5a50604d1ca28968c6c8d29377017a 100644 (file)
@@ -1337,6 +1337,9 @@ relation_excluded_by_constraints(PlannerInfo *root,
        List       *safe_constraints;
        ListCell   *lc;
 
+       /* As of now, constraint exclusion works only with simple relations. */
+       Assert(IS_SIMPLE_REL(rel));
+
        /*
         * Regardless of the setting of constraint_exclusion, detect
         * constant-FALSE-or-NULL restriction clauses.  Because const-folding will
index 7912df0baaae5a3c3295864d3fdb284590df602f..3aa701fd843dd01e449ba69f1e274349426b1675 100644 (file)
@@ -88,7 +88,7 @@ setup_simple_rel_arrays(PlannerInfo *root)
  *       Construct a new RelOptInfo for a base relation or 'other' relation.
  */
 RelOptInfo *
-build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
+build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
 {
        RelOptInfo *rel;
        RangeTblEntry *rte;
@@ -103,7 +103,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
        Assert(rte != NULL);
 
        rel = makeNode(RelOptInfo);
-       rel->reloptkind = reloptkind;
+       rel->reloptkind = parent ? RELOPT_OTHER_MEMBER_REL : RELOPT_BASEREL;
        rel->relids = bms_make_singleton(relid);
        rel->rows = 0;
        /* cheap startup cost is interesting iff not all tuples to be retrieved */
@@ -144,6 +144,22 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
        rel->joininfo = NIL;
        rel->has_eclass_joins = false;
 
+       /*
+        * Pass top parent's relids down the inheritance hierarchy. If the parent
+        * has top_parent_relids set, it's a direct or an indirect child of the top
+        * parent indicated by top_parent_relids. By extention this child is also
+        * an indirect child of that parent.
+        */
+       if (parent)
+       {
+               if (parent->top_parent_relids)
+                       rel->top_parent_relids = parent->top_parent_relids;
+               else
+                       rel->top_parent_relids = bms_copy(parent->relids);
+       }
+       else
+               rel->top_parent_relids = NULL;
+
        /* Check type of rtable entry */
        switch (rte->rtekind)
        {
@@ -209,7 +225,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
                                continue;
 
                        (void) build_simple_rel(root, appinfo->child_relid,
-                                                                       RELOPT_OTHER_MEMBER_REL);
+                                                                       rel);
                }
        }
 
@@ -504,6 +520,7 @@ build_join_rel(PlannerInfo *root,
        joinrel->baserestrict_min_security = UINT_MAX;
        joinrel->joininfo = NIL;
        joinrel->has_eclass_joins = false;
+       joinrel->top_parent_relids = NULL;
 
        /* Compute information relevant to the foreign relations. */
        set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
@@ -965,32 +982,6 @@ find_childrel_appendrelinfo(PlannerInfo *root, RelOptInfo *rel)
 }
 
 
-/*
- * find_childrel_top_parent
- *             Fetch the topmost appendrel parent rel of an appendrel child rel.
- *
- * Since appendrels can be nested, a child could have multiple levels of
- * appendrel ancestors.  This function locates the topmost ancestor,
- * which will be a regular baserel not an otherrel.
- */
-RelOptInfo *
-find_childrel_top_parent(PlannerInfo *root, RelOptInfo *rel)
-{
-       do
-       {
-               AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, rel);
-               Index           prelid = appinfo->parent_relid;
-
-               /* traverse up to the parent rel, loop if it's also a child rel */
-               rel = find_base_rel(root, prelid);
-       } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
-
-       Assert(rel->reloptkind == RELOPT_BASEREL);
-
-       return rel;
-}
-
-
 /*
  * find_childrel_parents
  *             Compute the set of parent relids of an appendrel child rel.
@@ -1004,6 +995,8 @@ find_childrel_parents(PlannerInfo *root, RelOptInfo *rel)
 {
        Relids          result = NULL;
 
+       Assert(rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
+
        do
        {
                AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, rel);
index 5c382a2013e2b09905deef9cfaa70bf1ad765e3e..68b54235b3f84526a4b7f5cbe883a0f28a626f59 100644 (file)
@@ -3473,7 +3473,7 @@ estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows,
                /*
                 * Sanity check --- don't divide by zero if empty relation.
                 */
-               Assert(rel->reloptkind == RELOPT_BASEREL);
+               Assert(IS_SIMPLE_REL(rel));
                if (rel->tuples > 0)
                {
                        /*
index ebf9480f3773b160112443abb7f9457b6027f01f..fc53eb171aab685a2fede2fa7b04fd68740ebe26 100644 (file)
@@ -484,6 +484,23 @@ typedef enum RelOptKind
        RELOPT_DEADREL
 } RelOptKind;
 
+/*
+ * Is the given relation a simple relation i.e a base or "other" member
+ * relation?
+ */
+#define IS_SIMPLE_REL(rel) \
+       ((rel)->reloptkind == RELOPT_BASEREL || \
+        (rel)->reloptkind == RELOPT_OTHER_MEMBER_REL)
+
+/* Is the given relation a join relation? */
+#define IS_JOIN_REL(rel) ((rel)->reloptkind == RELOPT_JOINREL)
+
+/* Is the given relation an upper relation? */
+#define IS_UPPER_REL(rel) ((rel)->reloptkind == RELOPT_UPPER_REL)
+
+/* Is the given relation an "other" relation? */
+#define IS_OTHER_REL(rel) ((rel)->reloptkind == RELOPT_OTHER_MEMBER_REL)
+
 typedef struct RelOptInfo
 {
        NodeTag         type;
@@ -554,6 +571,9 @@ typedef struct RelOptInfo
        List       *joininfo;           /* RestrictInfo structures for join clauses
                                                                 * involving this rel */
        bool            has_eclass_joins;               /* T means joininfo is incomplete */
+
+       /* used by "other" relations. */
+       Relids          top_parent_relids;              /* Relids of topmost parents. */
 } RelOptInfo;
 
 /*
index 82d4e8701c893c1568474360946389ce74c593ee..2e712c6a35d2c745f8b4e44f88862e53a57dc847 100644 (file)
@@ -256,7 +256,7 @@ extern Path *reparameterize_path(PlannerInfo *root, Path *path,
  */
 extern void setup_simple_rel_arrays(PlannerInfo *root);
 extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid,
-                                RelOptKind reloptkind);
+                                RelOptInfo *parent);
 extern RelOptInfo *find_base_rel(PlannerInfo *root, int relid);
 extern RelOptInfo *find_join_rel(PlannerInfo *root, Relids relids);
 extern RelOptInfo *build_join_rel(PlannerInfo *root,
@@ -274,7 +274,6 @@ extern RelOptInfo *fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind,
                                Relids relids);
 extern AppendRelInfo *find_childrel_appendrelinfo(PlannerInfo *root,
                                                        RelOptInfo *rel);
-extern RelOptInfo *find_childrel_top_parent(PlannerInfo *root, RelOptInfo *rel);
 extern Relids find_childrel_parents(PlannerInfo *root, RelOptInfo *rel);
 extern ParamPathInfo *get_baserel_parampathinfo(PlannerInfo *root,
                                                  RelOptInfo *baserel,