diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index 7171682..7658906 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -83,6 +83,7 @@ struct ParallelAppendState struct PartitionPruneContextCache { PartitionPruneContext *context; + PartitionClauseInfo *partclauseinfo; PartitionPruneContextCache *subcache; }; @@ -714,7 +715,7 @@ set_valid_runtime_subplans_recurse(AppendState *node, context->econtext = node->ps.ps_ExprContext; context->paramids = NULL; - generate_partition_clauses(context, pinfo->prunequal); + ctxcache->partclauseinfo = generate_partition_clauses(context, pinfo->prunequal); node->part_prune_params = bms_add_members(node->part_prune_params, context->paramids); @@ -730,7 +731,7 @@ set_valid_runtime_subplans_recurse(AppendState *node, * Detect if any impossibilities were discovered during * generate_partition_clauses */ - if (context->clauseinfo->constfalse) + if (ctxcache->partclauseinfo->constfalse) { bms_free(*validsubplans); *validsubplans = NULL; @@ -747,7 +748,8 @@ set_valid_runtime_subplans_recurse(AppendState *node, * params. */ if (!bms_is_empty(context->paramids)) - partset = get_partitions_from_clauses(context); + partset = get_partitions_from_clauses(context, + ctxcache->partclauseinfo); else partset = pinfo->allsubnodes; diff --git a/src/backend/optimizer/util/partprune.c b/src/backend/optimizer/util/partprune.c index 81f66bf..010333e 100644 --- a/src/backend/optimizer/util/partprune.c +++ b/src/backend/optimizer/util/partprune.c @@ -24,21 +24,19 @@ * pruning from a list of clauses containing clauses that reference a given * partitioned table. For example, prune_append_rel_partitions() calls this * function, because a partitioned table's rel->baserestrictinfo may contain - * clauses that might be useful for partitioning. Caller must have set up a - * valid partition pruning context in the form of struct PartitionPruneContext, - * that is, each of its fields other other than clauseinfo must be valid before - * calling here. After extracting relevant clauses, clauseinfo is filled with - * information that will be used for actual pruning. + * clauses that might be useful for partitioning. The list of clauses is + * processed and a PartitionClauseInfo is returned which contains details of + * any clauses which could be matched to the partition keys of the relation + * defined in the context. * * get_partitions_from_clauses() * - * This is to be called to prune partitions based on relevant partitioning - * clauses. Caller must have called generate_partition_clauses() at least - * once and hence a valid partition pruning context must have already been - * created. Especially, PartitionPruneContext.clauseinfo must contain valid - * information. Partition pruning proceeds by extracting constant values - * from the clauses and comparing it with the partition bounds while also - * taking into account strategies of the operators in the matched clauses. + * This is to be called to prune partitions based on 'partclauseinfo'. Caller + * must have called generate_partition_clauses() in order to have generated + * a valid PartitionClauseInfo. Partition pruning proceeds by extracting + * constant values from the clauses and comparing it with the partition bounds + * while also taking into account strategies of the operators in the matched + * clauses. * * make_partition_pruneinfo() * @@ -104,18 +102,22 @@ typedef enum PartOpStrategy PART_OP_GREATER } PartOpStrategy; -static void extract_partition_clauses(PartitionPruneContext *context, - List *clauses); +static PartitionClauseInfo *extract_partition_clauses( + PartitionPruneContext *context, + List *clauses); static bool match_boolean_partition_clause(Expr *clause, Expr *partkey, Expr **rightop); static Bitmapset *get_partitions_from_or_args(PartitionPruneContext *context, - List *or_args); + List *or_args, + List *or_partclauselist); static void remove_redundant_clauses(PartitionPruneContext *context, + PartitionClauseInfo *partclauseinfo, List **minimalclauses); static bool partition_cmp_args(PartitionPruneContext *context, Oid parttypid, Oid partopfamily, PartClause *pc, PartClause *leftarg, PartClause *rightarg, bool *result); static bool extract_bounding_datums(PartitionPruneContext *context, + PartitionClauseInfo *clauseinfo, List **minimalclauses, PartScanKeyInfo *keys); static PartOpStrategy partition_op_strategy(char part_strategy, PartClause *pc, bool *incl); @@ -144,6 +146,7 @@ prune_append_rel_partitions(PlannerInfo *root, RelOptInfo *rel) else { PartitionPruneContext context; + PartitionClauseInfo *partclauseinfo; int partnatts = rel->part_scheme->partnatts, i; @@ -168,13 +171,16 @@ prune_append_rel_partitions(PlannerInfo *root, RelOptInfo *rel) context.econtext = NULL; context.paramids = NULL; - /* process clauses; context.clauseinfo will be set */ - generate_partition_clauses(&context, clauses); + /* process clauses */ + partclauseinfo = generate_partition_clauses(&context, clauses); - if (!context.clauseinfo->constfalse) + if (!partclauseinfo->constfalse) { /* Actual pruning happens here. */ - Bitmapset *partindexes = get_partitions_from_clauses(&context); + Bitmapset *partindexes; + + partindexes = get_partitions_from_clauses(&context, + partclauseinfo); /* Add selected partitions' RT indexes to result. */ i = -1; @@ -188,13 +194,10 @@ prune_append_rel_partitions(PlannerInfo *root, RelOptInfo *rel) /* * generate_partition_clauses - * Analyzes clauses to find those that match the partition key and sets - * context->clauseinfo - * - * Ideally, this should be called only once for a given query and a given - * partitioned table. + * Processes 'clauses' and returns a PartitionClauseInfo which contains + * the details of any clauses which were matched to partition keys. */ -void +PartitionClauseInfo * generate_partition_clauses(PartitionPruneContext *context, List *clauses) { /* The clauses list may be modified below, so better make a copy. */ @@ -227,25 +230,26 @@ generate_partition_clauses(PartitionPruneContext *context, List *clauses) clauses = list_concat(clauses, partqual); } - /* And away we go to do the real work; context->clauseinfo will be set */ - extract_partition_clauses(context, clauses); + /* pre-process the clauses and generate the PartitionClauseInfo */ + return extract_partition_clauses(context, clauses); } /* * get_partitions_from_clauses * Determine partitions that could possible contain a record that - * satisfies clauses as described in context->clauseinfo + * satisfies clauses as described in partclauseinfo * * Returns a Bitmapset of the matching partition indexes, or NULL if none can * match. */ Bitmapset * -get_partitions_from_clauses(PartitionPruneContext *context) +get_partitions_from_clauses(PartitionPruneContext *context, + PartitionClauseInfo *partclauseinfo) { - PartitionClauseInfo *partclauseinfo = context->clauseinfo; PartScanKeyInfo keys; Bitmapset *result; - ListCell *lc; + ListCell *lc; + ListCell *lc2; Assert(partclauseinfo != NULL); Assert(!partclauseinfo->constfalse); @@ -260,17 +264,18 @@ get_partitions_from_clauses(PartitionPruneContext *context) List *minimalclauses[PARTITION_MAX_KEYS]; /* - * For each partition key column, populate its slot in minimalclauses - * with the most restrictive of the clauses from the corresponding - * list in context->clauseinfo. + * For each partition key column, populate its element in + * minimalclauses with the most restrictive set of the clauses from + * the corresponding partition key in partclauseinfo. */ - remove_redundant_clauses(context, minimalclauses); + remove_redundant_clauses(context, partclauseinfo, minimalclauses); /* Did remove_redundant_clauses find any contradicting clauses? */ if (partclauseinfo->constfalse) return NULL; - if (extract_bounding_datums(context, minimalclauses, &keys)) + if (extract_bounding_datums(context, partclauseinfo, minimalclauses, + &keys)) { result = get_partitions_for_keys(context, &keys); @@ -292,12 +297,14 @@ get_partitions_from_clauses(PartitionPruneContext *context) } /* Now apply the OR clauses. */ - foreach(lc, partclauseinfo->or_clauses) + forboth(lc, partclauseinfo->or_clauses, lc2, + partclauseinfo->or_partclauseinfos) { List *or_args = (List *) lfirst(lc); + List *or_partclauselist = lfirst(lc2); Bitmapset *or_parts; - or_parts = get_partitions_from_or_args(context, or_args); + or_parts = get_partitions_from_or_args(context, or_args, or_partclauselist); /* * Clauses in or_clauses are mutually conjunctive and also in @@ -327,26 +334,27 @@ get_partitions_from_clauses(PartitionPruneContext *context) /* * extract_partition_clauses * Processes 'clauses' to extract clause matching the partition key. - * This adds matched clauses to the list corresponding to particular key - * in context->clauseinfo. Also collects other useful clauses to assist - * in partition elimination, such as OR clauses, clauses containing <> - * operator, and IS [NOT] NULL clauses + * Returns a PartitionClauseInfo which stores the clauses which were + * matched to the partition key. The PartitionClauseInfo also collects + * other useful clauses to assist in partition elimination, such as OR + * clauses, clauses containing <> operator, and IS [NOT] NULL clauses * * We may also discover some contradiction in the clauses which means that no - * partition can possibly match. In this case, the function sets - * context->clauseinfo's 'constfalse' to true and exits immediately without - * processing any further clauses. In this case, the caller must be careful - * not to assume the context->clauseinfo is fully populated with all clauses. + * partition can possibly match. In this case, the function sets the + * returned PartitionClauseInfo's 'constfalse' to true and exits immediately + * without processing any further clauses. In this case, the caller must be + * careful not to assume the return value is fully populated with all clauses. */ -static void +static PartitionClauseInfo * extract_partition_clauses(PartitionPruneContext *context, List *clauses) { PartitionClauseInfo *partclauseinfo; ListCell *lc; - context->clauseinfo = partclauseinfo = palloc(sizeof(PartitionClauseInfo)); + partclauseinfo = palloc(sizeof(PartitionClauseInfo)); memset(partclauseinfo->keyclauses, 0, sizeof(partclauseinfo->keyclauses)); partclauseinfo->or_clauses = NIL; + partclauseinfo->or_partclauseinfos = NIL; partclauseinfo->ne_clauses = NIL; partclauseinfo->keyisnull = NULL; partclauseinfo->keyisnotnull = NULL; @@ -367,7 +375,7 @@ extract_partition_clauses(PartitionPruneContext *context, List *clauses) !DatumGetBool(((Const *) clause)->constvalue)) { partclauseinfo->constfalse = true; - return; + return partclauseinfo; } } @@ -558,7 +566,7 @@ extract_partition_clauses(PartitionPruneContext *context, List *clauses) if (bms_is_member(i, partclauseinfo->keyisnull)) { partclauseinfo->constfalse = true; - return; + return partclauseinfo; } /* Record that a strict clause has been seen for this key */ partclauseinfo->keyisnotnull = @@ -734,7 +742,7 @@ extract_partition_clauses(PartitionPruneContext *context, List *clauses) if (bms_is_member(i, partclauseinfo->keyisnotnull)) { partclauseinfo->constfalse = true; - return; + return partclauseinfo; } partclauseinfo->keyisnull = bms_add_member(partclauseinfo->keyisnull, @@ -746,7 +754,7 @@ extract_partition_clauses(PartitionPruneContext *context, List *clauses) if (bms_is_member(i, partclauseinfo->keyisnull)) { partclauseinfo->constfalse = true; - return; + return partclauseinfo; } partclauseinfo->keyisnotnull = @@ -760,6 +768,31 @@ extract_partition_clauses(PartitionPruneContext *context, List *clauses) partclauseinfo->foundkeyclauses = true; } } + + /* + * Now pre-process any OR clauses found above and generate + * PartitionClauseInfos for them. + */ + foreach(lc, partclauseinfo->or_clauses) + { + List *or_args = lfirst(lc); + List *pclauselist = NIL; + ListCell *lc2; + + foreach (lc2, or_args) + { + List *clauses = list_make1(lfirst(lc2)); + PartitionClauseInfo *orpartclauseinfo; + + orpartclauseinfo = extract_partition_clauses(context, clauses); + pclauselist = lappend(pclauselist, orpartclauseinfo); + } + + partclauseinfo->or_partclauseinfos = + lappend(partclauseinfo->or_partclauseinfos, pclauselist); + } + + return partclauseinfo; } /* @@ -829,10 +862,11 @@ match_boolean_partition_clause(Expr *clause, Expr *partkey, * clause in or_args. */ static Bitmapset * -get_partitions_from_or_args(PartitionPruneContext *context, List *or_args) +get_partitions_from_or_args(PartitionPruneContext *context, List *or_args, + List *or_partclauselist) { Bitmapset *result = NULL; - ListCell *lc; + ListCell *lc, *lc2; /* * When matching an OR expression, it is only checked if at least one of @@ -843,20 +877,13 @@ get_partitions_from_or_args(PartitionPruneContext *context, List *or_args) * clause refutes its partition constraint, that is, we can eliminate all * of its partitions. */ - foreach(lc, or_args) + forboth(lc, or_args, lc2, or_partclauselist) { List *clauses = list_make1(lfirst(lc)); - PartitionPruneContext subcontext; + PartitionClauseInfo *or_pclause = lfirst(lc2); Bitmapset *arg_partset; - /* - * All fields except clauseinfo are same as in the parent context, - * which will be set by calling extract_partition_clauses(). - */ - memcpy(&subcontext, context, sizeof(PartitionPruneContext)); - extract_partition_clauses(&subcontext, clauses); - - if (!subcontext.clauseinfo->foundkeyclauses) + if (!or_pclause->foundkeyclauses) { List *partconstr = context->partition_qual; @@ -873,8 +900,8 @@ get_partitions_from_or_args(PartitionPruneContext *context, List *or_args) return bms_add_range(NULL, 0, context->nparts - 1); } - if (!subcontext.clauseinfo->constfalse) - arg_partset = get_partitions_from_clauses(&subcontext); + if (!or_pclause->constfalse) + arg_partset = get_partitions_from_clauses(context, or_pclause); else arg_partset = NULL; @@ -887,8 +914,8 @@ get_partitions_from_or_args(PartitionPruneContext *context, List *or_args) /* * remove_redundant_clauses - * Processes the clauses contained in context->clauseinfo to remove the - * ones that are superseeded by other clauses which are more restrictive. + * Process 'partpruneinfo' to remove the clauses that are superseeded + * by other clauses which are more restrictive. * * Finished lists of clauses are returned in *minimalclauses which is an array * with one slot for each of the partition keys. @@ -900,16 +927,16 @@ get_partitions_from_or_args(PartitionPruneContext *context, List *or_args) * that the clauses cannot possibly match any partition. Impossible clauses * include things like: x = 1 AND x = 2, x > 0 and x < 10. The function * returns right after finding such a clause and before returning, sets - * constfalse in context->clauseinfo to inform the caller that we found such + * constfalse in 'partclauseinfo' to inform the caller that we found such * clause. */ static void remove_redundant_clauses(PartitionPruneContext *context, + PartitionClauseInfo *partclauseinfo, List **minimalclauses) { PartClause *hash_clause, *btree_clauses[BTMaxStrategyNumber]; - PartitionClauseInfo *partclauseinfo = context->clauseinfo; ListCell *lc; int s; int i; @@ -1220,8 +1247,9 @@ partition_cmp_args(PartitionPruneContext *context, Oid parttypid, /* * extract_bounding_datums - * Process clauses in context->clauseinfo and populate 'keys' with all - * min/max/equal/not-equal values that we're able to determine. + * Process 'clauseinfo' and populate 'keys' with all + * min/max/equal/not-equal values that we're able to + * determine. * * *minimalclauses is an array with partnatts members, each of which is a list * of the most restrictive clauses of each operator strategy for the given @@ -1237,9 +1265,9 @@ partition_cmp_args(PartitionPruneContext *context, Oid parttypid, */ static bool extract_bounding_datums(PartitionPruneContext *context, + PartitionClauseInfo *clauseinfo, List **minimalclauses, PartScanKeyInfo *keys) { - PartitionClauseInfo *clauseinfo = context->clauseinfo; bool need_next_eq, need_next_min, need_next_max; diff --git a/src/include/optimizer/partprune.h b/src/include/optimizer/partprune.h index a761e65..ff68d4a 100644 --- a/src/include/optimizer/partprune.h +++ b/src/include/optimizer/partprune.h @@ -39,6 +39,9 @@ typedef struct PartitionClauseInfo /* Each members is a List itself of a given OR clauses's arguments. */ List *or_clauses; + /* each OR clause processed into a PartitionClauseInfo */ + List *or_partclauseinfos; + /* List of clauses containing <> operator. */ List *ne_clauses; @@ -55,9 +58,11 @@ typedef struct PartitionClauseInfo extern Relids prune_append_rel_partitions(PlannerInfo *root, RelOptInfo *rel); -extern void generate_partition_clauses(PartitionPruneContext *context, - List *clauses); -extern Bitmapset *get_partitions_from_clauses(PartitionPruneContext *context); +extern PartitionClauseInfo *generate_partition_clauses( + PartitionPruneContext *context, + List *clauses); +extern Bitmapset *get_partitions_from_clauses(PartitionPruneContext *context, + PartitionClauseInfo *partclauseinfo); extern PartitionPruneInfo *make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *rel,