in crates/iceberg/src/expr/visitors/manifest_evaluator.rs [287:344]
fn not_starts_with(
&mut self,
reference: &BoundReference,
datum: &Datum,
_predicate: &BoundPredicate,
) -> crate::Result<bool> {
let field = self.field_summary_for_reference(reference);
if field.contains_null || field.lower_bound.is_none() || field.upper_bound.is_none() {
return ROWS_MIGHT_MATCH;
}
let prefix = ManifestFilterVisitor::datum_as_str(
datum,
"Cannot perform not_starts_with on non-string value",
)?;
let prefix_len = prefix.len();
// not_starts_with will match unless all values must start with the prefix. This happens when
// the lower and upper bounds both start with the prefix.
if let Some(lower_bound) = &field.lower_bound {
let lower_bound_str = ManifestFilterVisitor::datum_as_str(
lower_bound,
"Cannot perform not_starts_with on non-string lower bound",
)?;
// if lower is shorter than the prefix then lower doesn't start with the prefix
if prefix_len > lower_bound_str.len() {
return ROWS_MIGHT_MATCH;
}
if prefix
.as_bytes()
.eq(&lower_bound_str.as_bytes()[..prefix_len])
{
if let Some(upper_bound) = &field.upper_bound {
let upper_bound_str = ManifestFilterVisitor::datum_as_str(
upper_bound,
"Cannot perform not_starts_with on non-string upper bound",
)?;
// if upper is shorter than the prefix then upper can't start with the prefix
if prefix_len > upper_bound_str.len() {
return ROWS_MIGHT_MATCH;
}
if prefix
.as_bytes()
.eq(&upper_bound_str.as_bytes()[..prefix_len])
{
return ROWS_CANNOT_MATCH;
}
}
}
}
ROWS_MIGHT_MATCH
}