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