Predicate pushdown This method looks for opportunities to push predicates toward sources of data. Primarily, this is the `Filter` expression, and moving its predicates through the operators it contains. In addition, the method accumulates the intersection of predicates applied to each `Get` expression, so that the predicate can then be pushed through to a `Let` binding, or to the external source
(
&self,
relation: &mut MirRelationExpr,
get_predicates: &mut BTreeMap<Id, BTreeSet<MirScalarExpr>>,
)
| 157 | /// then be pushed through to a `Let` binding, or to the external |
| 158 | /// source of the data if the `Get` binds to another view. |
| 159 | pub fn action( |
| 160 | &self, |
| 161 | relation: &mut MirRelationExpr, |
| 162 | get_predicates: &mut BTreeMap<Id, BTreeSet<MirScalarExpr>>, |
| 163 | ) -> Result<(), TransformError> { |
| 164 | self.checked_recur(|_| { |
| 165 | // In the case of Filter or Get we have specific work to do; |
| 166 | // otherwise we should recursively descend. |
| 167 | match relation { |
| 168 | MirRelationExpr::Filter { input, predicates } => { |
| 169 | // Reduce the predicates to determine as best as possible |
| 170 | // whether they are literal errors before working with them. |
| 171 | let input_type = input.typ(); |
| 172 | for predicate in predicates.iter_mut() { |
| 173 | predicate.reduce(&input_type.column_types); |
| 174 | } |
| 175 | |
| 176 | // It can be helpful to know if there are any non-literal errors, |
| 177 | // as this is justification for not pushing down literal errors. |
| 178 | let all_errors = predicates.iter().all(|p| p.is_literal_err()); |
| 179 | // Depending on the type of `input` we have different |
| 180 | // logic to apply to consider pushing `predicates` down. |
| 181 | match &mut **input { |
| 182 | MirRelationExpr::Let { body, .. } |
| 183 | | MirRelationExpr::LetRec { body, .. } => { |
| 184 | // Push all predicates to the body. |
| 185 | **body = body |
| 186 | .take_dangerous() |
| 187 | .filter(std::mem::replace(predicates, Vec::new())); |
| 188 | |
| 189 | self.action(input, get_predicates)?; |
| 190 | } |
| 191 | MirRelationExpr::Get { id, .. } => { |
| 192 | // We can report the predicates upward in `get_predicates`, |
| 193 | // but we are not yet able to delete them from the |
| 194 | // `Filter`. |
| 195 | get_predicates |
| 196 | .entry(*id) |
| 197 | .or_insert_with(|| predicates.iter().cloned().collect()) |
| 198 | .retain(|p| predicates.contains(p)); |
| 199 | } |
| 200 | MirRelationExpr::Join { |
| 201 | inputs, |
| 202 | equivalences, |
| 203 | .. |
| 204 | } => { |
| 205 | // We want to scan `predicates` for any that can |
| 206 | // 1) become join variable constraints |
| 207 | // 2) apply to individual elements of `inputs`. |
| 208 | // Figuring out the set of predicates that belong to |
| 209 | // the latter group requires 1) knowing which predicates |
| 210 | // are in the former group and 2) that the variable |
| 211 | // constraints be in canonical form. |
| 212 | // Thus, there is a first scan across `predicates` to |
| 213 | // populate the join variable constraints |
| 214 | // and a second scan across the remaining predicates |
| 215 | // to see which ones can become individual elements of |
| 216 | // `inputs`. |
no test coverage detected