v26-0004-Perform-pruning-in-expand_partitioned_rtentry.patch
text/plain
Filename: v26-0004-Perform-pruning-in-expand_partitioned_rtentry.patch
Type: text/plain
Part: 3
Patch
Format: format-patch
Series: patch v26-0004
Subject: Perform pruning in expand_partitioned_rtentry
| File | + | − |
|---|---|---|
| src/backend/optimizer/path/allpaths.c | 5 | 171 |
| src/backend/optimizer/path/joinrels.c | 90 | 2 |
| src/backend/optimizer/plan/planner.c | 8 | 0 |
| src/backend/optimizer/util/inherit.c | 9 | 2 |
| src/backend/optimizer/util/relnode.c | 169 | 5 |
| src/backend/partitioning/partprune.c | 23 | 20 |
From d3fcb2331bfa8101195134f93aaf7e31010d3361 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 4 Mar 2019 11:43:38 +0900
Subject: [PATCH v26 4/6] Perform pruning in expand_partitioned_rtentry
This allows to avoid opening/locking partitions that won't be
scanned at all. Since expand_partitioned_rtentry recursivly processes
sub-partitioned tables, translated quals must be added right when the
child RelOptInfo is built for the sub-partitioned tables. So,
build_simple_rel itself performs apply_child_basequals.
Code for partitioning optimizations that access partition RelOptInfos
from part_rels array of the parent's RelOptInfo must now be made
aware that some entries might be NULL due partition pruning. In the
case of partitionwise join, even a pruned partition may need to be
joined if it falls on the nullable side of an outer join. A dummy
RelOptInfo containing a dummy path is built in that case and put
into its parent's part_rels array.
---
src/backend/optimizer/path/allpaths.c | 176 +---------------------------------
src/backend/optimizer/path/joinrels.c | 92 +++++++++++++++++-
src/backend/optimizer/plan/planner.c | 8 ++
src/backend/optimizer/util/inherit.c | 11 ++-
src/backend/optimizer/util/relnode.c | 174 ++++++++++++++++++++++++++++++++-
src/backend/partitioning/partprune.c | 43 +++++----
6 files changed, 304 insertions(+), 200 deletions(-)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 8d8a8f17d5..3191836c19 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -138,9 +138,6 @@ static void subquery_push_qual(Query *subquery,
static void recurse_push_qual(Node *setOp, Query *topquery,
RangeTblEntry *rte, Index rti, Node *qual);
static void remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel);
-static bool apply_child_basequals(PlannerInfo *root, RelOptInfo *rel,
- RelOptInfo *childrel,
- RangeTblEntry *childRTE, AppendRelInfo *appinfo);
/*
@@ -945,8 +942,6 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
double *parent_attrsizes;
int nattrs;
ListCell *l;
- Relids live_children = NULL;
- bool did_pruning = false;
/* Guard against stack overflow due to overly deep inheritance tree. */
check_stack_depth();
@@ -965,21 +960,6 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
rel->partitioned_child_rels = list_make1_int(rti);
/*
- * If the partitioned relation has any baserestrictinfo quals then we
- * attempt to use these quals to prune away partitions that cannot
- * possibly contain any tuples matching these quals. In this case we'll
- * store the relids of all partitions which could possibly contain a
- * matching tuple, and skip anything else in the loop below.
- */
- if (enable_partition_pruning &&
- rte->relkind == RELKIND_PARTITIONED_TABLE &&
- rel->baserestrictinfo != NIL)
- {
- live_children = prune_append_rel_partitions(rel);
- did_pruning = true;
- }
-
- /*
* If this is a partitioned baserel, set the consider_partitionwise_join
* flag; currently, we only consider partitionwise joins with the baserel
* if its targetlist doesn't contain a whole-row Var.
@@ -1033,30 +1013,11 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
childrel = find_base_rel(root, childRTindex);
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
- if (did_pruning && !bms_is_member(appinfo->child_relid, live_children))
- {
- /* This partition was pruned; skip it. */
- set_dummy_rel_pathlist(childrel);
+ /* build_simple_rel may have already proven the child to be dummy. */
+ if (IS_DUMMY_REL(childrel))
continue;
- }
-
- /*
- * We have to copy the parent's targetlist and quals to the child,
- * with appropriate substitution of variables. If any constant false
- * or NULL clauses turn up, we can disregard the child right away.
- * If not, we can apply constraint exclusion with just the
- * baserestrictinfo quals.
- */
- if (!apply_child_basequals(root, rel, childrel, childRTE, appinfo))
- {
- /*
- * Some restriction clause reduced to constant FALSE or NULL after
- * substitution, so this child need not be scanned.
- */
- set_dummy_rel_pathlist(childrel);
- continue;
- }
+ /* Apply constraint exclusion. */
if (relation_excluded_by_constraints(root, childrel, childRTE))
{
/*
@@ -1068,7 +1029,8 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
}
/*
- * CE failed, so finish copying/modifying targetlist and join quals.
+ * Constraint exclusion failed, so finish copying/modifying targetlist
+ * and join quals.
*
* NB: the resulting childrel->reltarget->exprs may contain arbitrary
* expressions, which otherwise would not occur in a rel's targetlist.
@@ -3557,134 +3519,6 @@ generate_partitionwise_join_paths(PlannerInfo *root, RelOptInfo *rel)
list_free(live_children);
}
-/*
- * apply_child_basequals
- * Populate childrel's quals based on rel's quals, translating them using
- * appinfo.
- *
- * If any of the resulting clauses evaluate to false or NULL, we return false
- * and don't apply any quals. Caller can mark the relation as a dummy rel in
- * this case, since it needn't be scanned.
- *
- * If any resulting clauses evaluate to true, they're unnecessary and we don't
- * apply then.
- */
-static bool
-apply_child_basequals(PlannerInfo *root, RelOptInfo *rel,
- RelOptInfo *childrel, RangeTblEntry *childRTE,
- AppendRelInfo *appinfo)
-{
- List *childquals;
- Index cq_min_security;
- ListCell *lc;
-
- /*
- * 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;
- foreach(lc, rel->baserestrictinfo)
- {
- RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
- Node *childqual;
- ListCell *lc2;
-
- Assert(IsA(rinfo, RestrictInfo));
- childqual = adjust_appendrel_attrs(root,
- (Node *) rinfo->clause,
- 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 */
- return false;
- }
- /* 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));
- /* track minimum security level among child quals */
- cq_min_security = Min(cq_min_security, rinfo->security_level);
- }
- }
-
- /*
- * In addition to the quals inherited from the parent, we might have
- * securityQuals associated with this particular child node. (Currently
- * this can only happen in appendrels originating from UNION ALL;
- * inheritance child tables don't have their own securityQuals, see
- * expand_inherited_rtentry().) Pull any such securityQuals up into the
- * baserestrictinfo for the child. This is similar to
- * process_security_barrier_quals() for the parent rel, except that we
- * can't make any general deductions from such quals, since they don't
- * hold for the whole appendrel.
- */
- if (childRTE->securityQuals)
- {
- Index security_level = 0;
-
- foreach(lc, childRTE->securityQuals)
- {
- List *qualset = (List *) lfirst(lc);
- ListCell *lc2;
-
- foreach(lc2, qualset)
- {
- 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));
- cq_min_security = Min(cq_min_security, security_level);
- }
- security_level++;
- }
- Assert(security_level <= root->qual_security_level);
- }
-
- /*
- * OK, we've got all the baserestrictinfo quals for this child.
- */
- childrel->baserestrictinfo = childquals;
- childrel->baserestrict_min_security = cq_min_security;
-
- return true;
-}
-
/*****************************************************************************
* DEBUG SUPPORT
*****************************************************************************/
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index dfbbfdac6d..66a5cf3334 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -14,6 +14,7 @@
*/
#include "postgres.h"
+#include "access/table.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/appendinfo.h"
@@ -21,6 +22,8 @@
#include "optimizer/joininfo.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
+#include "optimizer/tlist.h"
+#include "parser/parsetree.h"
#include "partitioning/partbounds.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
@@ -52,6 +55,9 @@ static SpecialJoinInfo *build_child_join_sjinfo(PlannerInfo *root,
Relids left_relids, Relids right_relids);
static int match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel,
bool strict_op);
+static RelOptInfo *build_dummy_partition_rel(PlannerInfo *root,
+ RelOptInfo *parent, Relation parentrel,
+ int partidx);
/*
@@ -1318,6 +1324,8 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
RelOptInfo *joinrel, SpecialJoinInfo *parent_sjinfo,
List *parent_restrictlist)
{
+ Relation baserel1 = NULL,
+ baserel2 = NULL;
bool rel1_is_simple = IS_SIMPLE_REL(rel1);
bool rel2_is_simple = IS_SIMPLE_REL(rel2);
int nparts;
@@ -1368,6 +1376,18 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
nparts = joinrel->nparts;
+ if (rel1_is_simple)
+ {
+ RangeTblEntry *rte = planner_rt_fetch(rel1->relid, root);
+
+ baserel1 = table_open(rte->relid, NoLock);
+ }
+ if (rel2_is_simple)
+ {
+ RangeTblEntry *rte = planner_rt_fetch(rel2->relid, root);
+
+ baserel2 = table_open(rte->relid, NoLock);
+ }
/*
* Create child-join relations for this partitioned join, if those don't
* exist. Add paths to child-joins for a pair of child relations
@@ -1384,6 +1404,13 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
AppendRelInfo **appinfos;
int nappinfos;
+ if (rel1_is_simple && child_rel1 == NULL)
+ child_rel1 = build_dummy_partition_rel(root, rel1, baserel1,
+ cnt_parts);
+ if (rel2_is_simple && child_rel2 == NULL)
+ child_rel2 = build_dummy_partition_rel(root, rel2, baserel2,
+ cnt_parts);
+
/*
* If a child table has consider_partitionwise_join=false, it means
* that it's a dummy relation for which we skipped setting up tlist
@@ -1444,6 +1471,11 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
child_joinrel, child_sjinfo,
child_restrictlist);
}
+
+ if (baserel1)
+ table_close(baserel1, NoLock);
+ if (baserel2)
+ table_close(baserel2, NoLock);
}
/*
@@ -1462,8 +1494,14 @@ update_child_rel_info(PlannerInfo *root,
(Node *) rel->reltarget->exprs,
1, &appinfo);
- /* Make child entries in the EquivalenceClass as well */
- if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
+ /*
+ * Make child entries in the EquivalenceClass as well. If the childrel
+ * appears to be a dummy one (one built by build_dummy_partition_rel()),
+ * no need to make any new entries, because anything that'd need those
+ * can instead use the parent's (rel).
+ */
+ if (childrel->relid != rel->relid &&
+ (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;
}
@@ -1674,3 +1712,53 @@ match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel, bool strict_op)
return -1;
}
+
+/*
+ * build_dummy_partition_rel
+ * Build a RelOptInfo and AppendRelInfo for a pruned partition
+ *
+ * This does not result in opening the relation or a range table entry being
+ * created. Also, the RelOptInfo thus created is not stored anywhere else
+ * beside the parent's part_rels array.
+ *
+ * The only reason this exists is because partition-wise join, in some cases,
+ * needs a RelOptInfo to represent an empty relation that's on the nullable
+ * side of an outer join, so that a Path representing the outer join can be
+ * created.
+ */
+static RelOptInfo *
+build_dummy_partition_rel(PlannerInfo *root, RelOptInfo *parent,
+ Relation parentrel, int partidx)
+{
+ RelOptInfo *rel;
+
+ Assert(parent->part_rels[partidx] == NULL);
+
+ /* Create minimally valid-looking RelOptInfo with parent's relid. */
+ rel = makeNode(RelOptInfo);
+ rel->reloptkind = RELOPT_OTHER_MEMBER_REL;
+ rel->relid = parent->relid;
+ rel->relids = bms_copy(parent->relids);
+ if (parent->top_parent_relids)
+ rel->top_parent_relids = parent->top_parent_relids;
+ else
+ rel->top_parent_relids = bms_copy(parent->relids);
+ rel->reltarget = copy_pathtarget(parent->reltarget);
+ parent->part_rels[partidx] = rel;
+ mark_dummy_rel(rel);
+
+ /*
+ * Now we'll need a (no-op) AppendRelInfo for parent, because we're
+ * setting the dummy partition's relid to be same as the parent's.
+ */
+ if (root->append_rel_array[parent->relid] == NULL)
+ {
+ AppendRelInfo *appinfo = make_append_rel_info(parentrel, parentrel,
+ parent->relid,
+ parent->relid);
+
+ root->append_rel_array[parent->relid] = appinfo;
+ }
+
+ return rel;
+}
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 94557108e8..7fd1366652 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -7138,6 +7138,10 @@ apply_scanjoin_target_to_paths(PlannerInfo *root,
int nappinfos;
List *child_scanjoin_targets = NIL;
+ /* Skip processing pruned partitions. */
+ if (child_rel == NULL)
+ continue;
+
/* Translate scan/join targets for this child. */
appinfos = find_appinfos_by_relids(root, child_rel->relids,
&nappinfos);
@@ -7239,6 +7243,10 @@ create_partitionwise_grouping_paths(PlannerInfo *root,
RelOptInfo *child_grouped_rel;
RelOptInfo *child_partially_grouped_rel;
+ /* Skip processing pruned partitions. */
+ if (child_input_rel == NULL)
+ continue;
+
/* Input child rel must have a path */
Assert(child_input_rel->pathlist != NIL);
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index fb2977dfbe..e2c1f341ce 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -26,6 +26,7 @@
#include "optimizer/planner.h"
#include "optimizer/prep.h"
#include "partitioning/partdesc.h"
+#include "partitioning/partprune.h"
#include "utils/rel.h"
@@ -242,6 +243,7 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
PlanRowMark *top_parentrc, LOCKMODE lockmode,
List **appinfos)
{
+ Bitmapset *live_parts = 0;
int i;
RangeTblEntry *childrte;
Index childRTindex;
@@ -276,12 +278,16 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
if (root->simple_rel_array_size > 0)
{
rel = find_base_rel(root, parentRTindex);
- expand_planner_arrays(root, partdesc->nparts + 1);
+ if (partdesc->nparts > 0)
+ live_parts = prune_append_rel_partitions(rel);
+ expand_planner_arrays(root, bms_num_members(live_parts) + 1);
Assert(rel->part_rels == NULL);
if (partdesc->nparts > 0)
rel->part_rels = (RelOptInfo **) palloc0(rel->nparts *
sizeof(RelOptInfo *));
}
+ else
+ live_parts = bms_add_range(NULL, 0, partdesc->nparts - 1);
/* First expand the partitioned table itself. */
expand_single_inheritance_child(root, parentrte, parentRTindex, parentrel,
@@ -298,7 +304,8 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
return;
}
- for (i = 0; i < partdesc->nparts; i++)
+ i = -1;
+ while ((i = bms_next_member(live_parts, i)) >= 0)
{
Oid childOID = partdesc->oids[i];
Relation childrel;
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 1dbf19e71b..adc06cf69a 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -70,6 +70,9 @@ static void build_child_join_reltarget(PlannerInfo *root,
RelOptInfo *childrel,
int nappinfos,
AppendRelInfo **appinfos);
+static bool apply_child_basequals(PlannerInfo *root, RelOptInfo *rel,
+ RelOptInfo *childrel,
+ RangeTblEntry *childRTE, AppendRelInfo *appinfo);
/*
@@ -324,10 +327,162 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
root->qual_security_level = Max(root->qual_security_level,
list_length(rte->securityQuals));
+ /*
+ * Copy the parent's quals to the child, with appropriate substitution of
+ * variables. If any constant false or NULL clauses turn up, we can
+ * disregard the child as dummy right away.
+ *
+ * We must copy the quals now, because if the child rel happens to be a
+ * partitioned table, expand_partitioned_rtentry (our caller) can
+ * immediate perform partition prunning using the translated quals.
+ */
+ if (parent)
+ {
+ AppendRelInfo *appinfo = root->append_rel_array[relid];
+
+ Assert(appinfo != NULL);
+ if (!apply_child_basequals(root, parent, rel, rte, appinfo))
+ {
+ /*
+ * Some restriction clause reduced to constant FALSE or NULL after
+ * substitution, so this child need not be scanned.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
+ }
+
return rel;
}
/*
+ * apply_child_basequals
+ * Populate childrel's quals based on rel's quals, translating them using
+ * appinfo.
+ *
+ * If any of the resulting clauses evaluate to false or NULL, we return false
+ * and don't apply any quals. Caller can mark the relation as a dummy rel in
+ * this case, since it needn't be scanned.
+ *
+ * If any resulting clauses evaluate to true, they're unnecessary and we don't
+ * apply then.
+ */
+static bool
+apply_child_basequals(PlannerInfo *root, RelOptInfo *rel,
+ RelOptInfo *childrel, RangeTblEntry *childRTE,
+ AppendRelInfo *appinfo)
+{
+ List *childquals;
+ Index cq_min_security;
+ ListCell *lc;
+
+ /*
+ * 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;
+ foreach(lc, rel->baserestrictinfo)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+ Node *childqual;
+ ListCell *lc2;
+
+ Assert(IsA(rinfo, RestrictInfo));
+ childqual = adjust_appendrel_attrs(root,
+ (Node *) rinfo->clause,
+ 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 */
+ return false;
+ }
+ /* 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));
+ /* track minimum security level among child quals */
+ cq_min_security = Min(cq_min_security, rinfo->security_level);
+ }
+ }
+
+ /*
+ * In addition to the quals inherited from the parent, we might have
+ * securityQuals associated with this particular child node. (Currently
+ * this can only happen in appendrels originating from UNION ALL;
+ * inheritance child tables don't have their own securityQuals, see
+ * expand_inherited_rtentry().) Pull any such securityQuals up into the
+ * baserestrictinfo for the child. This is similar to
+ * process_security_barrier_quals() for the parent rel, except that we
+ * can't make any general deductions from such quals, since they don't
+ * hold for the whole appendrel.
+ */
+ if (childRTE->securityQuals)
+ {
+ Index security_level = 0;
+
+ foreach(lc, childRTE->securityQuals)
+ {
+ List *qualset = (List *) lfirst(lc);
+ ListCell *lc2;
+
+ foreach(lc2, qualset)
+ {
+ 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));
+ cq_min_security = Min(cq_min_security, security_level);
+ }
+ security_level++;
+ }
+ Assert(security_level <= root->qual_security_level);
+ }
+
+ /*
+ * OK, we've got all the baserestrictinfo quals for this child.
+ */
+ childrel->baserestrictinfo = childquals;
+ childrel->baserestrict_min_security = cq_min_security;
+
+ return true;
+}
+
+/*
* add_appendrel_other_rels
* This adds the "other rel" RelOptInfos a given "appendrel" baserel
*
@@ -340,6 +495,7 @@ add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, Index rti)
ListCell *l;
RelOptInfo *rel;
Relation relation = NULL;
+ PartitionDesc partdesc = NULL;
int i;
/*
@@ -364,6 +520,7 @@ add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, Index rti)
rel->part_rels = (RelOptInfo **)
palloc0(sizeof(RelOptInfo *) * rel->nparts);
relation = table_open(rte->relid, NoLock);
+ partdesc = RelationGetPartitionDesc(relation);
}
/*
@@ -392,16 +549,23 @@ add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, Index rti)
* For partitioned parents, we also need to add childrel to its
* part_rels array. The order in which child tables appear in
* append_rel_list is same as the order in which they appear in the
- * parent's PartitionDesc, so assigning partitions like this works.
+ * parent's PartitionDesc. But considering that some partitions may
+ * have been pruned, we need to look up the correct position to
+ * assign this childrel by scanning the PartitionDesc.
*/
if (rel->part_scheme != NULL)
{
- Assert(rel->nparts > 0 && i < rel->nparts);
- rel->part_rels[i] = childrel;
+ Assert(partdesc != NULL);
+ for (i = 0; i < partdesc->nparts; i++)
+ {
+ if (childrte->relid == partdesc->oids[i])
+ {
+ rel->part_rels[i] = childrel;
+ break;
+ }
+ }
}
- i++;
-
/* Child may itself be an inherited relation. */
if (childrte->inh)
add_appendrel_other_rels(root, childrte, childRTindex);
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 8c9721935d..30ebce4e40 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -45,6 +45,7 @@
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/appendinfo.h"
+#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
#include "partitioning/partprune.h"
@@ -433,17 +434,23 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
* is, not pruned already).
*/
subplan_map = (int *) palloc(nparts * sizeof(int));
+ memset(subplan_map, -1, nparts * sizeof(int));
subpart_map = (int *) palloc(nparts * sizeof(int));
+ memset(subpart_map, -1, nparts * sizeof(int));
present_parts = NULL;
for (i = 0; i < nparts; i++)
{
RelOptInfo *partrel = subpart->part_rels[i];
- int subplanidx = relid_subplan_map[partrel->relid] - 1;
- int subpartidx = relid_subpart_map[partrel->relid] - 1;
+ int subplanidx;
+ int subpartidx;
- subplan_map[i] = subplanidx;
- subpart_map[i] = subpartidx;
+ /* Skip processing pruned partitions. */
+ if (partrel == NULL)
+ continue;
+
+ subplan_map[i] = subplanidx = relid_subplan_map[partrel->relid] - 1;
+ subpart_map[i] = subpartidx = relid_subpart_map[partrel->relid] - 1;
if (subplanidx >= 0)
{
present_parts = bms_add_member(present_parts, i);
@@ -537,23 +544,20 @@ gen_partprune_steps(RelOptInfo *rel, List *clauses, bool *contradictory)
/*
* prune_append_rel_partitions
- * Returns RT indexes of the minimum set of child partitions which must
- * be scanned to satisfy rel's baserestrictinfo quals.
+ * Returns indexes into rel->part_rels of the minimum set of child
+ * partitions which must be scanned to satisfy rel's baserestrictinfo
+ * quals.
*
* Callers must ensure that 'rel' is a partitioned table.
*/
-Relids
+Bitmapset *
prune_append_rel_partitions(RelOptInfo *rel)
{
- Relids result;
List *clauses = rel->baserestrictinfo;
List *pruning_steps;
bool contradictory;
PartitionPruneContext context;
- Bitmapset *partindexes;
- int i;
- Assert(clauses != NIL);
Assert(rel->part_scheme != NULL);
/* If there are no partitions, return the empty set */
@@ -561,6 +565,13 @@ prune_append_rel_partitions(RelOptInfo *rel)
return NULL;
/*
+ * If pruning is disabled or if there are no clauses to prune with,
+ * return all partitions.
+ */
+ if (!enable_partition_pruning || clauses == NIL)
+ return bms_add_range(NULL, 0, rel->nparts - 1);
+
+ /*
* Process clauses. If the clauses are found to be contradictory, we can
* return the empty set.
*/
@@ -587,15 +598,7 @@ prune_append_rel_partitions(RelOptInfo *rel)
context.evalexecparams = false;
/* Actual pruning happens here. */
- partindexes = get_matching_partitions(&context, pruning_steps);
-
- /* Add selected partitions' RT indexes to result. */
- i = -1;
- result = NULL;
- while ((i = bms_next_member(partindexes, i)) >= 0)
- result = bms_add_member(result, rel->part_rels[i]->relid);
-
- return result;
+ return get_matching_partitions(&context, pruning_steps);
}
/*
--
2.11.0