@@ -735,6 +735,7 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
735
735
PruneStepResult * * results ,
736
736
* final_result ;
737
737
ListCell * lc ;
738
+ bool scan_default ;
738
739
739
740
/* If there are no pruning steps then all partitions match. */
740
741
if (num_steps == 0 )
@@ -786,30 +787,39 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
786
787
Assert (final_result != NULL );
787
788
i = -1 ;
788
789
result = NULL ;
790
+ scan_default = final_result -> scan_default ;
789
791
while ((i = bms_next_member (final_result -> bound_offsets , i )) >= 0 )
790
792
{
791
793
int partindex = context -> boundinfo -> indexes [i ];
792
794
793
- /*
794
- * In range and hash partitioning cases, some slots may contain -1,
795
- * indicating that no partition has been defined to accept a given
796
- * range of data or for a given remainder, respectively. The default
797
- * partition, if any, in case of range partitioning, will be added to
798
- * the result, because the specified range still satisfies the query's
799
- * conditions.
800
- */
801
- if (partindex >= 0 )
802
- result = bms_add_member (result , partindex );
795
+ if (partindex < 0 )
796
+ {
797
+ /*
798
+ * In range partitioning cases, if a partition index is -1 it
799
+ * means that the bound at the offset is the upper bound for a
800
+ * range not covered by any partition (other than a possible
801
+ * default partition). In hash partitioning, the same means no
802
+ * partition has been defined for the corresponding remainder
803
+ * value.
804
+ *
805
+ * In either case, the value is still part of the queried range of
806
+ * values, so mark to scan the default partition if one exists.
807
+ */
808
+ scan_default |= partition_bound_has_default (context -> boundinfo );
809
+ continue ;
810
+ }
811
+
812
+ result = bms_add_member (result , partindex );
803
813
}
804
814
805
- /* Add the null and/or default partition if needed and if present. */
815
+ /* Add the null and/or default partition if needed and present. */
806
816
if (final_result -> scan_null )
807
817
{
808
818
Assert (context -> strategy == PARTITION_STRATEGY_LIST );
809
819
Assert (partition_bound_accepts_nulls (context -> boundinfo ));
810
820
result = bms_add_member (result , context -> boundinfo -> null_index );
811
821
}
812
- if (final_result -> scan_default )
822
+ if (scan_default )
813
823
{
814
824
Assert (context -> strategy == PARTITION_STRATEGY_LIST ||
815
825
context -> strategy == PARTITION_STRATEGY_RANGE );
@@ -2438,6 +2448,11 @@ get_matching_hash_bounds(PartitionPruneContext *context,
2438
2448
* get_matching_list_bounds
2439
2449
* Determine the offsets of list bounds matching the specified value,
2440
2450
* according to the semantics of the given operator strategy
2451
+ *
2452
+ * scan_default will be set in the returned struct, if the default partition
2453
+ * needs to be scanned, provided one exists at all. scan_null will be set if
2454
+ * the special null-accepting partition needs to be scanned.
2455
+ *
2441
2456
* 'opstrategy' if non-zero must be a btree strategy number.
2442
2457
*
2443
2458
* 'value' contains the value to use for pruning.
@@ -2640,8 +2655,13 @@ get_matching_list_bounds(PartitionPruneContext *context,
2640
2655
* Each datum whose offset is in result is to be treated as the upper bound of
2641
2656
* the partition that will contain the desired values.
2642
2657
*
2643
- * If default partition needs to be scanned for given values, set scan_default
2644
- * in result if present.
2658
+ * scan_default is set in the returned struct if a default partition exists
2659
+ * and we're absolutely certain that it needs to be scanned. We do *not* set
2660
+ * it just because values match portions of the key space uncovered by
2661
+ * partitions other than default (space which we normally assume to belong to
2662
+ * the default partition): the final set of bounds obtained after combining
2663
+ * multiple pruning steps might exclude it, so we infer its inclusion
2664
+ * elsewhere.
2645
2665
*
2646
2666
* 'opstrategy' if non-zero must be a btree strategy number.
2647
2667
*
@@ -2667,8 +2687,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
2667
2687
int * partindices = boundinfo -> indexes ;
2668
2688
int off ,
2669
2689
minoff ,
2670
- maxoff ,
2671
- i ;
2690
+ maxoff ;
2672
2691
bool is_equal ;
2673
2692
bool inclusive = false;
2674
2693
@@ -2698,13 +2717,15 @@ get_matching_range_bounds(PartitionPruneContext *context,
2698
2717
*/
2699
2718
if (nvalues == 0 )
2700
2719
{
2720
+ /* ignore key space not covered by any partitions */
2701
2721
if (partindices [minoff ] < 0 )
2702
2722
minoff ++ ;
2703
2723
if (partindices [maxoff ] < 0 )
2704
2724
maxoff -- ;
2705
2725
2706
2726
result -> scan_default = partition_bound_has_default (boundinfo );
2707
- Assert (minoff >= 0 && maxoff >= 0 );
2727
+ Assert (partindices [minoff ] >= 0 &&
2728
+ partindices [maxoff ] >= 0 );
2708
2729
result -> bound_offsets = bms_add_range (NULL , minoff , maxoff );
2709
2730
2710
2731
return result ;
@@ -2732,11 +2753,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
2732
2753
if (nvalues == partnatts )
2733
2754
{
2734
2755
/* There can only be zero or one matching partition. */
2735
- if (partindices [off + 1 ] >= 0 )
2736
- result -> bound_offsets = bms_make_singleton (off + 1 );
2737
- else
2738
- result -> scan_default =
2739
- partition_bound_has_default (boundinfo );
2756
+ result -> bound_offsets = bms_make_singleton (off + 1 );
2740
2757
return result ;
2741
2758
}
2742
2759
else
@@ -2824,57 +2841,21 @@ get_matching_range_bounds(PartitionPruneContext *context,
2824
2841
maxoff = off + 1 ;
2825
2842
}
2826
2843
2827
- /*
2828
- * Skip if minoff/maxoff are actually the upper bound of a
2829
- * un-assigned portion of values.
2830
- */
2831
- if (partindices [minoff ] < 0 && minoff < boundinfo -> ndatums )
2832
- minoff ++ ;
2833
- if (partindices [maxoff ] < 0 && maxoff >= 1 )
2834
- maxoff -- ;
2835
-
2836
- /*
2837
- * There may exist a range of values unassigned to any
2838
- * non-default partition between the datums at minoff and
2839
- * maxoff. Add the default partition in that case.
2840
- */
2841
- if (partition_bound_has_default (boundinfo ))
2842
- {
2843
- for (i = minoff ; i <= maxoff ; i ++ )
2844
- {
2845
- if (partindices [i ] < 0 )
2846
- {
2847
- result -> scan_default = true;
2848
- break ;
2849
- }
2850
- }
2851
- }
2852
-
2853
2844
Assert (minoff >= 0 && maxoff >= 0 );
2854
2845
result -> bound_offsets = bms_add_range (NULL , minoff , maxoff );
2855
2846
}
2856
- else if ( off >= 0 ) /* !is_equal */
2847
+ else
2857
2848
{
2858
2849
/*
2859
2850
* The lookup value falls in the range between some bounds in
2860
2851
* boundinfo. 'off' would be the offset of the greatest bound
2861
2852
* that is <= lookup value, so add off + 1 to the result
2862
2853
* instead as the offset of the upper bound of the only
2863
- * partition that may contain the lookup value.
2864
- */
2865
- if (partindices [off + 1 ] >= 0 )
2866
- result -> bound_offsets = bms_make_singleton (off + 1 );
2867
- else
2868
- result -> scan_default =
2869
- partition_bound_has_default (boundinfo );
2870
- }
2871
- else
2872
- {
2873
- /*
2874
- * off < 0: the lookup value is smaller than all bounds, so
2875
- * only the default partition qualifies, if there is one.
2854
+ * partition that may contain the lookup value. If 'off' is
2855
+ * -1 indicating that all bounds are greater, then we simply
2856
+ * end up adding the first bound's offset, that is, 0.
2876
2857
*/
2877
- result -> scan_default = partition_bound_has_default ( boundinfo );
2858
+ result -> bound_offsets = bms_make_singleton ( off + 1 );
2878
2859
}
2879
2860
2880
2861
return result ;
@@ -2945,16 +2926,18 @@ get_matching_range_bounds(PartitionPruneContext *context,
2945
2926
2946
2927
minoff = inclusive ? off : off + 1 ;
2947
2928
}
2948
-
2949
- /*
2950
- * lookup value falls in the range between some bounds in
2951
- * boundinfo. off would be the offset of the greatest bound
2952
- * that is <= lookup value, so add off + 1 to the result
2953
- * instead as the offset of the upper bound of the smallest
2954
- * partition that may contain the lookup value.
2955
- */
2956
2929
else
2930
+ {
2931
+
2932
+ /*
2933
+ * lookup value falls in the range between some bounds in
2934
+ * boundinfo. off would be the offset of the greatest
2935
+ * bound that is <= lookup value, so add off + 1 to the
2936
+ * result instead as the offset of the upper bound of the
2937
+ * smallest partition that may contain the lookup value.
2938
+ */
2957
2939
minoff = off + 1 ;
2940
+ }
2958
2941
}
2959
2942
break ;
2960
2943
@@ -2972,16 +2955,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
2972
2955
boundinfo ,
2973
2956
nvalues , values ,
2974
2957
& is_equal );
2975
- if (off < 0 )
2976
- {
2977
- /*
2978
- * All bounds are greater than the key, so we could only
2979
- * expect to find the lookup key in the default partition.
2980
- */
2981
- result -> scan_default = partition_bound_has_default (boundinfo );
2982
- return result ;
2983
- }
2984
- else
2958
+ if (off >= 0 )
2985
2959
{
2986
2960
/*
2987
2961
* See the comment above.
@@ -3029,65 +3003,58 @@ get_matching_range_bounds(PartitionPruneContext *context,
3029
3003
else
3030
3004
maxoff = off ;
3031
3005
}
3006
+ else
3007
+ {
3008
+ /*
3009
+ * 'off' is -1 indicating that all bounds are greater, so just
3010
+ * set the first bound's offset as maxoff.
3011
+ */
3012
+ maxoff = off + 1 ;
3013
+ }
3032
3014
break ;
3033
3015
3034
3016
default :
3035
3017
elog (ERROR , "invalid strategy number %d" , opstrategy );
3036
3018
break ;
3037
3019
}
3038
3020
3021
+ Assert (minoff >= 0 && minoff <= boundinfo -> ndatums );
3022
+ Assert (maxoff >= 0 && maxoff <= boundinfo -> ndatums );
3023
+
3039
3024
/*
3040
- * Skip a gap and when doing so, check if the bound contains a finite
3041
- * value to decide if we need to add the default partition. If it's an
3042
- * infinite bound, we need not add the default partition, as having an
3043
- * infinite bound means the partition in question catches any values that
3044
- * would otherwise be in the default partition.
3025
+ * If the smallest partition to return has MINVALUE (negative infinity) as
3026
+ * its lower bound, increment it to point to the next finite bound
3027
+ * (supposedly its upper bound), so that we don't advertently end up
3028
+ * scanning the default partition.
3045
3029
*/
3046
- if (partindices [minoff ] < 0 )
3030
+ if (minoff < boundinfo -> ndatums && partindices [minoff ] < 0 )
3047
3031
{
3048
3032
int lastkey = nvalues - 1 ;
3049
3033
3050
- if (minoff >= 0 &&
3051
- minoff < boundinfo -> ndatums &&
3052
- boundinfo -> kind [minoff ][lastkey ] ==
3053
- PARTITION_RANGE_DATUM_VALUE )
3054
- result -> scan_default = partition_bound_has_default (boundinfo );
3055
-
3056
- minoff ++ ;
3034
+ if (boundinfo -> kind [minoff ][lastkey ] ==
3035
+ PARTITION_RANGE_DATUM_MINVALUE )
3036
+ {
3037
+ minoff ++ ;
3038
+ Assert (boundinfo -> indexes [minoff ] >= 0 );
3039
+ }
3057
3040
}
3058
3041
3059
3042
/*
3060
- * Skip a gap. See the above comment about how we decide whether or not
3061
- * to scan the default partition based whether the datum that will become
3062
- * the maximum datum is finite or not.
3043
+ * If the previous greatest partition has MAXVALUE (positive infinity) as
3044
+ * its upper bound (something only possible to do with multi-column range
3045
+ * partitioning), we scan switch to it as the greatest partition to
3046
+ * return. Again, so that we don't advertently end up scanning the
3047
+ * default partition.
3063
3048
*/
3064
3049
if (maxoff >= 1 && partindices [maxoff ] < 0 )
3065
3050
{
3066
3051
int lastkey = nvalues - 1 ;
3067
3052
3068
- if (maxoff >= 0 &&
3069
- maxoff <= boundinfo -> ndatums &&
3070
- boundinfo -> kind [maxoff - 1 ][lastkey ] ==
3071
- PARTITION_RANGE_DATUM_VALUE )
3072
- result -> scan_default = partition_bound_has_default (boundinfo );
3073
-
3074
- maxoff -- ;
3075
- }
3076
-
3077
- if (partition_bound_has_default (boundinfo ))
3078
- {
3079
- /*
3080
- * There may exist a range of values unassigned to any non-default
3081
- * partition between the datums at minoff and maxoff. Add the default
3082
- * partition in that case.
3083
- */
3084
- for (i = minoff ; i <= maxoff ; i ++ )
3053
+ if (boundinfo -> kind [maxoff - 1 ][lastkey ] ==
3054
+ PARTITION_RANGE_DATUM_MAXVALUE )
3085
3055
{
3086
- if (partindices [i ] < 0 )
3087
- {
3088
- result -> scan_default = true;
3089
- break ;
3090
- }
3056
+ maxoff -- ;
3057
+ Assert (boundinfo -> indexes [maxoff ] >= 0 );
3091
3058
}
3092
3059
}
3093
3060
@@ -3332,14 +3299,24 @@ perform_pruning_combine_step(PartitionPruneContext *context,
3332
3299
3333
3300
/*
3334
3301
* A combine step without any source steps is an indication to not perform
3335
- * any partition pruning, we just return all partitions .
3302
+ * any partition pruning. Return all datum indexes in that case .
3336
3303
*/
3337
3304
result = (PruneStepResult * ) palloc0 (sizeof (PruneStepResult ));
3338
3305
if (list_length (cstep -> source_stepids ) == 0 )
3339
3306
{
3340
3307
PartitionBoundInfo boundinfo = context -> boundinfo ;
3308
+ int rangemax ;
3309
+
3310
+ /*
3311
+ * Add all valid offsets into the boundinfo->indexes array. For range
3312
+ * partitioning, boundinfo->indexes contains (boundinfo->ndatums + 1)
3313
+ * valid entries; otherwise there are boundinfo->ndatums.
3314
+ */
3315
+ rangemax = context -> strategy == PARTITION_STRATEGY_RANGE ?
3316
+ boundinfo -> ndatums : boundinfo -> ndatums - 1 ;
3341
3317
3342
- result -> bound_offsets = bms_add_range (NULL , 0 , boundinfo -> ndatums - 1 );
3318
+ result -> bound_offsets =
3319
+ bms_add_range (result -> bound_offsets , 0 , rangemax );
3343
3320
result -> scan_default = partition_bound_has_default (boundinfo );
3344
3321
result -> scan_null = partition_bound_accepts_nulls (boundinfo );
3345
3322
return result ;
0 commit comments