diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index d08739127b..9215f566b7 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -156,8 +156,8 @@ static PartitionPruneStep *gen_prune_step_op(GeneratePruningStepsContext *contex static PartitionPruneStep *gen_prune_step_combine(GeneratePruningStepsContext *context, List *source_stepids, PartitionPruneCombineOp combineOp); -static PartitionPruneStep *gen_prune_steps_from_opexps(GeneratePruningStepsContext *context, - List **keyclauses, Bitmapset *nullkeys); +static List *gen_prune_steps_from_opexps(GeneratePruningStepsContext *context, + List **keyclauses, Bitmapset *nullkeys); static PartClauseMatchStatus match_clause_to_partition_key(GeneratePruningStepsContext *context, Expr *clause, Expr *partkey, int partkeyidx, bool *clause_is_not_null, @@ -926,24 +926,23 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps) * gen_partprune_steps_internal * Processes 'clauses' to generate partition pruning steps. * - * From OpExpr clauses that are mutually AND'd, we find combinations of those - * that match to the partition key columns and for every such combination, - * we emit a PartitionPruneStepOp containing a vector of expressions whose - * values are used as a look up key to search partitions by comparing the - * values with partition bounds. Relevant details of the operator and a - * vector of (possibly cross-type) comparison functions is also included with - * each step. + * From OpExpr clauses that are mutually ANDed, we find combinations of those + * that match the partition key columns and make one or more "op" steps + * (PartitionPruneStepOp) from those clause combinations; details of how the + * combinations can be found in gen_prune_steps_from_opexps(). Each step thus + * created is added to context->steps * - * For BoolExpr clauses, we recursively generate steps for each argument, and - * return a PartitionPruneStepCombine of their results. + * For BoolExpr clauses, each argument is processed recursively and to + * mix the results of the steps resulting from each, a "combine" step + * (PartitionPruneStepCombine) is added to context->steps. * - * The return value is a list of the steps generated, which are also added to - * the context's steps list. Each step is assigned a step identifier, unique - * even across recursive calls. + * The return value is the list of steps to evaluate to get the partition set + * satisfying the provided clauses. Note that all of those steps would also + * have been added to context->steps. * * If we find clauses that are mutually contradictory, or contradictory with * the partitioning constraint, or a pseudoconstant clause that contains - * false, we set context->contradictory to true and return NIL (that is, no + * false, we set context->contradictory to true and return NULL (that is, no * pruning steps). Caller should consider all partitions as pruned in that * case. */ @@ -975,7 +974,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, predicate_refuted_by(context->rel->partition_qual, clauses, false)) { context->contradictory = true; - return NIL; + return NULL; } memset(keyclauses, 0, sizeof(keyclauses)); @@ -994,7 +993,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, !DatumGetBool(((Const *) clause)->constvalue))) { context->contradictory = true; - return NIL; + return NULL; } /* Get the BoolExpr's out of the way. */ @@ -1046,11 +1045,14 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, if (argsteps != NIL) { - PartitionPruneStep *step; + /* + * Because of the way gen_partprune_steps_internal() + * generates its result list, it suffices to only add + * the last of the steps we got from it. + */ + PartitionPruneStep *last = llast(argsteps); - Assert(list_length(argsteps) == 1); - step = (PartitionPruneStep *) linitial(argsteps); - arg_stepids = lappend_int(arg_stepids, step->step_id); + arg_stepids = lappend_int(arg_stepids, last->step_id); } else { @@ -1073,7 +1075,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, if (all_args_contradictory) { context->contradictory = true; - return NIL; + return NULL; } if (arg_stepids != NIL) @@ -1089,9 +1091,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, else if (is_andclause(clause)) { List *args = ((BoolExpr *) clause)->args; - List *argsteps, - *arg_stepids = NIL; - ListCell *lc1; + List *argsteps; /* * args may itself contain clauses of arbitrary type, so just @@ -1102,23 +1102,16 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, /* If any AND arm is contradictory, we can stop immediately */ if (context->contradictory) - return NIL; - - foreach(lc1, argsteps) - { - PartitionPruneStep *step = lfirst(lc1); - - arg_stepids = lappend_int(arg_stepids, step->step_id); - } + return NULL; - if (arg_stepids != NIL) - { - PartitionPruneStep *step; + /* + * Because of the way gen_partprune_steps_internal() generates + * its result list, it suffices to only add the last of the + * steps we got from it. + */ + if (argsteps != NIL) + result = lappend(result, llast(argsteps)); - step = gen_prune_step_combine(context, arg_stepids, - PARTPRUNE_COMBINE_INTERSECT); - result = lappend(result, step); - } continue; } @@ -1155,7 +1148,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, if (bms_is_member(i, nullkeys)) { context->contradictory = true; - return NIL; + return NULL; } generate_opsteps = true; keyclauses[i] = lappend(keyclauses[i], pc); @@ -1172,7 +1165,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, keyclauses[i] != NIL) { context->contradictory = true; - return NIL; + return NULL; } nullkeys = bms_add_member(nullkeys, i); } @@ -1182,7 +1175,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, if (bms_is_member(i, nullkeys)) { context->contradictory = true; - return NIL; + return NULL; } notnullkeys = bms_add_member(notnullkeys, i); } @@ -1196,7 +1189,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, case PARTCLAUSE_MATCH_CONTRADICT: /* We've nothing more to do if a contradiction was found. */ context->contradictory = true; - return NIL; + return NULL; case PARTCLAUSE_NOMATCH: @@ -1253,12 +1246,11 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, } else if (generate_opsteps) { - PartitionPruneStep *step; + List *opsteps; /* Strategy 2 */ - step = gen_prune_steps_from_opexps(context, keyclauses, nullkeys); - if (step != NULL) - result = lappend(result, step); + opsteps = gen_prune_steps_from_opexps(context, keyclauses, nullkeys); + result = list_concat(result, opsteps); } else if (bms_num_members(notnullkeys) == part_scheme->partnatts) { @@ -1271,12 +1263,14 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, } /* - * Finally, results from all entries appearing in result should be - * combined using an INTERSECT combine step, if more than one. + * Finally, if there are multiple steps, add an INTERSECT step to combine + * the partition sets resulting from them and append it to the result + * list. */ if (list_length(result) > 1) { List *step_ids = NIL; + PartitionPruneStep *final; foreach(lc, result) { @@ -1285,14 +1279,9 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, step_ids = lappend_int(step_ids, step->step_id); } - if (step_ids != NIL) - { - PartitionPruneStep *step; - - step = gen_prune_step_combine(context, step_ids, - PARTPRUNE_COMBINE_INTERSECT); - result = lappend(result, step); - } + final = gen_prune_step_combine(context, step_ids, + PARTPRUNE_COMBINE_INTERSECT); + result = lappend(result, final); } return result; @@ -1356,15 +1345,28 @@ gen_prune_step_combine(GeneratePruningStepsContext *context, /* * gen_prune_steps_from_opexps - * Generate pruning steps based on clauses for partition keys + * Generate pruning "op" steps (PartitionPruneStepOp) based on OpExpr + * clauses that have been matched to partition keys * - * 'keyclauses' contains one list of clauses per partition key. We check here - * if we have found clauses for a valid subset of the partition key. In some - * cases, (depending on the type of partitioning being used) if we didn't - * find clauses for a given key, we discard clauses that may have been + * 'keyclauses' contains a list of clauses for each partition key. We check + * here if we have found clauses for a valid subset of the partition keys. In + * some cases, depending on the type of partitioning being used, if we don't + * see clauses for a given key, we discard clauses that may have been * found for any subsequent keys; see specific notes below. + * + * Each "op" step generated here will contain a vector of expressions whose + * values will constitute a tuple to be used as the look up key to search + * partitions by comparing it with partition bound tuples in the + * PartitionBoundInfo of the parent table, along with the effective operator + * strategy to use in those comparisons (=, >, <, etc.), and a vector of + * possibly cross-type comparison functions. + * + * Note that if multiple steps are returned, the partition set satisfying all + * the clauses is the one obtained by intersecting the partition sets of those + * individual steps, which the caller should do by adding a relevant "combine" + * step. */ -static PartitionPruneStep * +static List * gen_prune_steps_from_opexps(GeneratePruningStepsContext *context, List **keyclauses, Bitmapset *nullkeys) { @@ -1397,7 +1399,7 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context, */ if (part_scheme->strategy == PARTITION_STRATEGY_HASH && clauselist == NIL && !bms_is_member(i, nullkeys)) - return NULL; + return NIL; foreach(lc, clauselist) { @@ -1728,27 +1730,7 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context, break; } - /* Lastly, add a combine step to mutually AND these op steps, if needed */ - if (list_length(opsteps) > 1) - { - List *opstep_ids = NIL; - - foreach(lc, opsteps) - { - PartitionPruneStep *step = lfirst(lc); - - opstep_ids = lappend_int(opstep_ids, step->step_id); - } - - if (opstep_ids != NIL) - return gen_prune_step_combine(context, opstep_ids, - PARTPRUNE_COMBINE_INTERSECT); - return NULL; - } - else if (opsteps != NIL) - return linitial(opsteps); - - return NULL; + return opsteps; } /* @@ -1782,8 +1764,8 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context, * true otherwise. * * * PARTCLAUSE_MATCH_STEPS if there is a match. - * Output arguments: *clause_steps is set to a list of PartitionPruneStep - * generated for the clause. + * Output arguments: *clause_steps is set to the list of recursively + * generated steps for the clause. * * * PARTCLAUSE_MATCH_CONTRADICT if the clause is self-contradictory, ie * it provably returns FALSE or NULL.