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.c132
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);
}
/*