in crates/iceberg/src/expr/visitors/row_group_metrics_evaluator.rs [335:391]
fn starts_with(
&mut self,
reference: &BoundReference,
datum: &Datum,
_predicate: &BoundPredicate,
) -> Result<bool> {
let field_id = reference.field().id;
if self.contains_nulls_only(field_id) {
return ROW_GROUP_CANT_MATCH;
}
let PrimitiveLiteral::String(datum) = datum.literal() else {
return Err(Error::new(
ErrorKind::Unexpected,
"Cannot use StartsWith operator on non-string values",
));
};
if let Some(lower_bound) = self.min_value(field_id)? {
let PrimitiveLiteral::String(lower_bound) = lower_bound.literal() else {
return Err(Error::new(
ErrorKind::Unexpected,
"Cannot use StartsWith operator on non-string lower_bound value",
));
};
let prefix_length = lower_bound.chars().count().min(datum.chars().count());
// truncate lower bound so that its length
// is not greater than the length of prefix
let truncated_lower_bound = lower_bound.chars().take(prefix_length).collect::<String>();
if datum < &truncated_lower_bound {
return ROW_GROUP_CANT_MATCH;
}
}
if let Some(upper_bound) = self.max_value(field_id)? {
let PrimitiveLiteral::String(upper_bound) = upper_bound.literal() else {
return Err(Error::new(
ErrorKind::Unexpected,
"Cannot use StartsWith operator on non-string upper_bound value",
));
};
let prefix_length = upper_bound.chars().count().min(datum.chars().count());
// truncate upper bound so that its length
// is not greater than the length of prefix
let truncated_upper_bound = upper_bound.chars().take(prefix_length).collect::<String>();
if datum > &truncated_upper_bound {
return ROW_GROUP_CANT_MATCH;
}
}
ROW_GROUP_MIGHT_MATCH
}