@@ -167,15 +167,13 @@ static List *get_steps_using_prefix(GeneratePruningStepsContext *context,
167167bool step_op_is_ne ,
168168Expr * step_lastexpr ,
169169Oid step_lastcmpfn ,
170- int step_lastkeyno ,
171170Bitmapset * step_nullkeys ,
172171List * prefix );
173172static List * get_steps_using_prefix_recurse (GeneratePruningStepsContext * context ,
174173StrategyNumber step_opstrategy ,
175174bool step_op_is_ne ,
176175Expr * step_lastexpr ,
177176Oid step_lastcmpfn ,
178- int step_lastkeyno ,
179177Bitmapset * step_nullkeys ,
180178List * prefix ,
181179ListCell * start ,
@@ -1531,7 +1529,6 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
15311529pc -> op_is_ne ,
15321530pc -> expr ,
15331531pc -> cmpfn ,
1534- 0 ,
15351532NULL ,
15361533NIL );
15371534opsteps = list_concat (opsteps ,pc_steps );
@@ -1657,7 +1654,6 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
16571654pc -> op_is_ne ,
16581655pc -> expr ,
16591656pc -> cmpfn ,
1660- pc -> keyno ,
16611657NULL ,
16621658prefix );
16631659opsteps = list_concat (opsteps ,pc_steps );
@@ -1731,7 +1727,6 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
17311727 false,
17321728pc -> expr ,
17331729pc -> cmpfn ,
1734- pc -> keyno ,
17351730nullkeys ,
17361731prefix );
17371732opsteps = list_concat (opsteps ,pc_steps );
@@ -2351,40 +2346,49 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context,
23512346
23522347/*
23532348 * get_steps_using_prefix
2354- *Generate list of PartitionPruneStepOp steps each consisting of given
2355- *opstrategy
2356- *
2357- * To generate steps, step_lastexpr and step_lastcmpfn are appended to
2358- * expressions and cmpfns, respectively, extracted from the clauses in
2359- * 'prefix'. Actually, since 'prefix' may contain multiple clauses for the
2360- * same partition key column, we must generate steps for various combinations
2361- * of the clauses of different keys.
2362- *
2363- * For list/range partitioning, callers must ensure that step_nullkeys is
2364- * NULL, and that prefix contains at least one clause for each of the
2365- * partition keys earlier than one specified in step_lastkeyno if it's
2366- * greater than zero. For hash partitioning, step_nullkeys is allowed to be
2367- * non-NULL, but they must ensure that prefix contains at least one clause
2368- * for each of the partition keys other than those specified in step_nullkeys
2369- * and step_lastkeyno.
2370- *
2371- * For both cases, callers must also ensure that clauses in prefix are sorted
2372- * in ascending order of their partition key numbers.
2349+ *Generate a list of PartitionPruneStepOps based on the given input.
2350+ *
2351+ * 'step_lastexpr' and 'step_lastcmpfn' are the Expr and comparison function
2352+ * belonging to the final partition key that we have a clause for. 'prefix'
2353+ * is a list of PartClauseInfos for partition key numbers prior to the given
2354+ * 'step_lastexpr' and 'step_lastcmpfn'. 'prefix' may contain multiple
2355+ * PartClauseInfos belonging to a single partition key. We will generate a
2356+ * PartitionPruneStepOp for each combination of the given PartClauseInfos
2357+ * using, at most, one PartClauseInfo per partition key.
2358+ *
2359+ * For LIST and RANGE partitioned tables, callers must ensure that
2360+ * step_nullkeys is NULL, and that prefix contains at least one clause for
2361+ * each of the partition keys prior to the key that 'step_lastexpr' and
2362+ * 'step_lastcmpfn'belong to.
2363+ *
2364+ * For HASH partitioned tables, callers must ensure that 'prefix' contains at
2365+ * least one clause for each of the partition keys apart from the final key
2366+ * (the expr and comparison function for the final key are in 'step_lastexpr'
2367+ * and 'step_lastcmpfn'). A bit set in step_nullkeys can substitute clauses
2368+ * in the 'prefix' list for any given key. If a bit is set in 'step_nullkeys'
2369+ * for a given key, then there must be no PartClauseInfo for that key in the
2370+ * 'prefix' list.
2371+ *
2372+ * For each of the above cases, callers must ensure that PartClauseInfos in
2373+ * 'prefix' are sorted in ascending order of keyno.
23732374 */
23742375static List *
23752376get_steps_using_prefix (GeneratePruningStepsContext * context ,
23762377StrategyNumber step_opstrategy ,
23772378bool step_op_is_ne ,
23782379Expr * step_lastexpr ,
23792380Oid step_lastcmpfn ,
2380- int step_lastkeyno ,
23812381Bitmapset * step_nullkeys ,
23822382List * prefix )
23832383{
2384+ /* step_nullkeys must be empty for RANGE and LIST partitioned tables */
23842385Assert (step_nullkeys == NULL ||
23852386context -> rel -> part_scheme -> strategy == PARTITION_STRATEGY_HASH );
23862387
2387- /* Quick exit if there are no values to prefix with. */
2388+ /*
2389+ * No recursive processing is required when 'prefix' is an empty list. This
2390+ * occurs when there is only 1 partition key column.
2391+ */
23882392if (list_length (prefix )== 0 )
23892393{
23902394PartitionPruneStep * step ;
@@ -2398,13 +2402,12 @@ get_steps_using_prefix(GeneratePruningStepsContext *context,
23982402return list_make1 (step );
23992403}
24002404
2401- /* Recurse to generate steps forvarious combinations . */
2405+ /* Recurse to generate steps forevery combination of clauses . */
24022406return get_steps_using_prefix_recurse (context ,
24032407step_opstrategy ,
24042408step_op_is_ne ,
24052409step_lastexpr ,
24062410step_lastcmpfn ,
2407- step_lastkeyno ,
24082411step_nullkeys ,
24092412prefix ,
24102413list_head (prefix ),
@@ -2413,13 +2416,17 @@ get_steps_using_prefix(GeneratePruningStepsContext *context,
24132416
24142417/*
24152418 * get_steps_using_prefix_recurse
2416- *Recursively generate combinations of clauses for different partition
2417- *keys and start generating steps upon reaching clauses for the greatest
2418- *column that is less than the one for which we're currently generating
2419- *steps (that is, step_lastkeyno)
2419+ *Generate and return a list of PartitionPruneStepOps using the 'prefix'
2420+ *list of PartClauseInfos starting at the 'start' cell.
2421+ *
2422+ * When 'prefix' contains multiple PartClauseInfos for a single partition key
2423+ * we create a PartitionPruneStepOp for each combination of duplicated
2424+ * PartClauseInfos. The returned list will contain a PartitionPruneStepOp
2425+ * for each unique combination of input PartClauseInfos containing at most one
2426+ * PartClauseInfo per partition key.
24202427 *
2421- * 'prefix' is the list of PartClauseInfos.
2422- * 'start'is where we should start iterating for the current invocation .
2428+ * 'prefix' is theinput list of PartClauseInfos sorted by keyno .
2429+ * 'start'marks the cell that searching the 'prefix' list should start from .
24232430 * 'step_exprs' and 'step_cmpfns' each contains the expressions and cmpfns
24242431 * we've generated so far from the clauses for the previous part keys.
24252432 */
@@ -2429,7 +2436,6 @@ get_steps_using_prefix_recurse(GeneratePruningStepsContext *context,
24292436bool step_op_is_ne ,
24302437Expr * step_lastexpr ,
24312438Oid step_lastcmpfn ,
2432- int step_lastkeyno ,
24332439Bitmapset * step_nullkeys ,
24342440List * prefix ,
24352441ListCell * start ,
@@ -2439,23 +2445,25 @@ get_steps_using_prefix_recurse(GeneratePruningStepsContext *context,
24392445List * result = NIL ;
24402446ListCell * lc ;
24412447int cur_keyno ;
2448+ int final_keyno ;
24422449
24432450/* Actually, recursion would be limited by PARTITION_MAX_KEYS. */
24442451check_stack_depth ();
24452452
2446- /* Check if we need to recurse. */
24472453Assert (start != NULL );
24482454cur_keyno = ((PartClauseInfo * )lfirst (start ))-> keyno ;
2449- if (cur_keyno < step_lastkeyno - 1 )
2455+ final_keyno = ((PartClauseInfo * )llast (prefix ))-> keyno ;
2456+
2457+ /* Check if we need to recurse. */
2458+ if (cur_keyno < final_keyno )
24502459{
24512460PartClauseInfo * pc ;
24522461ListCell * next_start ;
24532462
24542463/*
2455- * For each clause with cur_keyno, add its expr and cmpfn to
2456- * step_exprs and step_cmpfns, respectively, and recurse after setting
2457- * next_start to the ListCell of the first clause for the next
2458- * partition key.
2464+ * Find the first PartClauseInfo belonging to the next partition key, the
2465+ * next recursive call must start iteration of the prefix list from that
2466+ * point.
24592467 */
24602468for_each_cell (lc ,prefix ,start )
24612469{
@@ -2464,8 +2472,15 @@ get_steps_using_prefix_recurse(GeneratePruningStepsContext *context,
24642472if (pc -> keyno > cur_keyno )
24652473break ;
24662474}
2475+
2476+ /* record where to start iterating in the next recursive call */
24672477next_start = lc ;
24682478
2479+ /*
2480+ * For each PartClauseInfo with keyno set to cur_keyno, add its expr and
2481+ * cmpfn to step_exprs and step_cmpfns, respectively, and recurse using
2482+ * 'next_start' as the starting point in the 'prefix' list.
2483+ */
24692484for_each_cell (lc ,prefix ,start )
24702485{
24712486List * moresteps ;
@@ -2485,6 +2500,7 @@ get_steps_using_prefix_recurse(GeneratePruningStepsContext *context,
24852500}
24862501else
24872502{
2503+ /* check the 'prefix' list is sorted correctly */
24882504Assert (pc -> keyno > cur_keyno );
24892505break ;
24902506}
@@ -2494,7 +2510,6 @@ get_steps_using_prefix_recurse(GeneratePruningStepsContext *context,
24942510step_op_is_ne ,
24952511step_lastexpr ,
24962512step_lastcmpfn ,
2497- step_lastkeyno ,
24982513step_nullkeys ,
24992514prefix ,
25002515next_start ,
@@ -2513,8 +2528,8 @@ get_steps_using_prefix_recurse(GeneratePruningStepsContext *context,
25132528 * each clause with cur_keyno, which is all clauses from here onward
25142529 * till the end of the list. Note that for hash partitioning,
25152530 * step_nullkeys is allowed to be non-empty, in which case step_exprs
2516- * would only contain expressions for theearlier partition keys that
2517- *are not specified in step_nullkeys.
2531+ * would only contain expressions for the partition keys that are not
2532+ * specified in step_nullkeys.
25182533 */
25192534Assert (list_length (step_exprs )== cur_keyno ||
25202535 !bms_is_empty (step_nullkeys ));