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

Function build_not_like_match

datafusion/pruning/src/pruning_predicate.rs:1886–1937  ·  view source on GitHub ↗

For predicate `col NOT LIKE 'const_prefix%'`, we rewrite it as `(col_min NOT LIKE 'const_prefix%' OR col_max NOT LIKE 'const_prefix%')`. The intuition is that if both `col_min` and `col_max` begin with `const_prefix` that means all** data in this row group begins with `const_prefix` as well (and therefore the predicate looking for rows that don't begin with `const_prefix` can never be true)

(
    expr_builder: &mut PruningExpressionBuilder<'_>,
)

Source from the content-addressed store, hash-verified

1884// **all** data in this row group begins with `const_prefix` as well (and therefore the predicate
1885// looking for rows that don't begin with `const_prefix` can never be true)
1886fn build_not_like_match(
1887 expr_builder: &mut PruningExpressionBuilder<'_>,
1888) -> Result<Arc<dyn PhysicalExpr>> {
1889 // col NOT LIKE 'const_prefix%' -> !(col_min LIKE 'const_prefix%' && col_max LIKE 'const_prefix%') -> (col_min NOT LIKE 'const_prefix%' || col_max NOT LIKE 'const_prefix%')
1890
1891 let min_column_expr = expr_builder.min_column_expr()?;
1892 let max_column_expr = expr_builder.max_column_expr()?;
1893
1894 let scalar_expr = expr_builder.scalar_expr();
1895
1896 let pattern = extract_string_literal(scalar_expr).ok_or_else(|| {
1897 plan_datafusion_err!("cannot extract literal from NOT LIKE expression")
1898 })?;
1899
1900 let (const_prefix, remaining) = split_constant_prefix(pattern);
1901 if const_prefix.is_empty() || remaining != "%" {
1902 // we can not handle `%` at the beginning or in the middle of the pattern
1903 // Example: For pattern "foo%bar", the row group might include values like
1904 // ["foobar", "food", "foodbar"], making it unsafe to prune.
1905 // Even if the min/max values in the group (e.g., "foobar" and "foodbar")
1906 // match the pattern, intermediate values like "food" may not
1907 // match the full pattern "foo%bar", making pruning unsafe.
1908 // (truncate foo%bar to foo% have same problem)
1909
1910 // we can not handle pattern containing `_`
1911 // Example: For pattern "foo_", row groups might contain ["fooa", "fooaa", "foob"],
1912 // which means not every row is guaranteed to match the pattern.
1913 return Err(plan_datafusion_err!(
1914 "NOT LIKE expressions only support constant_prefix+wildcard`%`"
1915 ));
1916 }
1917
1918 let min_col_not_like_epxr = Arc::new(phys_expr::LikeExpr::new(
1919 true,
1920 false,
1921 Arc::clone(&min_column_expr),
1922 Arc::clone(scalar_expr),
1923 ));
1924
1925 let max_col_not_like_expr = Arc::new(phys_expr::LikeExpr::new(
1926 true,
1927 false,
1928 Arc::clone(&max_column_expr),
1929 Arc::clone(scalar_expr),
1930 ));
1931
1932 Ok(Arc::new(phys_expr::BinaryExpr::new(
1933 min_col_not_like_epxr,
1934 Operator::Or,
1935 max_col_not_like_expr,
1936 )))
1937}
1938
1939/// Returns unescaped constant prefix of a LIKE pattern (possibly empty) and the remaining pattern (possibly empty)
1940fn split_constant_prefix(pattern: &str) -> (String, &str) {

Callers 1

build_statistics_exprFunction · 0.85

Calls 7

extract_string_literalFunction · 0.85
split_constant_prefixFunction · 0.85
newFunction · 0.85
min_column_exprMethod · 0.80
max_column_exprMethod · 0.80
scalar_exprMethod · 0.80
is_emptyMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…