v3-0004-WIP-generate-all-inheritance-child-RelOptInfos-af.patch
text/plain
Filename: v3-0004-WIP-generate-all-inheritance-child-RelOptInfos-af.patch
Type: text/plain
Part: 3
Patch
Format: format-patch
Series: patch v3-0004
Subject: WIP: generate *all* inheritance child RelOptInfos after pruning
| File | + | − |
|---|---|---|
| src/backend/optimizer/path/allpaths.c | 82 | 127 |
| src/backend/optimizer/plan/initsplan.c | 23 | 34 |
| src/backend/optimizer/plan/planner.c | 17 | 14 |
| src/backend/optimizer/prep/prepunion.c | 256 | 221 |
| src/backend/optimizer/util/plancat.c | 21 | 37 |
| src/backend/optimizer/util/relnode.c | 189 | 103 |
| src/backend/partitioning/partprune.c | 2 | 3 |
| src/include/optimizer/pathnode.h | 8 | 1 |
| src/include/optimizer/plancat.h | 6 | 3 |
| src/include/optimizer/prep.h | 16 | 12 |
From 45334d7f43033adbc9682d0cbb549301d2c4366d Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 13 Sep 2018 15:11:46 +0900
Subject: [PATCH v3 4/4] WIP: generate *all* inheritance child RelOptInfos
after pruning
---
src/backend/optimizer/path/allpaths.c | 209 ++++++---------
src/backend/optimizer/plan/initsplan.c | 57 ++--
src/backend/optimizer/plan/planner.c | 31 ++-
src/backend/optimizer/prep/prepunion.c | 477 ++++++++++++++++++---------------
src/backend/optimizer/util/plancat.c | 58 ++--
src/backend/optimizer/util/relnode.c | 292 +++++++++++++-------
src/backend/partitioning/partprune.c | 5 +-
src/include/optimizer/pathnode.h | 9 +-
src/include/optimizer/plancat.h | 9 +-
src/include/optimizer/prep.h | 28 +-
10 files changed, 620 insertions(+), 555 deletions(-)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index e54cccd077..21723e7cdc 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -367,8 +367,23 @@ static void
set_rel_size(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte)
{
+
+ /*
+ * Check if the relation's constraints contradict the clauses matched
+ * to it. Only plain relations have constraints. In a partitioning
+ * hierarchy, but not with regular table inheritance, it's OK to assume
+ * that any constraints that hold for the parent also hold for every
+ * child; for instance, table inheritance allows the parent to have
+ * constraints marked NO INHERIT, but table partitioning does not. We
+ * choose to check whether the partitioning parents can be excluded here;
+ * doing so consumes some cycles, but potentially saves us the work of
+ * excluding each child individually.
+ */
if (rel->reloptkind == RELOPT_BASEREL &&
- relation_excluded_by_constraints(root, rel, rte))
+ rte->rtekind == RTE_RELATION &&
+ (!rte->inh || rte->relkind == RELKIND_PARTITIONED_TABLE) &&
+ relation_excluded_by_constraints(root, rel->baserestrictinfo,
+ rti, rte->relid, false))
{
/*
* We proved we don't need to scan the rel via constraint exclusion,
@@ -916,11 +931,7 @@ static void
set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte)
{
- Relids top_parent_relids = rel->top_parent_relids;
int parentRTindex = rti;
- int rootParentRTindex = top_parent_relids ?
- bms_singleton_member(top_parent_relids) :
- parentRTindex;
bool has_live_children;
double parent_rows;
double parent_size;
@@ -951,6 +962,17 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
*/
prune_append_rel_partitions(root, rel);
}
+ else
+ {
+ expand_inherited_rtentry(root, rel, rte, rti);
+ if (IS_DUMMY_REL(rel))
+ return;
+ if (!rte->inh)
+ {
+ set_rel_size(root, rel, rti, rte);
+ return;
+ }
+ }
/*
* If this is a partitioned baserel, set the consider_partitionwise_join
@@ -989,9 +1011,9 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
int childRTindex;
RangeTblEntry *childRTE;
RelOptInfo *childrel;
- List *childquals;
+ List *childquals = NIL;
+ bool have_const_false_cq = false;
Index cq_min_security;
- bool have_const_false_cq;
ListCell *parentvars;
ListCell *childvars;
ListCell *lc;
@@ -1004,53 +1026,23 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
childRTE = root->simple_rte_array[childRTindex];
/*
- * The child rel's RelOptInfo was already created during
- * add_base_rels_to_query.
+ * The child rel's RelOptInfo may not have been created in some
+ * cases, for example, if it is not a partition.
*/
- childrel = find_base_rel(root, childRTindex);
+ childrel = root->simple_rel_array[childRTindex];
+ if (childrel == NULL)
+ childrel = build_inheritance_child_rel(root, childRTindex, rel);
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
- /*
- * We have to make child entries in the EquivalenceClass data
- * structures as well. This is needed either if the parent
- * participates in some eclass joins (because we will want to consider
- * inner-indexscan joins on the individual children) or if the parent
- * has useful pathkeys (because we should try to build MergeAppend
- * paths that produce those sort orderings). Even if this child is
- * deemed dummy, it may fall on nullable side in a child-join, which
- * in turn may participate in a MergeAppend, where we will need the
- * EquivalenceClass data structures.
- */
- if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
- add_child_rel_equivalences(root, appinfo, rel, childrel);
- childrel->has_eclass_joins = rel->has_eclass_joins;
-
- /*
- * We have to copy the parent's quals to the child, with appropriate
- * substitution of variables. However, only the baserestrictinfo
- * quals are needed before we can check for constraint exclusion; so
- * do that first and then check to see if we can disregard this child.
- *
- * The child rel's targetlist might contain non-Var expressions, which
- * means that substitution into the quals could produce opportunities
- * for const-simplification, and perhaps even pseudoconstant quals.
- * Therefore, transform each RestrictInfo separately to see if it
- * reduces to a constant or pseudoconstant. (We must process them
- * separately to keep track of the security level of each qual.)
- */
- childquals = NIL;
- cq_min_security = UINT_MAX;
- have_const_false_cq = false;
+ /* Convert parent's baserestrictinfo to store into childrel. */
foreach(lc, rel->baserestrictinfo)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
- Node *childqual;
+ Node *childqual = (Node *) rinfo->clause;
ListCell *lc2;
Assert(IsA(rinfo, RestrictInfo));
- childqual = adjust_appendrel_attrs(root,
- (Node *) rinfo->clause,
- 1, &appinfo);
+ childqual = adjust_appendrel_attrs(root, childqual, 1, &appinfo);
childqual = eval_const_expressions(root, childqual);
/* check for flat-out constant */
if (childqual && IsA(childqual, Const))
@@ -1082,13 +1074,12 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
}
/* reconstitute RestrictInfo with appropriate properties */
childquals = lappend(childquals,
- make_restrictinfo((Expr *) onecq,
- rinfo->is_pushed_down,
- rinfo->outerjoin_delayed,
- pseudoconstant,
- rinfo->security_level,
- NULL, NULL, NULL));
- /* track minimum security level among child quals */
+ make_restrictinfo((Expr *) onecq,
+ rinfo->is_pushed_down,
+ rinfo->outerjoin_delayed,
+ pseudoconstant,
+ rinfo->security_level,
+ NULL, NULL, NULL));
cq_min_security = Min(cq_min_security, rinfo->security_level);
}
}
@@ -1106,6 +1097,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
*/
if (childRTE->securityQuals)
{
+ List *security_quals = NIL;
Index security_level = 0;
foreach(lc, childRTE->securityQuals)
@@ -1118,16 +1110,37 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
Expr *qual = (Expr *) lfirst(lc2);
/* not likely that we'd see constants here, so no check */
- childquals = lappend(childquals,
- make_restrictinfo(qual,
- true, false, false,
- security_level,
- NULL, NULL, NULL));
+ security_quals = lappend(security_quals,
+ make_restrictinfo(qual,
+ true, false,
+ false,
+ security_level,
+ NULL, NULL,
+ NULL));
cq_min_security = Min(cq_min_security, security_level);
}
security_level++;
}
Assert(security_level <= root->qual_security_level);
+
+ /* Concatenate with parent's quals. */
+ childquals = list_concat(childquals, security_quals);
+ }
+
+ /*
+ * Check if any of the security quals contradict table
+ * constraints.
+ */
+ if (have_const_false_cq ||
+ (childRTE->rtekind == RTE_RELATION &&
+ relation_excluded_by_constraints(root, childquals,
+ childRTindex,
+ childRTE->relid,
+ true)))
+ {
+ childrel->reltarget = copy_pathtarget(rel->reltarget);
+ set_dummy_rel_pathlist(childrel);
+ continue;
}
/*
@@ -1137,77 +1150,19 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
childrel->baserestrict_min_security = cq_min_security;
/*
- * Mark the child as empty in certain cases, such as if a restriction
- * clause reduced to constant FALSE or NULL, or if constaint exclusion
- * pruned it.
+ * We have to make child entries in the EquivalenceClass data
+ * structures as well. This is needed either if the parent
+ * participates in some eclass joins (because we will want to consider
+ * inner-indexscan joins on the individual children) or if the parent
+ * has useful pathkeys (because we should try to build MergeAppend
+ * paths that produce those sort orderings). Even if this child is
+ * deemed dummy, it may fall on nullable side in a child-join, which
+ * in turn may participate in a MergeAppend, where we will need the
+ * EquivalenceClass data structures.
*/
- if (have_const_false_cq ||
- relation_excluded_by_constraints(root, childrel, childRTE))
- {
- /*
- * The child relation won't be scanned, but certain partitionwise
- * planning operations require its reltarget to contain valid
- * expressions, so oblige.
- */
- childrel->reltarget->exprs = (List *)
- adjust_appendrel_attrs(root,
- (Node *) rel->reltarget->exprs,
- 1, &appinfo);
-
- set_dummy_rel_pathlist(childrel);
- continue;
- }
-
- /*
- * Copy/Modify targetlist. Even if this child is deemed empty, we need
- * its targetlist in case it falls on nullable side in a child-join
- * because of partitionwise join.
- *
- * NB: the resulting childrel->reltarget->exprs may contain arbitrary
- * expressions, which otherwise would not occur in a rel's targetlist.
- * Code that might be looking at an appendrel child must cope with
- * such. (Normally, a rel's targetlist would only include Vars and
- * PlaceHolderVars.) XXX we do not bother to update the cost or width
- * fields of childrel->reltarget; not clear if that would be useful.
- */
- if (rootParentRTindex == root->parse->resultRelation)
- {
- Query *parse,
- *orig_parse = root->parse;
- List *tlist;
- List *other_exprs;
- ListCell *lc2;
-
- parse = (Query *)
- adjust_appendrel_attrs(root,
- (Node *) root->parse,
- 1, &appinfo);
- root->parse = parse;
- tlist = preprocess_targetlist(root);
- build_base_rel_tlists(root, tlist);
- root->parse = orig_parse;
-
- /*
- * Now add members of parent's reltarget->exprs, not already in
- * child's.
- */
- other_exprs = (List *)
- adjust_appendrel_attrs(root,
- (Node *) rel->reltarget->exprs,
- 1, &appinfo);
- foreach(lc2, other_exprs)
- {
- if (!list_member(childrel->reltarget->exprs, lfirst(lc2)))
- childrel->reltarget->exprs =
- lappend(childrel->reltarget->exprs,
- lfirst(lc2));
- }
- }
- else
- childrel->reltarget->exprs = (List *)
- adjust_appendrel_attrs(root,
- (Node *) rel->reltarget->exprs,
- 1, &appinfo);
+ if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
+ add_child_rel_equivalences(root, appinfo, rel, childrel);
+ childrel->has_eclass_joins = rel->has_eclass_joins;
/* CE failed, so finish copying/modifying join quals. */
childrel->joininfo = (List *)
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index beb3e95101..e7927cc136 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -16,6 +16,7 @@
#include "catalog/pg_type.h"
#include "catalog/pg_class.h"
+#include "catalog/pg_inherits.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
@@ -145,47 +146,29 @@ add_rel_partitions_to_query(PlannerInfo *root, RelOptInfo *rel,
bool scan_all_parts,
Bitmapset *partindexes)
{
- int new_size;
- int num_added_parts;
- int i;
+ int i;
+ Index rootRTindex;
+ PlanRowMark *rootrc = NULL;
- Assert(partindexes != NULL || scan_all_parts);
+ rootRTindex = get_inheritance_root_parent(root, rel);
+ if (root->rowMarks)
+ rootrc = get_plan_rowmark(root->rowMarks, rootRTindex);
- /* Expand the PlannerInfo arrays to hold new partition objects. */
- num_added_parts = scan_all_parts ? rel->nparts :
- bms_num_members(partindexes);
- new_size = root->simple_rel_array_size + num_added_parts;
- root->simple_rte_array = (RangeTblEntry **)
- repalloc(root->simple_rte_array,
- sizeof(RangeTblEntry *) * new_size);
- root->simple_rel_array = (RelOptInfo **)
- repalloc(root->simple_rel_array,
- sizeof(RelOptInfo *) * new_size);
- if (root->append_rel_array)
- root->append_rel_array = (AppendRelInfo **)
- repalloc(root->append_rel_array,
- sizeof(AppendRelInfo *) * new_size);
- else
- root->append_rel_array = (AppendRelInfo **)
- palloc0(sizeof(AppendRelInfo *) *
- new_size);
+ expand_planner_arrays_for_inheritance(root,
+ scan_all_parts ? rel->nparts :
+ bms_num_members(partindexes));
- /* Set the contents of just allocated memory to 0. */
- MemSet(root->simple_rte_array + root->simple_rel_array_size,
- 0, sizeof(RangeTblEntry *) * num_added_parts);
- MemSet(root->simple_rel_array + root->simple_rel_array_size,
- 0, sizeof(RelOptInfo *) * num_added_parts);
- MemSet(root->append_rel_array + root->simple_rel_array_size,
- 0, sizeof(AppendRelInfo *) * num_added_parts);
- root->simple_rel_array_size = new_size;
-
- /* And add the partitions. */
+ /* And add the partitions to the relation. */
+ rel->part_rels = (RelOptInfo **)
+ palloc0(sizeof(RelOptInfo *) * rel->nparts);
if (scan_all_parts)
{
for (i = 0; i < rel->nparts; i++)
{
rel->part_rels[i] = build_partition_rel(root, rel,
- rel->part_oids[i]);
+ rel->part_oids[i],
+ rootRTindex,
+ rootrc);
rel->live_parts = bms_add_member(rel->live_parts, i);
}
}
@@ -195,8 +178,12 @@ add_rel_partitions_to_query(PlannerInfo *root, RelOptInfo *rel,
i = -1;
while ((i = bms_next_member(partindexes, i)) >= 0)
rel->part_rels[i] = build_partition_rel(root, rel,
- rel->part_oids[i]);
+ rel->part_oids[i],
+ rootRTindex,
+ rootrc);
}
+
+
}
/*****************************************************************************
@@ -683,6 +670,7 @@ create_lateral_join_info(PlannerInfo *root)
}
}
+#ifdef NOT_USED
/*
* Lastly, propagate lateral_relids and lateral_referencers from appendrel
* parent rels to their child rels. We intentionally give each child rel
@@ -740,6 +728,7 @@ create_lateral_join_info(PlannerInfo *root)
}
}
}
+#endif
}
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a757aba551..556eb64ae4 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -713,16 +713,6 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
preprocess_rowmarks(root);
/*
- * Expand any rangetable entries that are inheritance sets into "append
- * relations". This can add entries to the rangetable, but they must be
- * plain base relations not joins, so it's OK (and marginally more
- * efficient) to do it after checking for join RTEs. We must do it after
- * pulling up subqueries, else we'd fail to handle inherited tables in
- * subqueries.
- */
- expand_inherited_tables(root);
-
- /*
* Set hasHavingQual to remember if HAVING clause is present. Needed
* because preprocess_expression will reduce a constant-true condition to
* an empty qual list ... but "HAVING TRUE" is not a semantic no-op.
@@ -2369,7 +2359,7 @@ preprocess_rowmarks(PlannerInfo *root)
newrc->allMarkTypes = (1 << newrc->markType);
newrc->strength = rc->strength;
newrc->waitPolicy = rc->waitPolicy;
- newrc->isParent = false;
+ newrc->isParent = has_subclass(rte->relid);
prowmarks = lappend(prowmarks, newrc);
}
@@ -2394,7 +2384,9 @@ preprocess_rowmarks(PlannerInfo *root)
newrc->allMarkTypes = (1 << newrc->markType);
newrc->strength = LCS_NONE;
newrc->waitPolicy = LockWaitBlock; /* doesn't matter */
- newrc->isParent = false;
+ newrc->isParent = rte->rtekind == RTE_RELATION ?
+ has_subclass(rte->relid) :
+ false;
prowmarks = lappend(prowmarks, newrc);
}
@@ -5871,8 +5863,19 @@ plan_create_index_workers(Oid tableOid, Oid indexOid)
rte->inFromCl = true;
query->rtable = list_make1(rte);
- /* Set up RTE/RelOptInfo arrays */
- setup_simple_rel_arrays(root);
+ /* Set up RTE/RelOptInfo arrays. */
+
+ /* Arrays are accessed using RT indexes (1..N) */
+ root->simple_rel_array_size = list_length(query->rtable) + 1;
+
+ /* simple_rel_array is initialized to all NULLs */
+ root->simple_rel_array = (RelOptInfo **)
+ palloc0(root->simple_rel_array_size * sizeof(RelOptInfo *));
+
+ /* simple_rte_array is an array equivalent of the rtable list */
+ root->simple_rte_array = (RangeTblEntry **)
+ palloc0(root->simple_rel_array_size * sizeof(RangeTblEntry *));
+ root->simple_rte_array[1] = rte;
/* Build RelOptInfo */
rel = build_simple_rel(root, 1, NULL);
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 4d9583e63b..400568a9e7 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -39,15 +39,20 @@
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
+#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
+#include "optimizer/plancat.h"
#include "optimizer/planmain.h"
#include "optimizer/planner.h"
#include "optimizer/prep.h"
+#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
+#include "optimizer/var.h"
#include "parser/parse_coerce.h"
#include "parser/parsetree.h"
+#include "rewrite/rewriteManip.h"
#include "utils/lsyscache.h"
#include "utils/lsyscache.h"
#include "utils/partcache.h"
@@ -101,12 +106,6 @@ static List *generate_append_tlist(List *colTypes, List *colCollations,
List *input_tlists,
List *refnames_tlist);
static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist);
-static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
- Index rti);
-static void make_inh_translation_list(TupleDesc old_tupdesc,
- TupleDesc new_tupdesc,
- RangeTblEntry *oldrte, RangeTblEntry *newrte,
- Index newvarno, List **translated_vars);
static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
List *translated_vars);
static Node *adjust_appendrel_attrs_mutator(Node *node,
@@ -1452,37 +1451,6 @@ generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
return grouplist;
}
-
-/*
- * expand_inherited_tables
- * Expand each rangetable entry that represents an inheritance set
- * into an "append relation". At the conclusion of this process,
- * the "inh" flag is set in all and only those RTEs that are append
- * relation parents.
- */
-void
-expand_inherited_tables(PlannerInfo *root)
-{
- Index nrtes;
- Index rti;
- ListCell *rl;
-
- /*
- * expand_inherited_rtentry may add RTEs to parse->rtable. The function is
- * expected to recursively handle any RTEs that it creates with inh=true.
- * So just scan as far as the original end of the rtable list.
- */
- nrtes = list_length(root->parse->rtable);
- rl = list_head(root->parse->rtable);
- for (rti = 1; rti <= nrtes; rti++)
- {
- RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
-
- expand_inherited_rtentry(root, rte, rti);
- rl = lnext(rl);
- }
-}
-
/*
* expand_inherited_rtentry
* Check whether a rangetable entry represents an inheritance set.
@@ -1503,30 +1471,34 @@ expand_inherited_tables(PlannerInfo *root)
* Since a partitioned table is not scanned, it might have only one associated
* AppendRelInfo.
*/
-static void
-expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
+void
+expand_inherited_rtentry(PlannerInfo *root,
+ RelOptInfo *rel,
+ RangeTblEntry *rte,
+ Index rti)
{
Query *parse = root->parse;
- Oid parentOID;
PlanRowMark *oldrc;
- Relation oldrelation;
LOCKMODE lockmode;
List *inhOIDs;
- ListCell *l;
- List *appinfos = NIL;
+ ListCell *l,
+ *l2;
+ List *childrtes = NIL,
+ *appinfos = NIL;
+ int num_children = 0;
- /* Does RT entry allow inheritance? */
- if (!rte->inh)
+ Assert(rte->inh);
+ /* Inheritance parent or UNION ALL parent query. */
+ Assert(rte->rtekind == RTE_RELATION || rte->rtekind == RTE_SUBQUERY);
+ /* No partitioned tables though. */
+ Assert(rte->relkind != RELKIND_PARTITIONED_TABLE);
+
+ /* Nothing to do for already-expanded UNION ALL nodes. */
+ if (rte->rtekind == RTE_SUBQUERY)
return;
- /* Ignore any already-expanded UNION ALL nodes */
- if (rte->rtekind != RTE_RELATION)
- {
- Assert(rte->rtekind == RTE_SUBQUERY);
- return;
- }
+
/* Fast path for common case of childless table */
- parentOID = rte->relid;
- if (!has_subclass(parentOID))
+ if (!has_subclass(rte->relid))
{
/* Clear flag before returning */
rte->inh = false;
@@ -1555,15 +1527,14 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
lockmode = AccessShareLock;
/* Scan for all members of inheritance set, acquire needed locks */
- if (rte->relkind != RELKIND_PARTITIONED_TABLE)
- inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
+ inhOIDs = find_all_inheritors(rte->relid, lockmode, NULL);
/*
* Check that there's at least one descendant, else treat as no-child
* case. This could happen despite above has_subclass() check, if table
* once had a child but no longer does.
*/
- if (rte->relkind != RELKIND_PARTITIONED_TABLE && list_length(inhOIDs) < 2)
+ if (list_length(inhOIDs) < 2)
{
/* Clear flag before returning */
rte->inh = false;
@@ -1578,33 +1549,145 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
if (oldrc)
oldrc->isParent = true;
- /* Partitioned tables are expanded elsewhere. */
- if (rte->relkind == RELKIND_PARTITIONED_TABLE)
- return;
-
- /*
- * Must open the parent relation to examine its tupdesc. We need not lock
- * it; we assume the rewriter already did.
- */
- oldrelation = heap_open(parentOID, NoLock);
-
foreach(l, inhOIDs)
{
Oid childOID = lfirst_oid(l);
+ Relation childrel;
Index childRTindex = 0;
RangeTblEntry *childrte = NULL;
- AppendRelInfo *appinfo = NULL;
+ AppendRelInfo *appinfo;
+ List *childquals;
+ bool have_const_false_cq;
+ ListCell *lc;
- add_inheritance_child_to_query(root, rte, rti,
- oldrelation->rd_rel->reltype,
- RelationGetDescr(oldrelation),
- oldrc, childOID, NoLock,
- &appinfo, &childrte,
- &childRTindex, NULL);
+ /* find_all_inheritors already locked. */
+ childrel = heap_open(childOID, NoLock);
+
+ /*
+ * If childrel doesn't belong to this session, skip it, also
+ * relinquishing the lock.
+ */
+ if (RELATION_IS_OTHER_TEMP(childrel))
+ {
+ heap_close(childrel, lockmode);
+ continue;
+ }
+
+ /*
+ * Initialize the AppendRelInfo that's used to map the child to its
+ * parent in subsequent planning steps.
+ */
+ appinfo = makeNode(AppendRelInfo);
+ appinfo->parent_relid = rti;
+
+ /*
+ * We'll replace it with childRTindex once we're done adding the child
+ * to the range table.
+ */
+ appinfo->child_relid = rti;
+ appinfo->parent_reltype = rel->reltype;
+ appinfo->child_reltype = childrel->rd_rel->reltype;
+ make_inh_translation_list(rel->tupdesc,
+ RelationGetDescr(childrel),
+ rte->relid, childOID, rti,
+ &appinfo->translated_vars);
+ appinfo->parent_reloid = rte->relid;
+
+ /*
+ * Check if we don't need to include this child based on whether its
+ * constraints contradict query's quals. For a child that's not same
+ * as the parent, we'll need to convert the quals' Vars so that they
+ * contain child's attribute numbers.
+ */
+ childquals = NIL;
+ have_const_false_cq = false;
+ foreach(lc, rel->baserestrictinfo)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+ Node *childqual = (Node *) rinfo->clause;
+ ListCell *lc2;
+
+ Assert(IsA(rinfo, RestrictInfo));
+ if (childOID != rte->relid)
+ childqual = adjust_appendrel_attrs(root, childqual,
+ 1, &appinfo);
+ childqual = eval_const_expressions(root, childqual);
+ /* check for flat-out constant */
+ if (childqual && IsA(childqual, Const))
+ {
+ if (((Const *) childqual)->constisnull ||
+ !DatumGetBool(((Const *) childqual)->constvalue))
+ {
+ /* Restriction reduces to constant FALSE or NULL */
+ have_const_false_cq = true;
+ break;
+ }
+ /* Restriction reduces to constant TRUE, so drop it */
+ continue;
+ }
+ /* might have gotten an AND clause, if so flatten it */
+ foreach(lc2, make_ands_implicit((Expr *) childqual))
+ {
+ Node *onecq = (Node *) lfirst(lc2);
+ bool pseudoconstant;
+
+ /* check for pseudoconstant (no Vars or volatile functions) */
+ pseudoconstant =
+ !contain_vars_of_level(onecq, 0) &&
+ !contain_volatile_functions(onecq);
+ if (pseudoconstant)
+ {
+ /* tell createplan.c to check for gating quals */
+ root->hasPseudoConstantQuals = true;
+ }
+ /* reconstitute RestrictInfo with appropriate properties */
+ childquals = lappend(childquals,
+ make_restrictinfo((Expr *) onecq,
+ rinfo->is_pushed_down,
+ rinfo->outerjoin_delayed,
+ pseudoconstant,
+ rinfo->security_level,
+ NULL, NULL, NULL));
+ }
+ }
+
+ /*
+ * Mark the child as empty in certain cases, such as if a restriction
+ * clause reduced to constant FALSE or NULL, or if constaint exclusion
+ * pruned it. Note that we pass 'rti' for RT index that will be used
+ * to initialize constraint expressions, because we haven't initialized
+ * one for child yet.
+ */
+ if (have_const_false_cq ||
+ relation_excluded_by_constraints(root, childquals, rti, childOID,
+ true))
+ {
+ heap_close(childrel, NoLock);
+ continue;
+ }
+
+ childRTindex = add_inheritance_child_to_query(root, rte, childrel,
+ appinfo, oldrc,
+ &childrte);
+ heap_close(childrel, NoLock);
+
+ /* Fix up the AppendRelInfo using the child's actual RT index. */
Assert(childRTindex > 1);
- Assert(childrte != NULL);
- Assert(appinfo != NULL);
+ appinfo->child_relid = childRTindex;
+ ChangeVarNodes((Node *) appinfo->translated_vars, rti, childRTindex, 0);
+
+ /* Will be added to planner arrays below. */
+ childrtes = lappend(childrtes, childrte);
appinfos = lappend(appinfos, appinfo);
+
+ /* We'll scan this child. */
+ num_children++;
+ }
+
+ if (num_children == 0)
+ {
+ set_dummy_rel_pathlist(rel);
+ return;
}
/*
@@ -1620,95 +1703,28 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
root->append_rel_list = list_concat(root->append_rel_list,
appinfos);
- heap_close(oldrelation, NoLock);
+ expand_planner_arrays_for_inheritance(root, num_children);
+ forboth(l, childrtes, l2, appinfos)
+ {
+ RangeTblEntry *childrte = lfirst(l);
+ AppendRelInfo *appinfo = lfirst(l2);
+
+ Assert(appinfo->child_relid < root->simple_rel_array_size);
+ root->simple_rte_array[appinfo->child_relid] = childrte;
+ root->append_rel_array[appinfo->child_relid] = appinfo;
+ }
}
-/*
- * add_inheritance_child_to_query
- * Build a RangeTblEntry and an AppendRelInfo, if appropriate, plus
- * maybe a PlanRowMark for a child relation.
- *
- * We now expand the partition hierarchy level by level, creating a
- * corresponding hierarchy of AppendRelInfos and RelOptInfos, where each
- * partitioned descendant acts as a parent of its immediate partitions.
- * (This is a difference from what older versions of PostgreSQL did and what
- * is still done in the case of table inheritance for unpartitioned tables,
- * where the hierarchy is flattened during RTE expansion.)
- *
- * PlanRowMarks still carry the top-parent's RTI, and the top-parent's
- * allMarkTypes field still accumulates values from all descendents.
- *
- * "parentrte" and "parentRTindex" are immediate parent's RTE and
- * RTI. "top_parentrc" is top parent's PlanRowMark.
- *
- * The child RangeTblEntry and its RTI are returned in "childrte_p" and
- * "childRTindex_p" resp.
- */
-void
-add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
- Index parentRTindex, Oid parentRelType,
- TupleDesc parentDesc,
+Index
+add_inheritance_child_to_query(PlannerInfo *root,
+ RangeTblEntry *parentrte,
+ Relation childrel,
+ AppendRelInfo *appinfo,
PlanRowMark *top_parentrc,
- Oid childOID, int lockmode,
- AppendRelInfo **appinfo_p,
- RangeTblEntry **childrte_p,
- Index *childRTindex_p,
- PlanRowMark **child_rowmark)
+ RangeTblEntry **childrte_p)
{
- Query *parse = root->parse;
- Oid parentOID = parentrte->relid;
+ Query *parse = root->parse;
RangeTblEntry *childrte;
- Index childRTindex;
- AppendRelInfo *appinfo;
- Relation childrel = NULL;
- char child_relkind;
- Oid child_reltype;
- TupleDesc childDesc;
-
- *appinfo_p = NULL;
- *childrte_p = NULL;
- *childRTindex_p = 0;
-
- /* Open rel if needed; we already have required locks */
- if (childOID != parentOID)
- {
- childrel = heap_open(childOID, lockmode);
-
- /*
- * Temporary partitions belonging to other sessions should have been
- * disallowed at definition, but for paranoia's sake, let's double
- * check.
- */
- if (RELATION_IS_OTHER_TEMP(childrel))
- {
- if (childrel->rd_rel->relispartition)
- elog(ERROR, "temporary relation from another session found as partition");
- heap_close(childrel, lockmode);
- return;
- }
-
- child_relkind = childrel->rd_rel->relkind;
-
- /*
- * No point in adding to the query a partitioned table that has no
- * partitions.
- */
- if (child_relkind == RELKIND_PARTITIONED_TABLE &&
- RelationGetPartitionDesc(childrel)->nparts == 0)
- {
- heap_close(childrel, lockmode);
- return;
- }
-
- child_reltype = childrel->rd_rel->reltype;
- childDesc = RelationGetDescr(childrel);
- }
- else
- {
- child_relkind = parentrte->relkind;
- child_reltype = parentRelType;
- childDesc = parentDesc;
- }
/*
* Build an RTE for the child, and attach to query's rangetable list. We
@@ -1723,11 +1739,10 @@ add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
* restriction clauses, so we don't need to do it here.
*/
childrte = copyObject(parentrte);
- *childrte_p = childrte;
- childrte->relid = childOID;
- childrte->relkind = child_relkind;
+ childrte->relid = RelationGetRelid(childrel);
+ childrte->relkind = RelationGetForm(childrel)->relkind;
/* A partitioned child will need to be expanded further. */
- if (childOID != parentOID &&
+ if (childrte->relid != parentrte->relid &&
childrte->relkind == RELKIND_PARTITIONED_TABLE)
childrte->inh = true;
else
@@ -1735,62 +1750,36 @@ add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
childrte->requiredPerms = 0;
childrte->securityQuals = NIL;
parse->rtable = lappend(parse->rtable, childrte);
- childRTindex = list_length(parse->rtable);
- *childRTindex_p = childRTindex;
/*
- * We need an AppendRelInfo if paths will be built for the child RTE. If
- * childrte->inh is true, then we'll always need to generate append paths
- * for it. If childrte->inh is false, we must scan it if it's not a
- * partitioned table; but if it is a partitioned table, then it never has
- * any data of its own and need not be scanned.
+ * Translate the column permissions bitmaps to the child's attnums (we
+ * have to build the translated_vars list before we can do this). But
+ * if this is the parent table, leave copyObject's result alone.
+ *
+ * Note: we need to do this even though the executor won't run any
+ * permissions checks on the child RTE. The insertedCols/updatedCols
+ * bitmaps may be examined for trigger-firing purposes.
*/
- if (childrte->relkind != RELKIND_PARTITIONED_TABLE || childrte->inh)
+ if (childrte->relid != parentrte->relid)
{
- appinfo = makeNode(AppendRelInfo);
- appinfo->parent_relid = parentRTindex;
- appinfo->child_relid = childRTindex;
- appinfo->parent_reltype = parentRelType;
- appinfo->child_reltype = child_reltype;
- make_inh_translation_list(parentDesc, childDesc,
- parentrte, childrte, childRTindex,
- &appinfo->translated_vars);
- appinfo->parent_reloid = parentOID;
- *appinfo_p = appinfo;
-
- /*
- * Translate the column permissions bitmaps to the child's attnums (we
- * have to build the translated_vars list before we can do this). But
- * if this is the parent table, leave copyObject's result alone.
- *
- * Note: we need to do this even though the executor won't run any
- * permissions checks on the child RTE. The insertedCols/updatedCols
- * bitmaps may be examined for trigger-firing purposes.
- */
- if (childOID != parentOID)
- {
- childrte->selectedCols = translate_col_privs(parentrte->selectedCols,
- appinfo->translated_vars);
- childrte->insertedCols = translate_col_privs(parentrte->insertedCols,
- appinfo->translated_vars);
- childrte->updatedCols = translate_col_privs(parentrte->updatedCols,
- appinfo->translated_vars);
- }
+ childrte->selectedCols = translate_col_privs(parentrte->selectedCols,
+ appinfo->translated_vars);
+ childrte->insertedCols = translate_col_privs(parentrte->insertedCols,
+ appinfo->translated_vars);
+ childrte->updatedCols = translate_col_privs(parentrte->updatedCols,
+ appinfo->translated_vars);
}
- /*
- * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
- */
if (top_parentrc)
{
PlanRowMark *childrc = makeNode(PlanRowMark);
+ int orig_allMarkTypes = top_parentrc->allMarkTypes;
- childrc->rti = childRTindex;
+ childrc->rti = list_length(parse->rtable);
childrc->prti = top_parentrc->rti;
childrc->rowmarkId = top_parentrc->rowmarkId;
/* Reselect rowmark type, because relkind might not match parent */
- childrc->markType = select_rowmark_type(childrte,
- top_parentrc->strength);
+ childrc->markType = select_rowmark_type(childrte, top_parentrc->strength);
childrc->allMarkTypes = (1 << childrc->markType);
childrc->strength = top_parentrc->strength;
childrc->waitPolicy = top_parentrc->waitPolicy;
@@ -1804,18 +1793,65 @@ add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
/* Include child's rowmark type in top parent's allMarkTypes */
top_parentrc->allMarkTypes |= childrc->allMarkTypes;
-
root->rowMarks = lappend(root->rowMarks, childrc);
- if (child_rowmark)
- *child_rowmark = childrc;
+
+ /*
+ * Update query's targetlist if the newly added child row mark requires
+ * additional columns and also add the relevant expressions to root
+ * parent's reltarget.
+ */
+ if (top_parentrc->allMarkTypes != orig_allMarkTypes)
+ {
+ List *tlist = root->parse->targetList;
+
+ tlist = add_rowmark_columns(root, tlist, list_make1(top_parentrc));
+ build_base_rel_tlists(root, tlist);
+ }
}
- /* Close child relations, but keep locks */
- if (childOID != parentOID)
+ *childrte_p = childrte;
+ return list_length(parse->rtable);
+}
+
+/*
+ * Starting with 'rel', find the root inheritance parent's RT index.
+ */
+Index
+get_inheritance_root_parent(PlannerInfo *root, RelOptInfo *rel)
+{
+ Index rootRTindex = 0;
+
+ /* No AppendRelInfo array yet. */
+ if (root->append_rel_array == NULL)
+ return rel->relid;
+
+ /*
+ * The inheritance root itself might be a child of UNION ALL subquery,
+ * so we must resort to finding it like this.
+ */
+ rootRTindex = rel->relid;
+ if (root->append_rel_array[rootRTindex])
{
- Assert(childrel != NULL);
- heap_close(childrel, lockmode);
+ AppendRelInfo *appinfo = root->append_rel_array[rootRTindex];
+ RangeTblEntry *parent = root->simple_rte_array[rootRTindex];
+
+ /*
+ * Keep moving up until we reach the parent RTE that's not a
+ * RTE_RELATION. The last RTE_RELATION entry would be the
+ * inheritance root's.
+ */
+ while(parent->rtekind == RTE_RELATION)
+ {
+ appinfo = root->append_rel_array[appinfo->parent_relid];
+ if (appinfo == NULL)
+ break;
+ rootRTindex = appinfo->parent_relid;
+ parent = root->simple_rte_array[rootRTindex];
+ }
}
+
+ Assert(rootRTindex > 0);
+ return rootRTindex;
}
/*
@@ -1825,13 +1861,12 @@ add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
*
* For paranoia's sake, we match type/collation as well as attribute name.
*/
-static void
+void
make_inh_translation_list(TupleDesc old_tupdesc, TupleDesc new_tupdesc,
- RangeTblEntry *oldrte, RangeTblEntry *newrte,
+ Oid from_rel, Oid to_rel,
Index newvarno, List **translated_vars)
{
List *vars = NIL;
- Oid new_relid = newrte->relid;
int oldnatts = old_tupdesc->natts;
int newnatts = new_tupdesc->natts;
int old_attno;
@@ -1861,7 +1896,7 @@ make_inh_translation_list(TupleDesc old_tupdesc, TupleDesc new_tupdesc,
* When we are generating the "translation list" for the parent table
* of an inheritance set, no need to search for matches.
*/
- if (oldrte->relid == newrte->relid)
+ if (from_rel == to_rel)
{
vars = lappend(vars, makeVar(newvarno,
(AttrNumber) (old_attno + 1),
@@ -1887,10 +1922,10 @@ make_inh_translation_list(TupleDesc old_tupdesc, TupleDesc new_tupdesc,
{
HeapTuple newtup;
- newtup = SearchSysCacheAttName(new_relid, attname);
+ newtup = SearchSysCacheAttName(to_rel, attname);
if (!newtup)
elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
- attname, get_rel_name(newrte->relid));
+ attname, get_rel_name(to_rel));
new_attno = ((Form_pg_attribute) GETSTRUCT(newtup))->attnum - 1;
ReleaseSysCache(newtup);
@@ -1900,10 +1935,10 @@ make_inh_translation_list(TupleDesc old_tupdesc, TupleDesc new_tupdesc,
/* Found it, check type and collation match */
if (atttypid != att->atttypid || atttypmod != att->atttypmod)
elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
- attname, get_rel_name(newrte->relid));
+ attname, get_rel_name(to_rel));
if (attcollation != att->attcollation)
elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation",
- attname, get_rel_name(newrte->relid));
+ attname, get_rel_name(to_rel));
vars = lappend(vars, makeVar(newvarno,
(AttrNumber) (new_attno + 1),
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 77ae4b538a..c4a485af91 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -65,7 +65,7 @@ static bool infer_collation_opclass_match(InferenceElem *elem, Relation idxRel,
List *idxExprs);
static int32 get_rel_data_width(Relation rel, int32 *attr_widths);
static List *get_relation_constraints(PlannerInfo *root,
- Oid relationObjectId, RelOptInfo *rel,
+ Oid relationObjectId, Index varno,
bool include_notnull);
static List *build_index_tlist(PlannerInfo *root, IndexOptInfo *index,
Relation heapRelation);
@@ -99,14 +99,13 @@ static void set_baserel_partition_key_exprs(Relation relation,
* cases these are left as zeroes, but sometimes we need to compute attr
* widths here, and we may as well cache the results for costsize.c.
*
- * If inhparent is true, all we need to do is set up the attr arrays:
+ * If rte->inh is true, all we need to do is set up the attr arrays:
* the RelOptInfo actually represents the appendrel formed by an inheritance
* tree, and so the parent rel's physical size and index information isn't
* important for it.
*/
void
-get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
- Bitmapset *updatedCols, RelOptInfo *rel)
+get_relation_info(PlannerInfo *root, RangeTblEntry *rte, RelOptInfo *rel)
{
Index varno = rel->relid;
Relation relation;
@@ -118,7 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
* the rewriter or when expand_inherited_rtentry() added it to the query's
* rangetable.
*/
- relation = heap_open(relationObjectId, NoLock);
+ relation = heap_open(rte->relid, NoLock);
/* Temporary and unlogged relations are inaccessible during recovery. */
if (!RelationNeedsWAL(relation) && RecoveryInProgress())
@@ -142,7 +141,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
* must leave it zero for now to avoid bollixing the total_table_pages
* calculation.
*/
- if (!inhparent)
+ if (!rte->inh)
estimate_rel_size(relation, rel->attr_widths - rel->min_attr,
&rel->pages, &rel->tuples, &rel->allvisfrac);
@@ -153,7 +152,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
* Make list of indexes. Ignore indexes on system catalogs if told to.
* Don't bother with indexes for an inheritance parent, either.
*/
- if (inhparent ||
+ if (rte->inh ||
(IgnoreSystemIndexes && IsSystemRelation(relation)))
hasindex = false;
else
@@ -442,18 +441,18 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
}
/* Collect info about relation's foreign keys, if relevant */
- get_relation_foreign_keys(root, rel, relation, inhparent);
+ get_relation_foreign_keys(root, rel, relation, rte->inh);
/*
* Collect info about relation's partitioning scheme, if any. Only
* inheritance parents may be partitioned.
*/
- if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ if (rte->inh && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
set_relation_partition_info(root, rel, relation);
if (!root->partColsUpdated)
root->partColsUpdated =
- has_partition_attrs(relation, updatedCols, NULL);
+ has_partition_attrs(relation, rte->updatedCols, NULL);
}
rel->tupdesc = RelationGetDescr(relation);
@@ -467,7 +466,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
* removing an index, or adding a hypothetical index to the indexlist.
*/
if (get_relation_info_hook)
- (*get_relation_info_hook) (root, relationObjectId, inhparent, rel);
+ (*get_relation_info_hook) (root, rte->relid, rte->inh, rel);
}
/*
@@ -1181,11 +1180,10 @@ get_relation_data_width(Oid relid, int32 *attr_widths)
*/
static List *
get_relation_constraints(PlannerInfo *root,
- Oid relationObjectId, RelOptInfo *rel,
+ Oid relationObjectId, Index varno,
bool include_notnull)
{
List *result = NIL;
- Index varno = rel->relid;
Relation relation;
TupleConstr *constr;
@@ -1363,16 +1361,16 @@ get_relation_statistics(RelOptInfo *rel, Relation relation)
*/
bool
relation_excluded_by_constraints(PlannerInfo *root,
- RelOptInfo *rel, RangeTblEntry *rte)
+ List *baserestrictinfo,
+ Index varno,
+ Oid table_oid,
+ bool is_child)
{
List *safe_restrictions;
List *constraint_pred;
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
@@ -1382,9 +1380,9 @@ relation_excluded_by_constraints(PlannerInfo *root,
* this, we'd miss some optimizations that 9.5 and earlier found via much
* more roundabout methods.)
*/
- if (list_length(rel->baserestrictinfo) == 1)
+ if (list_length(baserestrictinfo) == 1)
{
- RestrictInfo *rinfo = (RestrictInfo *) linitial(rel->baserestrictinfo);
+ RestrictInfo *rinfo = (RestrictInfo *) linitial(baserestrictinfo);
Expr *clause = rinfo->clause;
if (clause && IsA(clause, Const) &&
@@ -1407,7 +1405,7 @@ relation_excluded_by_constraints(PlannerInfo *root,
* When constraint_exclusion is set to 'partition' we only handle
* OTHER_MEMBER_RELs.
*/
- if (rel->reloptkind != RELOPT_OTHER_MEMBER_REL)
+ if (!is_child)
return false;
break;
@@ -1424,7 +1422,7 @@ relation_excluded_by_constraints(PlannerInfo *root,
* expecting to see any in its predicate argument.
*/
safe_restrictions = NIL;
- foreach(lc, rel->baserestrictinfo)
+ foreach(lc, baserestrictinfo)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
@@ -1440,24 +1438,10 @@ relation_excluded_by_constraints(PlannerInfo *root,
return true;
/*
- * Only plain relations have constraints. In a partitioning hierarchy,
- * but not with regular table inheritance, it's OK to assume that any
- * constraints that hold for the parent also hold for every child; for
- * instance, table inheritance allows the parent to have constraints
- * marked NO INHERIT, but table partitioning does not. We choose to check
- * whether the partitioning parents can be excluded here; doing so
- * consumes some cycles, but potentially saves us the work of excluding
- * each child individually.
- */
- if (rte->rtekind != RTE_RELATION ||
- (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE))
- return false;
-
- /*
* OK to fetch the constraint expressions. Include "col IS NOT NULL"
* expressions for attnotnull columns, in case we can refute those.
*/
- constraint_pred = get_relation_constraints(root, rte->relid, rel, true);
+ constraint_pred = get_relation_constraints(root, table_oid, varno, true);
/*
* We do not currently enforce that CHECK constraints contain only
@@ -1488,7 +1472,7 @@ relation_excluded_by_constraints(PlannerInfo *root,
* We need strong refutation because we have to prove that the constraints
* would yield false, not just NULL.
*/
- if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo, false))
+ if (predicate_refuted_by(safe_constraints, baserestrictinfo, false))
return true;
return false;
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index e98b626395..f87283e261 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -16,7 +16,10 @@
#include <limits.h>
+#include "access/heapam.h"
+#include "catalog/partition.h"
#include "catalog/pg_class.h"
+#include "catalog/pg_inherits.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
@@ -24,12 +27,15 @@
#include "optimizer/paths.h"
#include "optimizer/placeholder.h"
#include "optimizer/plancat.h"
+#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
#include "partitioning/partbounds.h"
+#include "rewrite/rewriteManip.h"
#include "storage/lockdefs.h"
#include "utils/hsearch.h"
+#include "utils/rel.h"
typedef struct JoinHashEntry
@@ -91,6 +97,13 @@ setup_simple_rel_arrays(PlannerInfo *root)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
+ /*
+ * If a table has no inheritance children, then turn off
+ * inheritance so that further plannig steps process it as a
+ * regular table.
+ */
+ if (rte->rtekind == RTE_RELATION && !has_subclass(rte->relid))
+ rte->inh = false;
root->simple_rte_array[rti++] = rte;
}
}
@@ -227,8 +240,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
{
case RTE_RELATION:
/* Table --- retrieve statistics from the system catalogs */
- get_relation_info(root, rte->relid, rte->inh, rte->updatedCols,
- rel);
+ get_relation_info(root, rte, rel);
break;
case RTE_SUBQUERY:
case RTE_FUNCTION:
@@ -269,29 +281,17 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
root->qual_security_level = Max(root->qual_security_level,
list_length(rte->securityQuals));
+#ifdef NOT_USED
/*
* 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 (rte->inh)
+ if (rte->inh && rte->rtekind == RTE_SUBQUERY)
{
ListCell *l;
- /*
- * For partitioned tables, we just allocate space for RelOptInfo's.
- * pointers for all partitions and copy the partition OIDs from the
- * relcache. Actual RelOptInfo is built for a partition only if it is
- * not pruned.
- */
- if (rte->relkind == RELKIND_PARTITIONED_TABLE)
- {
- rel->part_rels = (RelOptInfo **)
- palloc0(sizeof(RelOptInfo *) * rel->nparts);
- return rel;
- }
-
foreach(l, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
@@ -303,6 +303,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
(void) build_simple_rel(root, appinfo->child_relid, rel);
}
}
+#endif
return rel;
}
@@ -1746,6 +1747,60 @@ build_joinrel_partition_info(RelOptInfo *joinrel, RelOptInfo *outer_rel,
}
/*
+ * build_child_join_reltarget
+ * Set up a child-join relation's reltarget from a parent-join relation.
+ */
+static void
+build_child_join_reltarget(PlannerInfo *root,
+ RelOptInfo *parentrel,
+ RelOptInfo *childrel,
+ int nappinfos,
+ AppendRelInfo **appinfos)
+{
+ /* Build the targetlist */
+ childrel->reltarget->exprs = (List *)
+ adjust_appendrel_attrs(root,
+ (Node *) parentrel->reltarget->exprs,
+ nappinfos, appinfos);
+
+ /* Set the cost and width fields */
+ childrel->reltarget->cost.startup = parentrel->reltarget->cost.startup;
+ childrel->reltarget->cost.per_tuple = parentrel->reltarget->cost.per_tuple;
+ childrel->reltarget->width = parentrel->reltarget->width;
+}
+
+/* Expand the PlannerInfo arrays to hold new inheritance children objects. */
+void
+expand_planner_arrays_for_inheritance(PlannerInfo *root, int num_children)
+{
+ int new_size = root->simple_rel_array_size + num_children;
+
+ root->simple_rte_array = (RangeTblEntry **)
+ repalloc(root->simple_rte_array,
+ sizeof(RangeTblEntry *) * new_size);
+ root->simple_rel_array = (RelOptInfo **)
+ repalloc(root->simple_rel_array,
+ sizeof(RelOptInfo *) * new_size);
+ if (root->append_rel_array)
+ root->append_rel_array = (AppendRelInfo **)
+ repalloc(root->append_rel_array,
+ sizeof(AppendRelInfo *) * new_size);
+ else
+ root->append_rel_array = (AppendRelInfo **)
+ palloc0(sizeof(AppendRelInfo *) *
+ new_size);
+
+ /* Set the contents of just allocated memory to 0. */
+ MemSet(root->simple_rte_array + root->simple_rel_array_size,
+ 0, sizeof(RangeTblEntry *) * num_children);
+ MemSet(root->simple_rel_array + root->simple_rel_array_size,
+ 0, sizeof(RelOptInfo *) * num_children);
+ MemSet(root->append_rel_array + root->simple_rel_array_size,
+ 0, sizeof(AppendRelInfo *) * num_children);
+ root->simple_rel_array_size = new_size;
+}
+
+/*
* build_dummy_partition_rel
* Build a RelOptInfo and AppendRelInfo for a pruned partition
*
@@ -1804,55 +1859,20 @@ build_dummy_partition_rel(PlannerInfo *root, RelOptInfo *parent, int partidx)
* range table and creating planner data structures for it
*/
RelOptInfo *
-build_partition_rel(PlannerInfo *root, RelOptInfo *parent, Oid partoid)
+build_partition_rel(PlannerInfo *root,
+ RelOptInfo *parent,
+ Oid partoid,
+ Index rootRTindex,
+ PlanRowMark *rootrc)
{
RangeTblEntry *parentrte = root->simple_rte_array[parent->relid];
- RelOptInfo *result;
- Index rootRTindex = 0;
+ RangeTblEntry *partrte;
+ Relation partrel;
+ PartitionDesc partdesc;
Index partRTindex = 0;
- RangeTblEntry *partrte = NULL;
- AppendRelInfo *appinfo = NULL;
- PlanRowMark *rootrc = NULL;
- int orig_allMarkTypes;
- PlanRowMark *childrc = NULL;
+ AppendRelInfo *appinfo;
int lockmode;
- /* Locate the root partitioned table and fetch its PlanRowMark, if any. */
- if (root->rowMarks)
- {
- /*
- * The root partitioned table itself might be a child of UNION ALL
- * parent, so we must resort to finding the root parent like this.
- */
- rootRTindex = parent->relid;
- if (root->append_rel_array[rootRTindex])
- {
- AppendRelInfo *tmp = root->append_rel_array[rootRTindex];
-
- /*
- * Keep moving up until we each the parent rel that's not a
- * partitioned table. The one before that one would be the root
- * parent.
- */
- while(root->simple_rel_array[rootRTindex]->part_scheme)
- {
- tmp = root->append_rel_array[tmp->parent_relid];
- if (tmp == NULL)
- break;
- rootRTindex = tmp->parent_relid;
- }
- }
-
- rootrc = get_plan_rowmark(root->rowMarks, rootRTindex);
-
- /*
- * Addition of certain child rowmarks will change the value, in which
- * case, we need to add additional columns to the query's targetlist.
- */
- if (rootrc)
- orig_allMarkTypes = rootrc->allMarkTypes;
- }
-
/* Determine the correct lockmode to use. */
if (rootRTindex == root->parse->resultRelation)
lockmode = RowExclusiveLock;
@@ -1860,58 +1880,124 @@ build_partition_rel(PlannerInfo *root, RelOptInfo *parent, Oid partoid)
lockmode = RowShareLock;
else
lockmode = AccessShareLock;
- add_inheritance_child_to_query(root, parentrte, parent->relid,
- parent->reltype, parent->tupdesc,
- rootrc, partoid, lockmode,
- &appinfo, &partrte, &partRTindex,
- &childrc);
- /* Partition turned out to be a partitioned table with 0 partitions. */
- if (partrte == NULL)
+ partrel = heap_open(partoid, lockmode);
+ Assert(!RELATION_IS_OTHER_TEMP(partrel));
+ partdesc = RelationGetPartitionDesc(partrel);
+ if (partdesc && partdesc->nparts == 0)
+ {
+ heap_close(partrel, NoLock);
return NULL;
+ }
+
+ appinfo = makeNode(AppendRelInfo);
+ appinfo->parent_relid = parent->relid;
+ appinfo->child_relid = 0; /* Set to correct value below. */
+ appinfo->parent_reltype = parent->reltype;
+ appinfo->child_reltype = partrel->rd_rel->reltype;
+ make_inh_translation_list(parent->tupdesc,
+ RelationGetDescr(partrel),
+ parentrte->relid, partoid,
+ parent->relid,
+ &appinfo->translated_vars);
+ appinfo->parent_reloid = parentrte->relid;
+
+ partRTindex = add_inheritance_child_to_query(root, parentrte, partrel,
+ appinfo, rootrc, &partrte);
+ heap_close(partrel, NoLock);
+
+ Assert(partrte != NULL);
+
+ /* Fix up the AppendRelInfo with correct child RT index. */
+ appinfo->child_relid = partRTindex;
+ ChangeVarNodes((Node *) appinfo->translated_vars, parent->relid,
+ partRTindex, 0);
- Assert(appinfo != NULL);
root->append_rel_list = lappend(root->append_rel_list, appinfo);
root->simple_rte_array[partRTindex] = partrte;
root->append_rel_array[partRTindex] = appinfo;
- /* Build the RelOptInfo. */
- result = build_simple_rel(root, partRTindex, parent);
-
- /* Set the information created by create_lateral_join_info(). */
- result->direct_lateral_relids = parent->direct_lateral_relids;
- result->lateral_relids = parent->lateral_relids;
- result->lateral_referencers = parent->lateral_referencers;
-
- if (rootrc && rootrc->allMarkTypes != orig_allMarkTypes)
- {
- List *tlist = root->parse->targetList;
-
- tlist = add_rowmark_columns(root, tlist, list_make1(rootrc));
- }
-
- return result;
+ return build_inheritance_child_rel(root, partRTindex, parent);
}
-/*
- * build_child_join_reltarget
- * Set up a child-join relation's reltarget from a parent-join relation.
- */
-static void
-build_child_join_reltarget(PlannerInfo *root,
- RelOptInfo *parentrel,
- RelOptInfo *childrel,
- int nappinfos,
- AppendRelInfo **appinfos)
+RelOptInfo *
+build_inheritance_child_rel(PlannerInfo *root, Index childRTindex,
+ RelOptInfo *parent)
{
- /* Build the targetlist */
- childrel->reltarget->exprs = (List *)
- adjust_appendrel_attrs(root,
- (Node *) parentrel->reltarget->exprs,
- nappinfos, appinfos);
+ Relids top_parent_relids = parent->top_parent_relids;
+ int rootParentRTindex = top_parent_relids ?
+ bms_singleton_member(top_parent_relids) :
+ parent->relid;
+ AppendRelInfo *appinfo = root->append_rel_array[childRTindex];
+ /* Build the RelOptInfo. */
+ RelOptInfo *childrel = build_simple_rel(root, childRTindex, parent);
- /* Set the cost and width fields */
- childrel->reltarget->cost.startup = parentrel->reltarget->cost.startup;
- childrel->reltarget->cost.per_tuple = parentrel->reltarget->cost.per_tuple;
- childrel->reltarget->width = parentrel->reltarget->width;
+ /*
+ * 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.
+ */
+ childrel->direct_lateral_relids = parent->direct_lateral_relids;
+ childrel->lateral_relids = parent->lateral_relids;
+ childrel->lateral_referencers = parent->lateral_referencers;
+
+ /*
+ * Copy/Modify targetlist. Even if this child is deemed empty, we need
+ * its targetlist in case it falls on nullable side in a child-join
+ * because of partitionwise join.
+ *
+ * NB: the resulting childrel->reltarget->exprs may contain arbitrary
+ * expressions, which otherwise would not occur in a rel's targetlist.
+ * Code that might be looking at an appendrel child must cope with
+ * such. (Normally, a rel's targetlist would only include Vars and
+ * PlaceHolderVars.) XXX we do not bother to update the cost or width
+ * fields of childrel->reltarget; not clear if that would be useful.
+ */
+ if (rootParentRTindex == root->parse->resultRelation)
+ {
+ Query *parse,
+ *orig_parse = root->parse;
+ List *tlist;
+ List *other_exprs;
+ ListCell *lc2;
+
+ parse = (Query *)
+ adjust_appendrel_attrs(root,
+ (Node *) root->parse,
+ 1, &appinfo);
+ root->parse = parse;
+ tlist = preprocess_targetlist(root);
+ build_base_rel_tlists(root, tlist);
+ root->parse = orig_parse;
+
+ /*
+ * Now add members of parent's reltarget->exprs, not already in
+ * child's.
+ */
+ other_exprs = (List *)
+ adjust_appendrel_attrs(root,
+ (Node *) parent->reltarget->exprs,
+ 1, &appinfo);
+ foreach(lc2, other_exprs)
+ {
+ if (!list_member(childrel->reltarget->exprs, lfirst(lc2)))
+ childrel->reltarget->exprs =
+ lappend(childrel->reltarget->exprs,
+ lfirst(lc2));
+ }
+ }
+ else
+ {
+ childrel->reltarget->exprs = (List *)
+ adjust_appendrel_attrs(root,
+ (Node *) parent->reltarget->exprs,
+ 1, &appinfo);
+ }
+
+ return childrel;
}
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 345ab19989..d5dad5a1e9 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -601,8 +601,6 @@ prune_append_rel_partitions(PlannerInfo *root, RelOptInfo *rel)
if (bms_is_empty(partindexes))
return;
}
- else
- scan_all_parts = true;
}
else
scan_all_parts = true;
@@ -611,7 +609,8 @@ prune_append_rel_partitions(PlannerInfo *root, RelOptInfo *rel)
* Build selected partitions' range table entries, RelOptInfos, and
* AppendRelInfos.
*/
- add_rel_partitions_to_query(root, rel, scan_all_parts, partindexes);
+ if (scan_all_parts || !bms_is_empty(partindexes))
+ add_rel_partitions_to_query(root, rel, scan_all_parts, partindexes);
}
/*
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 4f567765a4..bf5a025b69 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -15,6 +15,7 @@
#define PATHNODE_H
#include "nodes/bitmapset.h"
+#include "nodes/plannodes.h"
#include "nodes/relation.h"
@@ -261,6 +262,8 @@ extern Path *reparameterize_path_by_child(PlannerInfo *root, Path *path,
*/
extern void setup_simple_rel_arrays(PlannerInfo *root);
extern void setup_append_rel_array(PlannerInfo *root);
+extern void expand_planner_arrays_for_inheritance(PlannerInfo *root,
+ int num_children);
extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid,
RelOptInfo *parent);
extern RelOptInfo *find_base_rel(PlannerInfo *root, int relid);
@@ -300,8 +303,12 @@ extern RelOptInfo *build_child_join_rel(PlannerInfo *root,
extern RelOptInfo *build_dummy_partition_rel(PlannerInfo *root,
RelOptInfo *parent,
int partidx);
+RelOptInfo *build_inheritance_child_rel(PlannerInfo *root, Index childRTindex,
+ RelOptInfo *parent);
extern RelOptInfo *build_partition_rel(PlannerInfo *root,
RelOptInfo *parent,
- Oid partoid);
+ Oid partoid,
+ Index rootRTindex,
+ PlanRowMark *rootrc);
#endif /* PATHNODE_H */
diff --git a/src/include/optimizer/plancat.h b/src/include/optimizer/plancat.h
index edaf2a3b4f..5e1e7478bf 100644
--- a/src/include/optimizer/plancat.h
+++ b/src/include/optimizer/plancat.h
@@ -25,8 +25,8 @@ typedef void (*get_relation_info_hook_type) (PlannerInfo *root,
extern PGDLLIMPORT get_relation_info_hook_type get_relation_info_hook;
-extern void get_relation_info(PlannerInfo *root, Oid relationObjectId,
- bool inhparent, Bitmapset *updatedCols, RelOptInfo *rel);
+extern void get_relation_info(PlannerInfo *root, RangeTblEntry *rte,
+ RelOptInfo *rel);
extern List *infer_arbiter_indexes(PlannerInfo *root);
@@ -36,7 +36,10 @@ extern void estimate_rel_size(Relation rel, int32 *attr_widths,
extern int32 get_relation_data_width(Oid relid, int32 *attr_widths);
extern bool relation_excluded_by_constraints(PlannerInfo *root,
- RelOptInfo *rel, RangeTblEntry *rte);
+ List *baserestrictinfo,
+ Index varno,
+ Oid table_oid,
+ bool is_child);
extern List *build_physical_tlist(PlannerInfo *root, RelOptInfo *rel);
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index ee7406e4f6..1462e7b92f 100644
--- a/src/include/optimizer/prep.h
+++ b/src/include/optimizer/prep.h
@@ -16,6 +16,7 @@
#include "nodes/plannodes.h"
#include "nodes/relation.h"
+#include "utils/relcache.h"
/*
@@ -50,18 +51,21 @@ extern PlanRowMark *get_plan_rowmark(List *rowmarks, Index rtindex);
*/
extern RelOptInfo *plan_set_operations(PlannerInfo *root);
-extern void expand_inherited_tables(PlannerInfo *root);
-
-extern void add_inheritance_child_to_query(PlannerInfo *root,
- RangeTblEntry *parentrte,
- Index parentRTindex, Oid parentRelType,
- TupleDesc parentDesc,
- PlanRowMark *top_parentrc,
- Oid childOID, int lockmode,
- AppendRelInfo **appinfo_p,
- RangeTblEntry **childrte_p,
- Index *childRTindex_p,
- PlanRowMark **child_rowmark);
+extern void expand_inherited_rtentry(PlannerInfo *root,
+ RelOptInfo *rel,
+ RangeTblEntry *rte,
+ Index rti);
+extern Index add_inheritance_child_to_query(PlannerInfo *root,
+ RangeTblEntry *parentrte,
+ Relation childrel,
+ AppendRelInfo *appinfo,
+ PlanRowMark *top_parentrc,
+ RangeTblEntry **childrte_p);
+extern Index get_inheritance_root_parent(PlannerInfo *root, RelOptInfo *rel);
+extern void make_inh_translation_list(TupleDesc old_tupdesc,
+ TupleDesc new_tupdesc,
+ Oid from_rel, Oid to_rel,
+ Index newvarno, List **translated_vars);
extern Node *adjust_appendrel_attrs(PlannerInfo *root, Node *node,
int nappinfos, AppendRelInfo **appinfos);
--
2.11.0