/*
* The child rel's RelOptInfo was already created during
- * add_base_rels_to_query.
+ * add_other_rels_to_query.
*/
childrel = find_base_rel(root, childRTindex);
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
* add_base_rels_to_query
*
* Scan the query's jointree and create baserel RelOptInfos for all
- * the base relations (ie, table, subquery, and function RTEs)
+ * the base relations (e.g., table, subquery, and function RTEs)
* appearing in the jointree.
*
* The initial invocation must pass root->parse->jointree as the value of
* jtnode. Internally, the function recurses through the jointree.
*
* At the end of this process, there should be one baserel RelOptInfo for
- * every non-join RTE that is used in the query. Therefore, this routine
- * is the only place that should call build_simple_rel with reloptkind
- * RELOPT_BASEREL. (Note: build_simple_rel recurses internally to build
- * "other rel" RelOptInfos for the members of any appendrels we find here.)
+ * every non-join RTE that is used in the query. Some of the baserels
+ * may be appendrel parents, which will require additional "otherrel"
+ * RelOptInfos for their member rels, but those are added later.
*/
void
add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
(int) nodeTag(jtnode));
}
+/*
+ * add_other_rels_to_query
+ * create "otherrel" RelOptInfos for the children of appendrel baserels
+ *
+ * At the end of this process, there should be RelOptInfos for all relations
+ * that will be scanned by the query.
+ */
+void
+add_other_rels_to_query(PlannerInfo *root)
+{
+ int rti;
+
+ for (rti = 1; rti < root->simple_rel_array_size; rti++)
+ {
+ RelOptInfo *rel = root->simple_rel_array[rti];
+ RangeTblEntry *rte = root->simple_rte_array[rti];
+
+ /* there may be empty slots corresponding to non-baserel RTEs */
+ if (rel == NULL)
+ continue;
+
+ /* Ignore any "otherrels" that were already added. */
+ if (rel->reloptkind != RELOPT_BASEREL)
+ continue;
+
+ /* If it's marked as inheritable, look for children. */
+ if (rte->inh)
+ {
+ /* Only relation and subquery RTEs can have children. */
+ Assert(rte->rtekind == RTE_RELATION ||
+ rte->rtekind == RTE_SUBQUERY);
+ add_appendrel_other_rels(root, rel, rti);
+ }
+ }
+}
+
/*****************************************************************************
*
create_lateral_join_info(PlannerInfo *root)
{
bool found_laterals = false;
- Relids prev_parents PG_USED_FOR_ASSERTS_ONLY = NULL;
Index rti;
ListCell *lc;
bms_add_member(brel2->lateral_referencers, rti);
}
}
-
- /*
- * Lastly, propagate lateral_relids and lateral_referencers 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 must be propagated all the way down.
- * This code handles that case correctly so long as append_rel_list has
- * entries for child relationships before grandchild relationships, which
- * is an okay assumption right now, but we'll need to be careful to
- * preserve it. The assertions below check for incorrect ordering.
- */
- foreach(lc, root->append_rel_list)
- {
- AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
- RelOptInfo *parentrel = root->simple_rel_array[appinfo->parent_relid];
- RelOptInfo *childrel = root->simple_rel_array[appinfo->child_relid];
-
- /*
- * If we're processing a subquery of a query with inherited target rel
- * (cf. inheritance_planner), append_rel_list may contain entries for
- * tables that are not part of the current subquery and hence have no
- * RelOptInfo. Ignore them. We can ignore dead rels, too.
- */
- if (parentrel == NULL || !IS_SIMPLE_REL(parentrel))
- continue;
-
- /* Verify that children are processed before grandchildren */
-#ifdef USE_ASSERT_CHECKING
- prev_parents = bms_add_member(prev_parents, appinfo->parent_relid);
- Assert(!bms_is_member(appinfo->child_relid, prev_parents));
-#endif
-
- /* OK, propagate info down */
- Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
- Assert(childrel->direct_lateral_relids == NULL);
- childrel->direct_lateral_relids = parentrel->direct_lateral_relids;
- Assert(childrel->lateral_relids == NULL);
- childrel->lateral_relids = parentrel->lateral_relids;
- Assert(childrel->lateral_referencers == NULL);
- childrel->lateral_referencers = parentrel->lateral_referencers;
- }
}
setup_append_rel_array(root);
/*
- * Construct RelOptInfo nodes for all base relations in query, and
- * indirectly for all appendrel member relations ("other rels"). This
- * will give us a RelOptInfo for every "simple" (non-join) rel involved in
- * the query.
+ * Construct RelOptInfo nodes for all base relations used in the query.
+ * Appendrel member relations ("other rels") will be added later.
*
- * Note: the reason we find the rels by searching the jointree and
- * appendrel list, rather than just scanning the rangetable, is that the
- * rangetable may contain RTEs for rels not actively part of the query,
- * for example views. We don't want to make RelOptInfos for them.
+ * Note: the reason we find the baserels by searching the jointree, rather
+ * than scanning the rangetable, is that the rangetable may contain RTEs
+ * for rels not actively part of the query, for example views. We don't
+ * want to make RelOptInfos for them.
*/
add_base_rels_to_query(root, (Node *) parse->jointree);
*/
extract_restriction_or_clauses(root);
+ /*
+ * Now expand appendrels by adding "otherrels" for their children. We
+ * delay this to the end so that we have as much information as possible
+ * available for each baserel, including all restriction clauses. That
+ * let us prune away partitions that don't satisfy a restriction clause.
+ * Also note that some information such as lateral_relids is propagated
+ * from baserels to otherrels here, so we must have computed it already.
+ */
+ add_other_rels_to_query(root);
+
/*
* Ready to do the primary planning.
*/
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;
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)
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);
}
/*
extern void setup_append_rel_array(PlannerInfo *root);
extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid,
RelOptInfo *parent);
+extern void add_appendrel_other_rels(PlannerInfo *root, RelOptInfo *rel,
+ Index rti);
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,
extern int join_collapse_limit;
extern void add_base_rels_to_query(PlannerInfo *root, Node *jtnode);
+extern void add_other_rels_to_query(PlannerInfo *root);
extern void build_base_rel_tlists(PlannerInfo *root, List *final_tlist);
extern void add_vars_to_targetlist(PlannerInfo *root, List *vars,
Relids where_needed, bool create_new_ph);