diff options
Diffstat (limited to 'src/backend/optimizer/util/relnode.c')
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 132 |
1 files changed, 90 insertions, 42 deletions
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 4130514952b..0d40b8d3d2c 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -166,13 +166,10 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent) rel->cheapest_total_path = NULL; rel->cheapest_unique_path = NULL; rel->cheapest_parameterized_paths = NIL; - rel->direct_lateral_relids = NULL; - rel->lateral_relids = NULL; rel->relid = relid; rel->rtekind = rte->rtekind; /* min_attr, max_attr, attr_needed, attr_widths are set below */ rel->lateral_vars = NIL; - rel->lateral_referencers = NULL; rel->indexlist = NIL; rel->statlist = NIL; rel->pages = 0; @@ -205,20 +202,44 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent) rel->partitioned_child_rels = NIL; /* - * 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 extension this child is - * also an indirect child of that parent. + * Pass assorted information down the inheritance hierarchy. */ if (parent) { + /* + * Each direct or indirect child wants to know the relids of its + * topmost parent. + */ if (parent->top_parent_relids) rel->top_parent_relids = parent->top_parent_relids; else rel->top_parent_relids = bms_copy(parent->relids); + + /* + * Also propagate lateral-reference information from appendrel parent + * rels to their child rels. We intentionally give each child rel the + * same minimum parameterization, even though it's quite possible that + * some don't reference all the lateral rels. This is because any + * append path for the parent will have to have the same + * parameterization for every child anyway, and there's no value in + * forcing extra reparameterize_path() calls. Similarly, a lateral + * reference to the parent prevents use of otherwise-movable join rels + * for each child. + * + * It's possible for child rels to have their own children, in which + * case the topmost parent's lateral info propagates all the way down. + */ + rel->direct_lateral_relids = parent->direct_lateral_relids; + rel->lateral_relids = parent->lateral_relids; + rel->lateral_referencers = parent->lateral_referencers; } else + { rel->top_parent_relids = NULL; + rel->direct_lateral_relids = NULL; + rel->lateral_relids = NULL; + rel->lateral_referencers = NULL; + } /* Check type of rtable entry */ switch (rte->rtekind) @@ -273,53 +294,80 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent) root->qual_security_level = Max(root->qual_security_level, list_length(rte->securityQuals)); + return rel; +} + +/* + * add_appendrel_other_rels + * Add "other rel" RelOptInfos for the children of an appendrel baserel + * + * "rel" is a relation that (still) has the rte->inh flag set, meaning it + * has appendrel children listed in root->append_rel_list. We need to build + * a RelOptInfo for each child relation so that we can plan scans on them. + * (The parent relation might be a partitioned table, a table with + * traditional inheritance children, or a flattened UNION ALL subquery.) + */ +void +add_appendrel_other_rels(PlannerInfo *root, RelOptInfo *rel, Index rti) +{ + int cnt_parts = 0; + ListCell *l; + /* - * If this rel is an appendrel parent, recurse to build "other rel" - * RelOptInfos for its children. They are "other rels" because they are - * not in the main join tree, but we will need RelOptInfos to plan access - * to them. + * If rel is a partitioned table, then we also need to build a part_rels + * array so that the child RelOptInfos can be conveniently accessed from + * the parent. */ - if (rte->inh) + if (rel->part_scheme != NULL) { - ListCell *l; - int nparts = rel->nparts; - int cnt_parts = 0; - - if (nparts > 0) - rel->part_rels = (RelOptInfo **) - palloc(sizeof(RelOptInfo *) * nparts); + Assert(rel->nparts > 0); + rel->part_rels = (RelOptInfo **) + palloc0(sizeof(RelOptInfo *) * rel->nparts); + } - foreach(l, root->append_rel_list) - { - AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); - RelOptInfo *childrel; + foreach(l, root->append_rel_list) + { + AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); + Index childRTindex = appinfo->child_relid; + RangeTblEntry *childrte; + RelOptInfo *childrel; - /* append_rel_list contains all append rels; ignore others */ - if (appinfo->parent_relid != relid) - continue; + /* append_rel_list contains all append rels; ignore others */ + if (appinfo->parent_relid != rti) + continue; - childrel = build_simple_rel(root, appinfo->child_relid, - rel); + /* find the child RTE, which should already exist */ + Assert(childRTindex < root->simple_rel_array_size); + childrte = root->simple_rte_array[childRTindex]; + Assert(childrte != NULL); - /* Nothing more to do for an unpartitioned table. */ - if (!rel->part_scheme) - continue; + /* build child RelOptInfo, and add to main query data structures */ + childrel = build_simple_rel(root, childRTindex, rel); - /* - * The order of partition OIDs in append_rel_list is the same as - * the order in the PartitionDesc, so the order of part_rels will - * also match the PartitionDesc. See expand_partitioned_rtentry. - */ - Assert(cnt_parts < nparts); - rel->part_rels[cnt_parts] = childrel; - cnt_parts++; + /* + * If rel is a partitioned table, fill in the part_rels array. The + * order in which child tables appear in append_rel_list is the same + * as the order in which they appear in the parent's PartitionDesc, so + * assigning partitions like this works. + */ + if (rel->part_scheme != NULL) + { + Assert(cnt_parts < rel->nparts); + rel->part_rels[cnt_parts++] = childrel; } - /* We should have seen all the child partitions. */ - Assert(cnt_parts == nparts); + /* Child may itself be an inherited relation. */ + if (childrte->inh) + { + /* Only relation and subquery RTEs can have children. */ + Assert(childrte->rtekind == RTE_RELATION || + childrte->rtekind == RTE_SUBQUERY); + add_appendrel_other_rels(root, childrel, childRTindex); + } } - return rel; + /* We should have filled all of the part_rels array if it's partitioned */ + Assert(cnt_parts == rel->nparts); } /* |