Row Filter Syntax

Row filters drive predicate pushdown during scans, partition pruning, and row-level deletes. The DSL lives in the root iceberg package - all you need is the import:

import "github.com/apache/iceberg-go"

A column is referenced with iceberg.Reference("column_name"). Predicate constructors return a BooleanExpression (or an UnboundPredicate, which satisfies BooleanExpression) that can be combined with the boolean combinators in the Expression DSL and passed to APIs like table.WithRowFilter(...).

Equality

iceberg.EqualTo(iceberg.Reference("status"), "active")
iceberg.NotEqualTo(iceberg.Reference("retries"), int32(0))

EqualTo[T] and NotEqualTo[T] are generic over LiteralType (bool, int32, int64, float32, float64, string, []byte, plus a few iceberg-specific types). The value's type must be in that set - bare int literals are not, so use int32(0) / int64(0) explicitly. They wrap LiteralPredicate(OpEQ, ...) and LiteralPredicate(OpNEQ, ...) (predicates.go:83-91).

Comparison

iceberg.LessThan(iceberg.Reference("amount"), 100.0)
iceberg.LessThanEqual(iceberg.Reference("amount"), 100.0)
iceberg.GreaterThan(iceberg.Reference("created_at"), int64(1700000000))
iceberg.GreaterThanEqual(iceberg.Reference("score"), int32(50))

Operators: OpLT, OpLTEQ, OpGT, OpGTEQ (exprs.go:47-50). Constructors at predicates.go:98-124.

Set membership

iceberg.IsIn(iceberg.Reference("region"), "us-east", "us-west", "eu-west")
iceberg.NotIn(iceberg.Reference("status"), "deleted", "archived")

IsIn and NotIn are variadic. They return a BooleanExpression (not UnboundPredicate) because the result can simplify automatically:

  • Zero values - reduces to AlwaysFalse{} (for IsIn) or AlwaysTrue{} (for NotIn).
  • One value - reduces to EqualTo / NotEqualTo.

See predicates.go:55-78.

Null checks

iceberg.IsNull(iceberg.Reference("deleted_at"))
iceberg.NotNull(iceberg.Reference("user_id"))

These wrap UnaryPredicate(OpIsNull, ...) and UnaryPredicate(OpNotNull, ...). Both panic if the term is nil (predicates.go:23-32).

NaN checks (float / double columns only)

iceberg.IsNaN(iceberg.Reference("ratio"))
iceberg.NotNaN(iceberg.Reference("ratio"))

Operators OpIsNan and OpNotNan. Use these instead of EqualTo(..., math.NaN()) - NaN is never equal to itself.

String prefix

iceberg.StartsWith(iceberg.Reference("path"), "/var/log/")
iceberg.NotStartsWith(iceberg.Reference("name"), "tmp_")

Operators OpStartsWith and OpNotStartsWith (exprs.go:53-54). The value must be a string.

Constants

iceberg.AlwaysTrue{}
iceberg.AlwaysFalse{}

These satisfy BooleanExpression and short-circuit during expression simplification. Useful as a base case when filters are built dynamically:

filter := iceberg.BooleanExpression(iceberg.AlwaysTrue{})
for _, clause := range userClauses {
    filter = iceberg.NewAnd(filter, clause)
}

Operator reference

The full operator set is the Operation enum at exprs.go:34-62:

OperatorConstantConvenience builder
<OpLTLessThan
<=OpLTEQLessThanEqual
>OpGTGreaterThan
>=OpGTEQGreaterThanEqual
==OpEQEqualTo
!=OpNEQNotEqualTo
IS NULLOpIsNullIsNull
IS NOT NULLOpNotNullNotNull
IS NaNOpIsNanIsNaN
IS NOT NaNOpNotNanNotNaN
INOpInIsIn
NOT INOpNotInNotIn
STARTS WITHOpStartsWithStartsWith
NOT STARTS WITHOpNotStartsWithNotStartsWith
AND / OR / NOTOpAnd / OpOr / OpNotNewAnd / NewOr / NewNot (see Expression DSL)

Putting it together

A typical filter passed to a scan:

filter := iceberg.NewAnd(
    iceberg.GreaterThanEqual(iceberg.Reference("event_time"), int64(1700000000)),
    iceberg.IsIn(iceberg.Reference("region"), "us-east", "us-west"),
    iceberg.NotNull(iceberg.Reference("user_id")),
)

scan := tbl.Scan(table.WithRowFilter(filter))

For boolean combination, term details, and the lower-level escape hatches (UnaryPredicate, LiteralPredicate, SetPredicate), see Expression DSL.