aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/relnode.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2019-03-26 18:21:10 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2019-03-26 18:21:10 -0400
commit53bcf5e3dbeaed5baf9d09b124cf196d247c54ea (patch)
tree43e4de499207a59f6a557bce2638d5f4a2364ceb /src/backend/optimizer/util/relnode.c
parent8994cc6ffc8828569a39139996a0b0b8348ca036 (diff)
downloadpostgresql-53bcf5e3dbeaed5baf9d09b124cf196d247c54ea.tar.gz
postgresql-53bcf5e3dbeaed5baf9d09b124cf196d247c54ea.zip
Build "other rels" of appendrel baserels in a separate step.
Up to now, otherrel RelOptInfos were built at the same time as baserel RelOptInfos, thanks to recursion in build_simple_rel(). However, nothing in query_planner's preprocessing cares at all about otherrels, only baserels, so we don't really need to build them until just before we enter make_one_rel. This has two benefits: * create_lateral_join_info did a lot of extra work to propagate lateral-reference information from parents to the correct children. But if we delay creation of the children till after that, it's trivial (and much harder to break, too). * Since we have all the restriction quals correctly assigned to parent appendrels by this point, it'll be possible to do plan-time pruning and never make child RelOptInfos at all for partitions that can be pruned away. That's not done here, but will be later on. Amit Langote, reviewed at various times by Dilip Kumar, Jesper Pedersen, Yoshikazu Imai, and David Rowley Discussion: https://postgr.es/m/9d7c5112-cb99-6a47-d3be-cf1ee6862a1d@lab.ntt.co.jp
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);
}
/*