in arrow-string/src/like.rs [454:495]
fn ilike_scalar_op<O: OffsetSizeTrait, F: Fn(bool) -> bool>(
left: &GenericStringArray<O>,
right: &str,
op: F,
) -> Result<BooleanArray, ArrowError> {
// If not ASCII faster to use case insensitive regex than using to_uppercase
if right.is_ascii() && left.is_ascii() {
if !right.contains(is_like_pattern) {
return Ok(BooleanArray::from_unary(left, |item| {
op(item.eq_ignore_ascii_case(right))
}));
} else if right.ends_with('%')
&& !right.ends_with("\\%")
&& !right[..right.len() - 1].contains(is_like_pattern)
{
// fast path, can use starts_with
let start_str = &right[..right.len() - 1];
return Ok(BooleanArray::from_unary(left, |item| {
let end = item.len().min(start_str.len());
let result = item.is_char_boundary(end)
&& start_str.eq_ignore_ascii_case(&item[..end]);
op(result)
}));
} else if right.starts_with('%') && !right[1..].contains(is_like_pattern) {
// fast path, can use ends_with
let ends_str = &right[1..];
return Ok(BooleanArray::from_unary(left, |item| {
let start = item.len().saturating_sub(ends_str.len());
let result = item.is_char_boundary(start)
&& ends_str.eq_ignore_ascii_case(&item[start..]);
op(result)
}));
}
}
let re_pattern = replace_like_wildcards(right)?;
let re = Regex::new(&format!("(?is)^{re_pattern}$")).map_err(|e| {
ArrowError::ComputeError(format!("Unable to build regex from ILIKE pattern: {e}"))
})?;
Ok(BooleanArray::from_unary(left, |item| op(re.is_match(item))))
}