@@ -714,6 +714,7 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
714
714
PruneStepResult * * results ,
715
715
* final_result ;
716
716
ListCell * lc ;
717
+ bool scan_default ;
717
718
718
719
/* If there are no pruning steps then all partitions match. */
719
720
if (num_steps == 0 )
@@ -765,30 +766,39 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
765
766
Assert (final_result != NULL );
766
767
i = -1 ;
767
768
result = NULL ;
769
+ scan_default = final_result -> scan_default ;
768
770
while ((i = bms_next_member (final_result -> bound_offsets ,i )) >=0 )
769
771
{
770
772
int partindex = context -> boundinfo -> indexes [i ];
771
773
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 );
782
792
}
783
793
784
- /* Add the null and/or default partition if needed andif present. */
794
+ /* Add the null and/or default partition if needed and present. */
785
795
if (final_result -> scan_null )
786
796
{
787
797
Assert (context -> strategy == PARTITION_STRATEGY_LIST );
788
798
Assert (partition_bound_accepts_nulls (context -> boundinfo ));
789
799
result = bms_add_member (result ,context -> boundinfo -> null_index );
790
800
}
791
- if (final_result -> scan_default )
801
+ if (scan_default )
792
802
{
793
803
Assert (context -> strategy == PARTITION_STRATEGY_LIST ||
794
804
context -> strategy == PARTITION_STRATEGY_RANGE );
@@ -2412,6 +2422,11 @@ get_matching_hash_bounds(PartitionPruneContext *context,
2412
2422
* get_matching_list_bounds
2413
2423
*Determine the offsets of list bounds matching the specified value,
2414
2424
*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
+ *
2415
2430
* 'opstrategy' if non-zero must be a btree strategy number.
2416
2431
*
2417
2432
* 'value' contains the value to use for pruning.
@@ -2614,8 +2629,13 @@ get_matching_list_bounds(PartitionPruneContext *context,
2614
2629
* Each datum whose offset is in result is to be treated as the upper bound of
2615
2630
* the partition that will contain the desired values.
2616
2631
*
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.
2619
2639
*
2620
2640
* 'opstrategy' if non-zero must be a btree strategy number.
2621
2641
*
@@ -2641,8 +2661,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
2641
2661
int * partindices = boundinfo -> indexes ;
2642
2662
int off ,
2643
2663
minoff ,
2644
- maxoff ,
2645
- i ;
2664
+ maxoff ;
2646
2665
bool is_equal ;
2647
2666
bool inclusive = false;
2648
2667
@@ -2672,13 +2691,15 @@ get_matching_range_bounds(PartitionPruneContext *context,
2672
2691
*/
2673
2692
if (nvalues == 0 )
2674
2693
{
2694
+ /* ignore key space not covered by any partitions */
2675
2695
if (partindices [minoff ]< 0 )
2676
2696
minoff ++ ;
2677
2697
if (partindices [maxoff ]< 0 )
2678
2698
maxoff -- ;
2679
2699
2680
2700
result -> scan_default = partition_bound_has_default (boundinfo );
2681
- Assert (minoff >=0 && maxoff >=0 );
2701
+ Assert (partindices [minoff ] >=0 &&
2702
+ partindices [maxoff ] >=0 );
2682
2703
result -> bound_offsets = bms_add_range (NULL ,minoff ,maxoff );
2683
2704
2684
2705
return result ;
@@ -2706,11 +2727,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
2706
2727
if (nvalues == partnatts )
2707
2728
{
2708
2729
/* 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 );
2714
2731
return result ;
2715
2732
}
2716
2733
else
@@ -2798,57 +2815,21 @@ get_matching_range_bounds(PartitionPruneContext *context,
2798
2815
maxoff = off + 1 ;
2799
2816
}
2800
2817
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
-
2827
2818
Assert (minoff >=0 && maxoff >=0 );
2828
2819
result -> bound_offsets = bms_add_range (NULL ,minoff ,maxoff );
2829
2820
}
2830
- else if ( off >= 0 ) /* !is_equal */
2821
+ else
2831
2822
{
2832
2823
/*
2833
2824
* The lookup value falls in the range between some bounds in
2834
2825
* boundinfo. 'off' would be the offset of the greatest bound
2835
2826
* that is <= lookup value, so add off + 1 to the result
2836
2827
* 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.
2850
2831
*/
2851
- result -> scan_default = partition_bound_has_default ( boundinfo );
2832
+ result -> bound_offsets = bms_make_singleton ( off + 1 );
2852
2833
}
2853
2834
2854
2835
return result ;
@@ -2919,16 +2900,18 @@ get_matching_range_bounds(PartitionPruneContext *context,
2919
2900
2920
2901
minoff = inclusive ?off :off + 1 ;
2921
2902
}
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
- */
2930
2903
else
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
+ */
2931
2913
minoff = off + 1 ;
2914
+ }
2932
2915
}
2933
2916
break ;
2934
2917
@@ -2946,16 +2929,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
2946
2929
boundinfo ,
2947
2930
nvalues ,values ,
2948
2931
& 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 )
2959
2933
{
2960
2934
/*
2961
2935
* See the comment above.
@@ -3003,65 +2977,58 @@ get_matching_range_bounds(PartitionPruneContext *context,
3003
2977
else
3004
2978
maxoff = off ;
3005
2979
}
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
+ }
3006
2988
break ;
3007
2989
3008
2990
default :
3009
2991
elog (ERROR ,"invalid strategy number %d" ,opstrategy );
3010
2992
break ;
3011
2993
}
3012
2994
2995
+ Assert (minoff >=0 && minoff <=boundinfo -> ndatums );
2996
+ Assert (maxoff >=0 && maxoff <=boundinfo -> ndatums );
2997
+
3013
2998
/*
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.
3019
3003
*/
3020
- if (partindices [minoff ]< 0 )
3004
+ if (minoff < boundinfo -> ndatums && partindices [minoff ]< 0 )
3021
3005
{
3022
3006
int lastkey = nvalues - 1 ;
3023
3007
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
+ }
3031
3014
}
3032
3015
3033
3016
/*
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.
3037
3022
*/
3038
3023
if (maxoff >=1 && partindices [maxoff ]< 0 )
3039
3024
{
3040
3025
int lastkey = nvalues - 1 ;
3041
3026
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 )
3059
3029
{
3060
- if (partindices [i ]< 0 )
3061
- {
3062
- result -> scan_default = true;
3063
- break ;
3064
- }
3030
+ maxoff -- ;
3031
+ Assert (boundinfo -> indexes [maxoff ] >=0 );
3065
3032
}
3066
3033
}
3067
3034
@@ -3306,14 +3273,24 @@ perform_pruning_combine_step(PartitionPruneContext *context,
3306
3273
3307
3274
/*
3308
3275
* 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 .
3310
3277
*/
3311
3278
result = (PruneStepResult * )palloc0 (sizeof (PruneStepResult ));
3312
3279
if (list_length (cstep -> source_stepids )== 0 )
3313
3280
{
3314
3281
PartitionBoundInfo 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 ;
3315
3291
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 );
3317
3294
result -> scan_default = partition_bound_has_default (boundinfo );
3318
3295
result -> scan_null = partition_bound_accepts_nulls (boundinfo );
3319
3296
return result ;