in table/evaluators.go [397:465]
func (m *manifestEvalVisitor) VisitStartsWith(term iceberg.BoundTerm, lit iceberg.Literal) bool {
pos := term.Ref().Pos()
field := m.partitionFields[pos]
var prefix string
if val, ok := lit.(iceberg.TypedLiteral[string]); ok {
prefix = val.Value()
} else {
prefix = string(lit.(iceberg.TypedLiteral[[]byte]).Value())
}
lenPrefix := len(prefix)
if field.LowerBound == nil {
return rowsCannotMatch
}
lower, err := iceberg.LiteralFromBytes(term.Ref().Type(), *field.LowerBound)
if err != nil {
panic(err)
}
// truncate lower bound so that it's length is not greater than the length of prefix
var v string
switch l := lower.(type) {
case iceberg.TypedLiteral[string]:
v = l.Value()
if len(v) > lenPrefix {
v = v[:lenPrefix]
}
case iceberg.TypedLiteral[[]byte]:
v = string(l.Value())
if len(v) > lenPrefix {
v = v[:lenPrefix]
}
}
if v > prefix {
return rowsCannotMatch
}
if field.UpperBound == nil {
return rowsCannotMatch
}
upper, err := iceberg.LiteralFromBytes(term.Ref().Type(), *field.UpperBound)
if err != nil {
panic(err)
}
switch u := upper.(type) {
case iceberg.TypedLiteral[string]:
v = u.Value()
if len(v) > lenPrefix {
v = v[:lenPrefix]
}
case iceberg.TypedLiteral[[]byte]:
v = string(u.Value())
if len(v) > lenPrefix {
v = v[:lenPrefix]
}
}
if v < prefix {
return rowsCannotMatch
}
return rowsMightMatch
}