@@ -714,6 +714,7 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
714714PruneStepResult * * results ,
715715* final_result ;
716716ListCell * lc ;
717+ bool scan_default ;
717718
718719/* If there are no pruning steps then all partitions match. */
719720if (num_steps == 0 )
@@ -765,30 +766,39 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
765766Assert (final_result != NULL );
766767i = -1 ;
767768result = NULL ;
769+ scan_default = final_result -> scan_default ;
768770while ((i = bms_next_member (final_result -> bound_offsets ,i )) >=0 )
769771{
770772int partindex = context -> boundinfo -> indexes [i ];
771773
772- /*
773- * In range and hash partitioning cases, some slots may contain -1,
774- * indicating that no partition has been defined to accept a given
775- * range of data or for a given remainder, respectively. The default
776- * partition, if any, in case of range partitioning, will be added to
777- * the result, because the specified range still satisfies the query's
778- * conditions.
779- */
780- if (partindex >=0 )
781- result = bms_add_member (result ,partindex );
774+ if (partindex < 0 )
775+ {
776+ /*
777+ * In range partitioning cases, if a partition index is -1 it
778+ * means that the bound at the offset is the upper bound for a
779+ * range not covered by any partition (other than a possible
780+ * default partition). In hash partitioning, the same means no
781+ * partition has been defined for the corresponding remainder
782+ * value.
783+ *
784+ * In either case, the value is still part of the queried range of
785+ * values, so mark to scan the default partition if one exists.
786+ */
787+ scan_default |=partition_bound_has_default (context -> boundinfo );
788+ continue ;
789+ }
790+
791+ result = bms_add_member (result ,partindex );
782792}
783793
784- /* Add the null and/or default partition if needed andif present. */
794+ /* Add the null and/or default partition if needed and present. */
785795if (final_result -> scan_null )
786796{
787797Assert (context -> strategy == PARTITION_STRATEGY_LIST );
788798Assert (partition_bound_accepts_nulls (context -> boundinfo ));
789799result = bms_add_member (result ,context -> boundinfo -> null_index );
790800}
791- if (final_result -> scan_default )
801+ if (scan_default )
792802{
793803Assert (context -> strategy == PARTITION_STRATEGY_LIST ||
794804context -> strategy == PARTITION_STRATEGY_RANGE );
@@ -2412,6 +2422,11 @@ get_matching_hash_bounds(PartitionPruneContext *context,
24122422 * get_matching_list_bounds
24132423 *Determine the offsets of list bounds matching the specified value,
24142424 *according to the semantics of the given operator strategy
2425+ *
2426+ * scan_default will be set in the returned struct, if the default partition
2427+ * needs to be scanned, provided one exists at all. scan_null will be set if
2428+ * the special null-accepting partition needs to be scanned.
2429+ *
24152430 * 'opstrategy' if non-zero must be a btree strategy number.
24162431 *
24172432 * 'value' contains the value to use for pruning.
@@ -2614,8 +2629,13 @@ get_matching_list_bounds(PartitionPruneContext *context,
26142629 * Each datum whose offset is in result is to be treated as the upper bound of
26152630 * the partition that will contain the desired values.
26162631 *
2617- * If default partition needs to be scanned for given values, set scan_default
2618- * in result if present.
2632+ * scan_default is set in the returned struct if a default partition exists
2633+ * and we're absolutely certain that it needs to be scanned. We do *not* set
2634+ * it just because values match portions of the key space uncovered by
2635+ * partitions other than default (space which we normally assume to belong to
2636+ * the default partition): the final set of bounds obtained after combining
2637+ * multiple pruning steps might exclude it, so we infer its inclusion
2638+ * elsewhere.
26192639 *
26202640 * 'opstrategy' if non-zero must be a btree strategy number.
26212641 *
@@ -2641,8 +2661,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
26412661int * partindices = boundinfo -> indexes ;
26422662int off ,
26432663minoff ,
2644- maxoff ,
2645- i ;
2664+ maxoff ;
26462665bool is_equal ;
26472666bool inclusive = false;
26482667
@@ -2672,13 +2691,15 @@ get_matching_range_bounds(PartitionPruneContext *context,
26722691 */
26732692if (nvalues == 0 )
26742693{
2694+ /* ignore key space not covered by any partitions */
26752695if (partindices [minoff ]< 0 )
26762696minoff ++ ;
26772697if (partindices [maxoff ]< 0 )
26782698maxoff -- ;
26792699
26802700result -> scan_default = partition_bound_has_default (boundinfo );
2681- Assert (minoff >=0 && maxoff >=0 );
2701+ Assert (partindices [minoff ] >=0 &&
2702+ partindices [maxoff ] >=0 );
26822703result -> bound_offsets = bms_add_range (NULL ,minoff ,maxoff );
26832704
26842705return result ;
@@ -2706,11 +2727,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
27062727if (nvalues == partnatts )
27072728{
27082729/* There can only be zero or one matching partition. */
2709- if (partindices [off + 1 ] >=0 )
2710- result -> bound_offsets = bms_make_singleton (off + 1 );
2711- else
2712- result -> scan_default =
2713- partition_bound_has_default (boundinfo );
2730+ result -> bound_offsets = bms_make_singleton (off + 1 );
27142731return result ;
27152732}
27162733else
@@ -2798,57 +2815,21 @@ get_matching_range_bounds(PartitionPruneContext *context,
27982815maxoff = off + 1 ;
27992816}
28002817
2801- /*
2802- * Skip if minoff/maxoff are actually the upper bound of a
2803- * un-assigned portion of values.
2804- */
2805- if (partindices [minoff ]< 0 && minoff < boundinfo -> ndatums )
2806- minoff ++ ;
2807- if (partindices [maxoff ]< 0 && maxoff >=1 )
2808- maxoff -- ;
2809-
2810- /*
2811- * There may exist a range of values unassigned to any
2812- * non-default partition between the datums at minoff and
2813- * maxoff. Add the default partition in that case.
2814- */
2815- if (partition_bound_has_default (boundinfo ))
2816- {
2817- for (i = minoff ;i <=maxoff ;i ++ )
2818- {
2819- if (partindices [i ]< 0 )
2820- {
2821- result -> scan_default = true;
2822- break ;
2823- }
2824- }
2825- }
2826-
28272818Assert (minoff >=0 && maxoff >=0 );
28282819result -> bound_offsets = bms_add_range (NULL ,minoff ,maxoff );
28292820}
2830- else if ( off >= 0 ) /* !is_equal */
2821+ else
28312822{
28322823/*
28332824 * The lookup value falls in the range between some bounds in
28342825 * boundinfo. 'off' would be the offset of the greatest bound
28352826 * that is <= lookup value, so add off + 1 to the result
28362827 * instead as the offset of the upper bound of the only
2837- * partition that may contain the lookup value.
2838- */
2839- if (partindices [off + 1 ] >=0 )
2840- result -> bound_offsets = bms_make_singleton (off + 1 );
2841- else
2842- result -> scan_default =
2843- partition_bound_has_default (boundinfo );
2844- }
2845- else
2846- {
2847- /*
2848- * off < 0: the lookup value is smaller than all bounds, so
2849- * only the default partition qualifies, if there is one.
2828+ * partition that may contain the lookup value. If 'off' is
2829+ * -1 indicating that all bounds are greater, then we simply
2830+ * end up adding the first bound's offset, that is, 0.
28502831 */
2851- result -> scan_default = partition_bound_has_default ( boundinfo );
2832+ result -> bound_offsets = bms_make_singleton ( off + 1 );
28522833}
28532834
28542835return result ;
@@ -2919,16 +2900,18 @@ get_matching_range_bounds(PartitionPruneContext *context,
29192900
29202901minoff = inclusive ?off :off + 1 ;
29212902}
2922-
2923- /*
2924- * lookup value falls in the range between some bounds in
2925- * boundinfo. off would be the offset of the greatest bound
2926- * that is <= lookup value, so add off + 1 to the result
2927- * instead as the offset of the upper bound of the smallest
2928- * partition that may contain the lookup value.
2929- */
29302903else
2904+ {
2905+
2906+ /*
2907+ * lookup value falls in the range between some bounds in
2908+ * boundinfo. off would be the offset of the greatest
2909+ * bound that is <= lookup value, so add off + 1 to the
2910+ * result instead as the offset of the upper bound of the
2911+ * smallest partition that may contain the lookup value.
2912+ */
29312913minoff = off + 1 ;
2914+ }
29322915}
29332916break ;
29342917
@@ -2946,16 +2929,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
29462929boundinfo ,
29472930nvalues ,values ,
29482931& is_equal );
2949- if (off < 0 )
2950- {
2951- /*
2952- * All bounds are greater than the key, so we could only
2953- * expect to find the lookup key in the default partition.
2954- */
2955- result -> scan_default = partition_bound_has_default (boundinfo );
2956- return result ;
2957- }
2958- else
2932+ if (off >=0 )
29592933{
29602934/*
29612935 * See the comment above.
@@ -3003,65 +2977,58 @@ get_matching_range_bounds(PartitionPruneContext *context,
30032977else
30042978maxoff = off ;
30052979}
2980+ else
2981+ {
2982+ /*
2983+ * 'off' is -1 indicating that all bounds are greater, so just
2984+ * set the first bound's offset as maxoff.
2985+ */
2986+ maxoff = off + 1 ;
2987+ }
30062988break ;
30072989
30082990default :
30092991elog (ERROR ,"invalid strategy number %d" ,opstrategy );
30102992break ;
30112993}
30122994
2995+ Assert (minoff >=0 && minoff <=boundinfo -> ndatums );
2996+ Assert (maxoff >=0 && maxoff <=boundinfo -> ndatums );
2997+
30132998/*
3014- * Skip a gap and when doing so, check if the bound contains a finite
3015- * value to decide if we need to add the default partition. If it's an
3016- * infinite bound, we need not add the default partition, as having an
3017- * infinite bound means the partition in question catches any values that
3018- * would otherwise be in the default partition.
2999+ * If the smallest partition to return has MINVALUE (negative infinity) as
3000+ * its lower bound, increment it to point to the next finite bound
3001+ * (supposedly its upper bound), so that we don't advertently end up
3002+ * scanning the default partition.
30193003 */
3020- if (partindices [minoff ]< 0 )
3004+ if (minoff < boundinfo -> ndatums && partindices [minoff ]< 0 )
30213005{
30223006int lastkey = nvalues - 1 ;
30233007
3024- if (minoff >=0 &&
3025- minoff < boundinfo -> ndatums &&
3026- boundinfo -> kind [minoff ][lastkey ]==
3027- PARTITION_RANGE_DATUM_VALUE )
3028- result -> scan_default = partition_bound_has_default (boundinfo );
3029-
3030- minoff ++ ;
3008+ if (boundinfo -> kind [minoff ][lastkey ]==
3009+ PARTITION_RANGE_DATUM_MINVALUE )
3010+ {
3011+ minoff ++ ;
3012+ Assert (boundinfo -> indexes [minoff ] >=0 );
3013+ }
30313014}
30323015
30333016/*
3034- * Skip a gap. See the above comment about how we decide whether or not
3035- * to scan the default partition based whether the datum that will become
3036- * the maximum datum is finite or not.
3017+ * If the previous greatest partition has MAXVALUE (positive infinity) as
3018+ * its upper bound (something only possible to do with multi-column range
3019+ * partitioning), we scan switch to it as the greatest partition to
3020+ * return. Again, so that we don't advertently end up scanning the
3021+ * default partition.
30373022 */
30383023if (maxoff >=1 && partindices [maxoff ]< 0 )
30393024{
30403025int lastkey = nvalues - 1 ;
30413026
3042- if (maxoff >=0 &&
3043- maxoff <=boundinfo -> ndatums &&
3044- boundinfo -> kind [maxoff - 1 ][lastkey ]==
3045- PARTITION_RANGE_DATUM_VALUE )
3046- result -> scan_default = partition_bound_has_default (boundinfo );
3047-
3048- maxoff -- ;
3049- }
3050-
3051- if (partition_bound_has_default (boundinfo ))
3052- {
3053- /*
3054- * There may exist a range of values unassigned to any non-default
3055- * partition between the datums at minoff and maxoff. Add the default
3056- * partition in that case.
3057- */
3058- for (i = minoff ;i <=maxoff ;i ++ )
3027+ if (boundinfo -> kind [maxoff - 1 ][lastkey ]==
3028+ PARTITION_RANGE_DATUM_MAXVALUE )
30593029{
3060- if (partindices [i ]< 0 )
3061- {
3062- result -> scan_default = true;
3063- break ;
3064- }
3030+ maxoff -- ;
3031+ Assert (boundinfo -> indexes [maxoff ] >=0 );
30653032}
30663033}
30673034
@@ -3306,14 +3273,24 @@ perform_pruning_combine_step(PartitionPruneContext *context,
33063273
33073274/*
33083275 * A combine step without any source steps is an indication to not perform
3309- * any partition pruning, we just return allpartitions .
3276+ * any partition pruning. Return alldatum indexes in that case .
33103277 */
33113278result = (PruneStepResult * )palloc0 (sizeof (PruneStepResult ));
33123279if (list_length (cstep -> source_stepids )== 0 )
33133280{
33143281PartitionBoundInfo boundinfo = context -> boundinfo ;
3282+ int rangemax ;
3283+
3284+ /*
3285+ * Add all valid offsets into the boundinfo->indexes array. For range
3286+ * partitioning, boundinfo->indexes contains (boundinfo->ndatums + 1)
3287+ * valid entries; otherwise there are boundinfo->ndatums.
3288+ */
3289+ rangemax = context -> strategy == PARTITION_STRATEGY_RANGE ?
3290+ boundinfo -> ndatums :boundinfo -> ndatums - 1 ;
33153291
3316- result -> bound_offsets = bms_add_range (NULL ,0 ,boundinfo -> ndatums - 1 );
3292+ result -> bound_offsets =
3293+ bms_add_range (result -> bound_offsets ,0 ,rangemax );
33173294result -> scan_default = partition_bound_has_default (boundinfo );
33183295result -> scan_null = partition_bound_accepts_nulls (boundinfo );
33193296return result ;