From b327d5f6192e482b72b08603850b589b59bd556e Mon Sep 17 00:00:00 2001 From: amit Date: Mon, 4 Mar 2019 11:43:38 +0900 Subject: [PATCH v36 4/7] Perform pruning in expand_partitioned_rtentry This allows to avoid opening/locking partitions that won't be scanned at all. expand_partitioned_rtentry recursively processes sub-partitioned tables, which in turn performs partition pruning for them. To do so, the translated quals must be added exactly when the child RelOptInfo is built for the sub-partitioned tables, instead of delaying that to set_append_rel_size() as is done today. So, build_simple_rel() itself performs apply_child_basequals() now. 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 on one side of the join may need to be joined to the non-pruned counterpart on the other side, if the pruned partition 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/executor/execPartition.c | 17 ++- 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 | 25 ++- src/backend/optimizer/util/relnode.c | 155 +++++++++++++++++++ src/backend/partitioning/partprune.c | 45 +++--- src/test/regress/expected/partition_aggregate.out | 4 +- 8 files changed, 319 insertions(+), 203 deletions(-) diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index cfad8a38f0..a635de7ee4 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -1654,9 +1654,20 @@ ExecCreatePartitionPruneState(PlanState *planstate, memcpy(pprune->subplan_map, pinfo->subplan_map, sizeof(int) * pinfo->nparts); - /* Double-check that list of relations has not changed. */ - Assert(memcmp(partdesc->oids, pinfo->relid_map, - pinfo->nparts * sizeof(Oid)) == 0); +#ifdef USE_ASSERT_CHECKING + /* + * Double-check that list of unpruned relations has not + * changed. + */ + { + int k; + + /* Pruned partitions are not added to relid_map. */ + for (k = 0; k < pinfo->nparts; k++) + Assert(partdesc->oids[k] == pinfo->relid_map[k] || + pinfo->subplan_map[k] == -1); + } +#endif } else { diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 56a5084312..bb4a0510b7 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -139,9 +139,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); /* @@ -946,8 +943,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(); @@ -966,21 +961,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. @@ -1034,30 +1014,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)) { /* @@ -1069,7 +1030,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. @@ -3594,134 +3556,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 9604a54b77..83c24a45b8 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" @@ -51,6 +54,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); /* @@ -1346,6 +1352,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; @@ -1396,6 +1404,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 @@ -1412,6 +1432,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 @@ -1472,6 +1499,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); } /* @@ -1490,8 +1522,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 would 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; } @@ -1702,3 +1740,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 01b887568c..16b0290fd4 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -7008,6 +7008,10 @@ apply_scanjoin_target_to_paths(PlannerInfo *root, List *child_scanjoin_targets = NIL; ListCell *lc; + /* 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); @@ -7108,6 +7112,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 f7995a323d..aeb622c870 100644 --- a/src/backend/optimizer/util/inherit.c +++ b/src/backend/optimizer/util/inherit.c @@ -29,6 +29,7 @@ #include "optimizer/prep.h" #include "parser/parsetree.h" #include "partitioning/partdesc.h" +#include "partitioning/partprune.h" #include "utils/rel.h" @@ -294,6 +295,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; @@ -341,22 +343,37 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte, is_source_inh_expansion = (root->simple_rel_array_size > 0); if (is_source_inh_expansion && partdesc->nparts > 0) { + int num_live_parts; + rel = find_base_rel(root, parentRTindex); + /* + * Perform partition pruning using restriction clauses assigned to + * parent relation. live_parts will contain PartitionDesc indexes + * of partitions that survive pruning. Below, we will initialize + * child objects for the surviving partitions. + */ + live_parts = prune_append_rel_partitions(rel); + /* Expand simple_rel_array and friends to hold child objects. */ - expand_planner_arrays(root, partdesc->nparts); + num_live_parts = bms_num_members(live_parts); + if (num_live_parts > 0) + expand_planner_arrays(root, num_live_parts); /* * We also store partition RelOptInfo pointers in the parent - * relation. + * relation. Since we're palloc0'ing, slots corresponding to + * pruned partitions will contain NULL. */ 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); - 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 c64d6b72cc..dadeffa0a0 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. + */ + mark_dummy_rel(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 doesn't need to 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 * diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index af3f91133e..bca26bcfbb 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 "parser/parsetree.h" @@ -474,18 +475,24 @@ 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)); - relid_map = (Oid *) palloc(nparts * sizeof(Oid)); + memset(subpart_map, -1, nparts * sizeof(Oid)); + relid_map = (Oid *) palloc0(nparts * sizeof(Oid)); 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; relid_map[i] = planner_rt_fetch(partrel->relid, root)->relid; if (subplanidx >= 0) { @@ -567,23 +574,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 */ @@ -591,6 +595,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. */ @@ -617,15 +628,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); } /* diff --git a/src/test/regress/expected/partition_aggregate.out b/src/test/regress/expected/partition_aggregate.out index 6bc106831e..1450cef057 100644 --- a/src/test/regress/expected/partition_aggregate.out +++ b/src/test/regress/expected/partition_aggregate.out @@ -144,7 +144,7 @@ SELECT c, sum(a) FROM pagg_tab WHERE 1 = 2 GROUP BY c; QUERY PLAN -------------------------------- HashAggregate - Group Key: pagg_tab.c + Group Key: c -> Result One-Time Filter: false (4 rows) @@ -159,7 +159,7 @@ SELECT c, sum(a) FROM pagg_tab WHERE c = 'x' GROUP BY c; QUERY PLAN -------------------------------- GroupAggregate - Group Key: pagg_tab.c + Group Key: c -> Result One-Time Filter: false (4 rows) -- 2.11.0