@@ -743,9 +743,22 @@ double Histogram_json_hb::range_selectivity(Field *field, key_range *min_endp,
743
743
idx--;
744
744
}
745
745
double left_fract= get_left_fract (idx);
746
- double sel= position_in_interval (field, max_key, max_key_len,
747
- buckets[idx].start_value ,
748
- get_end_value (idx));
746
+
747
+ double sel;
748
+ /* Special handling for singleton buckets */
749
+ if (buckets[idx].ndv == 1 && equal)
750
+ {
751
+ if (inclusive_endp)
752
+ sel= 1.0 ;
753
+ else
754
+ sel= 0.0 ;
755
+ }
756
+ else
757
+ {
758
+ sel= position_in_interval (field, max_key, max_key_len,
759
+ buckets[idx].start_value ,
760
+ get_end_value (idx));
761
+ }
749
762
max= left_fract + sel * (buckets[idx].cum_fract - left_fract);
750
763
}
751
764
else
@@ -763,26 +776,18 @@ void Histogram_json_hb::serialize(Field *field)
763
776
764
777
765
778
/*
766
- Find the rightmost histogram bucket such that "lookup_val $GT start_value".
767
-
768
- $GT is either '>' or '>=' depending on equal_is_less parameter.
769
-
770
- @param equal_is_less Controls what to do if a histogram bound is equal to the
771
- lookup_val.
772
-
773
- @detail
774
- Possible cases:
775
- 1. The regular case: the value falls into some bucket.
779
+ @brief
780
+ Find the leftmost histogram bucket such that "lookup_val >= start_value".
776
781
777
- 2. The value is less than the minimum of the first bucket
778
- 3. The value is greater than the maximum of the last bucket
779
- In these cases we "clip" to the first/last bucket.
782
+ @param field Field object (used to do value comparisons)
783
+ @param lookup_val The lookup value in KeyTupleFormat.
784
+ @param equal OUT TRUE<=> the found bucket has left_bound=lookup_val
780
785
781
- 4. The value hits the bucket boundary. Then, we need to know whether the
782
- point of interest is to the left the constant, or to the right of it.
786
+ @return
787
+ The bucket index
783
788
*/
784
789
785
- int Histogram_json_hb::find_bucket (Field *field, const uchar *lookup_val,
790
+ int Histogram_json_hb::find_bucket (const Field *field, const uchar *lookup_val,
786
791
bool *equal)
787
792
{
788
793
int res;
@@ -797,7 +802,8 @@ int Histogram_json_hb::find_bucket(Field *field, const uchar *lookup_val,
797
802
if (!res)
798
803
{
799
804
*equal= true ;
800
- return middle;
805
+ low= middle;
806
+ goto end;
801
807
}
802
808
else if (res < 0 )
803
809
low= middle;
@@ -806,25 +812,25 @@ int Histogram_json_hb::find_bucket(Field *field, const uchar *lookup_val,
806
812
}
807
813
808
814
/*
809
- If low and high were assigned a value in the above loop, then they are not
810
- equal to the lookup value :
815
+ If low and high were assigned a value in the above loop and we got here,
816
+ then the following holds :
811
817
812
- bucket[low] < lookup_val < bucket[high]
818
+ bucket[low].start_value < lookup_val < bucket[high].start_value
813
819
814
- But there are two special cases: low=0 and high=last_bucket. Handle them
815
- below.
820
+ Besides that, there are two special cases: low=0 and high=last_bucket.
821
+ Handle them below.
816
822
*/
817
823
if (low == 0 )
818
824
{
819
825
res= field->key_cmp ((uchar*)buckets[0 ].start_value .data (), lookup_val);
820
826
if (!res)
821
827
*equal= true ;
822
- else if (res < 0 )
828
+ else if (res < 0 ) // buckets[0] < lookup_val
823
829
{
824
830
res= field->key_cmp ((uchar*)buckets[high].start_value .data (), lookup_val);
825
831
if (!res)
826
832
*equal= true ;
827
- if (res > = 0 )
833
+ if (res < = 0 ) // buckets[high] <= lookup_val
828
834
low= high;
829
835
}
830
836
}
@@ -833,9 +839,19 @@ int Histogram_json_hb::find_bucket(Field *field, const uchar *lookup_val,
833
839
res= field->key_cmp ((uchar*)buckets[high].start_value .data (), lookup_val);
834
840
if (!res)
835
841
*equal= true ;
836
- if (res > = 0 )
842
+ if (res < = 0 )
837
843
low= high;
838
844
}
839
845
846
+ end:
847
+ // Verification: *equal==TRUE <=> lookup value is equal to the found bucket.
848
+ DBUG_ASSERT (*equal == !(field->key_cmp ((uchar*)buckets[low].start_value .data (),
849
+ lookup_val)));
850
+ // buckets[low] <= lookup_val, with one exception of the first bucket.
851
+ DBUG_ASSERT (low == 0 ||
852
+ field->key_cmp ((uchar*)buckets[low].start_value .data (), lookup_val)<= 0 );
853
+ // buckets[low+1] > lookup_val, with one exception of the last bucket
854
+ DBUG_ASSERT (low == (int )buckets.size ()-1 ||
855
+ field->key_cmp ((uchar*)buckets[low+1 ].start_value .data (), lookup_val)> 0 );
840
856
return low;
841
857
}
0 commit comments