|
14 | 14 |
|
15 | 15 | use std::cmp::Ordering; |
16 | 16 |
|
17 | | -use databend_common_exception::ErrorCode; |
18 | | -use databend_common_exception::Result; |
19 | | - |
| 17 | +use crate::Scalar; |
| 18 | +use crate::stat_distribution::ArgStat; |
20 | 19 | use crate::stat_distribution::Ndv; |
| 20 | +use crate::stat_distribution::StatBinaryArg; |
21 | 21 | use crate::stat_distribution::StatEstimate; |
22 | 22 |
|
23 | 23 | pub trait StatComparisonOp { |
@@ -109,6 +109,75 @@ impl StatComparisonOp for GteOp { |
109 | 109 | const INCLUDE_EQUAL: bool = true; |
110 | 110 | } |
111 | 111 |
|
| 112 | +pub struct ConstantComparison<'s, 'a> { |
| 113 | + pub stat: &'s ArgStat<'a>, |
| 114 | + pub constant: Scalar, |
| 115 | + pub cardinality: f64, |
| 116 | +} |
| 117 | + |
| 118 | +impl<'s, 'a> ConstantComparison<'s, 'a> { |
| 119 | + pub fn from_equality_args(stat: &'s StatBinaryArg<'a>) -> Option<Self> { |
| 120 | + Self::from_right_constant(stat).or_else(|| Self::from_left_constant(stat)) |
| 121 | + } |
| 122 | + |
| 123 | + pub fn from_right_constant(stat: &'s StatBinaryArg<'a>) -> Option<Self> { |
| 124 | + Some(Self { |
| 125 | + stat: &stat.args[0], |
| 126 | + constant: stat.args[1].singleton()?, |
| 127 | + cardinality: stat.cardinality, |
| 128 | + }) |
| 129 | + } |
| 130 | + |
| 131 | + pub fn from_left_constant(stat: &'s StatBinaryArg<'a>) -> Option<Self> { |
| 132 | + Some(Self { |
| 133 | + stat: &stat.args[1], |
| 134 | + constant: stat.args[0].singleton()?, |
| 135 | + cardinality: stat.cardinality, |
| 136 | + }) |
| 137 | + } |
| 138 | + |
| 139 | + pub fn equality_true_count( |
| 140 | + &self, |
| 141 | + not_eq: bool, |
| 142 | + compare: impl Fn(&Scalar, &Scalar) -> Option<Ordering>, |
| 143 | + ) -> Option<StatEstimate> { |
| 144 | + let Some((min, max)) = self.stat.value_minmax() else { |
| 145 | + return Some(StatEstimate::exact(if not_eq { |
| 146 | + self.cardinality |
| 147 | + } else { |
| 148 | + 0.0 |
| 149 | + })); |
| 150 | + }; |
| 151 | + if compare(&self.constant, &min)? == Ordering::Less |
| 152 | + || compare(&self.constant, &max)? == Ordering::Greater |
| 153 | + { |
| 154 | + return Some(StatEstimate::exact(if not_eq { |
| 155 | + self.cardinality |
| 156 | + } else { |
| 157 | + 0.0 |
| 158 | + })); |
| 159 | + } |
| 160 | + |
| 161 | + Some(estimate_ndv_true_count( |
| 162 | + self.stat.ndv, |
| 163 | + not_eq, |
| 164 | + self.cardinality, |
| 165 | + )) |
| 166 | + } |
| 167 | + |
| 168 | + pub fn minmax_range_true_count<Op: StatComparisonOp>( |
| 169 | + &self, |
| 170 | + compare: impl Fn(&Scalar, &Scalar) -> Option<Ordering>, |
| 171 | + ) -> Option<StatEstimate> { |
| 172 | + try { |
| 173 | + let (min, max) = self.stat.value_minmax()?; |
| 174 | + let cmp_min = compare(&self.constant, &min)?; |
| 175 | + let cmp_max = compare(&self.constant, &max)?; |
| 176 | + Op::estimate_minmax_range_true_count(self.stat.ndv, self.cardinality, cmp_min, cmp_max)? |
| 177 | + } |
| 178 | + } |
| 179 | +} |
| 180 | + |
112 | 181 | pub fn estimate_ndv_true_count(ndv: Ndv, not_eq: bool, cardinality: f64) -> StatEstimate { |
113 | 182 | let value = ndv.value(); |
114 | 183 | let selectivity = if value == 0.0 { |
|
0 commit comments