MCPcopy Create free account
hub / github.com/apache/datafusion / aggregate_multi_conjunct

Method aggregate_multi_conjunct

datafusion/physical-expr/src/utils/guarantee.rs:313–371  ·  view source on GitHub ↗

ScalarValue has interior mutability but is intentionally used as hash key

(
        mut self,
        col: &'a crate::expressions::Column,
        guarantee: Guarantee,
        new_values: impl IntoIterator<Item = &'a ScalarValue>,
    )

Source from the content-addressed store, hash-verified

311 /// * `AND (a NOT IN (1,2,3))`: a is not in (1, 2, or 3)
312 #[allow(clippy::allow_attributes, clippy::mutable_key_type)] // ScalarValue has interior mutability but is intentionally used as hash key
313 fn aggregate_multi_conjunct(
314 mut self,
315 col: &'a crate::expressions::Column,
316 guarantee: Guarantee,
317 new_values: impl IntoIterator<Item = &'a ScalarValue>,
318 ) -> Self {
319 let key = (col, guarantee);
320 if let Some(index) = self.map.get(&key) {
321 // already have a guarantee for this column
322 let entry = &mut self.guarantees[*index];
323
324 let Some(existing) = entry else {
325 // determined the previous guarantee for this column has been
326 // invalidated, nothing to do
327 return self;
328 };
329
330 // Combine conjuncts if we have `a != foo AND a != bar`. `a = foo
331 // AND a = bar` doesn't make logical sense so we don't optimize this
332 // case
333 match existing.guarantee {
334 // knew that the column could not be a set of values
335 //
336 // For example, if we previously had `a != 5` and now we see
337 // another `AND a != 6` we know that a must not be either 5 or 6
338 // for the expression to be true
339 Guarantee::NotIn => {
340 let new_values: HashSet<_> = new_values.into_iter().collect();
341 existing.literals.extend(new_values.into_iter().cloned());
342 }
343 Guarantee::In => {
344 let intersection = new_values
345 .into_iter()
346 .filter(|new_value| existing.literals.contains(*new_value))
347 .collect::<Vec<_>>();
348 // for an In guarantee, if the intersection is not empty, we can extend the guarantee
349 // e.g. `a IN (1,2,3) AND a IN (2,3,4)` is `a IN (2,3)`
350 // otherwise, we invalidate the guarantee
351 // e.g. `a IN (1,2,3) AND a IN (4,5,6)` is `a IN ()`, which is invalid
352 if !intersection.is_empty() {
353 existing.literals = intersection.into_iter().cloned().collect();
354 } else {
355 // at least one was not, so invalidate the guarantee
356 *entry = None;
357 }
358 }
359 }
360 } else {
361 // This is a new guarantee
362 let new_values: HashSet<_> = new_values.into_iter().collect();
363
364 let guarantee = LiteralGuarantee::new(col.name(), guarantee, new_values);
365 // add it to the list of guarantees
366 self.guarantees.push(Some(guarantee));
367 self.map.insert(key, self.guarantees.len() - 1);
368 }
369
370 self

Callers 2

analyzeMethod · 0.80
aggregate_conjunctMethod · 0.80

Calls 13

newFunction · 0.85
collectMethod · 0.80
getMethod · 0.45
into_iterMethod · 0.45
extendMethod · 0.45
clonedMethod · 0.45
filterMethod · 0.45
containsMethod · 0.45
is_emptyMethod · 0.45
nameMethod · 0.45
pushMethod · 0.45
insertMethod · 0.45

Tested by

no test coverage detected