Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .palantir/revapi.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
versionOverrides:
org.apache.iceberg:iceberg-api:apache-iceberg-0.14.0: "0.14.0"
acceptedBreaks:
apache-iceberg-0.14.0:
org.apache.iceberg:iceberg-api:
- code: "java.method.addedToInterface"
new: "method java.lang.String org.apache.iceberg.expressions.Reference<T>::name()"
justification: "All subclasses implement name"
release-base-0.13.0:
org.apache.iceberg:iceberg-api:
- code: "java.class.defaultSerializationChanged"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@
public class BoundReference<T> implements BoundTerm<T>, Reference<T> {
private final Types.NestedField field;
private final Accessor<StructLike> accessor;
private final String name;

BoundReference(Types.NestedField field, Accessor<StructLike> accessor) {
BoundReference(Types.NestedField field, Accessor<StructLike> accessor, String name) {
this.field = field;
this.accessor = accessor;
this.name = name;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracking the field name was needed to handle bound expressions. This is also a good thing to track for other purposes (e.g., easier to read log messages with bound expressions).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be good to add a comment to distinguish this name from the field name.

}

@Override
Expand All @@ -52,6 +54,11 @@ public Type type() {
return field.type();
}

@Override
public String name() {
return name;
}

@Override
public boolean isEquivalentTo(BoundTerm<?> other) {
if (other instanceof BoundReference) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.apache.iceberg.expressions;

import java.util.Set;
import java.util.function.Supplier;
import org.apache.iceberg.exceptions.ValidationException;

/** Utils for traversing {@link Expression expressions}. */
Expand Down Expand Up @@ -404,4 +405,187 @@ public static Boolean visitEvaluator(Expression expr, ExpressionVisitor<Boolean>
}
}
}

public abstract static class CustomOrderExpressionVisitor<R> {
public R alwaysTrue() {
return null;
}

public R alwaysFalse() {
return null;
}

public R not(Supplier<R> result) {
return null;
}

public R and(Supplier<R> leftResult, Supplier<R> rightResult) {
return null;
}

public R or(Supplier<R> leftResult, Supplier<R> rightResult) {
return null;
}

public <T> R predicate(UnboundPredicate<T> pred) {
throw new UnsupportedOperationException("Not a bound predicate: " + pred);
}

public <T> R predicate(BoundPredicate<T> pred) {
if (pred.isLiteralPredicate()) {
BoundLiteralPredicate<T> literalPred = pred.asLiteralPredicate();
switch (pred.op()) {
case LT:
return lt(pred.term(), literalPred.literal());
case LT_EQ:
return ltEq(pred.term(), literalPred.literal());
case GT:
return gt(pred.term(), literalPred.literal());
case GT_EQ:
return gtEq(pred.term(), literalPred.literal());
case EQ:
return eq(pred.term(), literalPred.literal());
case NOT_EQ:
return notEq(pred.term(), literalPred.literal());
case STARTS_WITH:
return startsWith(pred.term(), literalPred.literal());
case NOT_STARTS_WITH:
return notStartsWith(pred.term(), literalPred.literal());
default:
throw new IllegalStateException(
"Invalid operation for BoundLiteralPredicate: " + pred.op());
}

} else if (pred.isUnaryPredicate()) {
switch (pred.op()) {
case IS_NULL:
return isNull(pred.term());
case NOT_NULL:
return notNull(pred.term());
case IS_NAN:
return isNaN(pred.term());
case NOT_NAN:
return notNaN(pred.term());
default:
throw new IllegalStateException(
"Invalid operation for BoundUnaryPredicate: " + pred.op());
}

} else if (pred.isSetPredicate()) {
switch (pred.op()) {
case IN:
return in(pred.term(), pred.asSetPredicate().literalSet());
case NOT_IN:
return notIn(pred.term(), pred.asSetPredicate().literalSet());
default:
throw new IllegalStateException(
"Invalid operation for BoundSetPredicate: " + pred.op());
}
}

throw new IllegalStateException("Unsupported bound predicate: " + pred.getClass().getName());
}

public <T> R isNull(BoundTerm<T> term) {
return null;
}

public <T> R notNull(BoundTerm<T> term) {
return null;
}

public <T> R isNaN(BoundTerm<T> term) {
return null;
}

public <T> R notNaN(BoundTerm<T> term) {
return null;
}

public <T> R lt(BoundTerm<T> term, Literal<T> lit) {
return null;
}

public <T> R ltEq(BoundTerm<T> term, Literal<T> lit) {
return null;
}

public <T> R gt(BoundTerm<T> term, Literal<T> lit) {
return null;
}

public <T> R gtEq(BoundTerm<T> term, Literal<T> lit) {
return null;
}

public <T> R eq(BoundTerm<T> term, Literal<T> lit) {
return null;
}

public <T> R notEq(BoundTerm<T> term, Literal<T> lit) {
return null;
}

public <T> R in(BoundTerm<T> term, Set<T> literalSet) {
return null;
}

public <T> R notIn(BoundTerm<T> term, Set<T> literalSet) {
return null;
}

public <T> R startsWith(BoundTerm<T> term, Literal<T> lit) {
return null;
}

public <T> R notStartsWith(BoundTerm<T> term, Literal<T> lit) {
return null;
}
}

/**
* Traverses the given {@link Expression expression} with a {@link CustomOrderExpressionVisitor
* visitor}.
*
* <p>This passes a {@link Supplier} to each non-leaf {@link CustomOrderExpressionVisitor visitor}
* method. The supplier returns the result of traversing child expressions. Getting the result of
* the supplier allows traversing the expression in the desired order.
*
* @param expr an expression to traverse
* @param visitor a visitor that will be called to handle each node in the expression tree
* @param <R> the return type produced by the expression visitor
* @return the value returned by the visitor for the root expression node
*/
public static <R> R visit(Expression expr, CustomOrderExpressionVisitor<R> visitor) {
return visitExpr(expr, visitor).get();
}

private static <R> Supplier<R> visitExpr(
Expression expr, CustomOrderExpressionVisitor<R> visitor) {
if (expr instanceof Predicate) {
if (expr instanceof BoundPredicate) {
return () -> visitor.predicate((BoundPredicate<?>) expr);
} else {
return () -> visitor.predicate((UnboundPredicate<?>) expr);
}
} else {
switch (expr.op()) {
case TRUE:
return visitor::alwaysTrue;
case FALSE:
return visitor::alwaysFalse;
case NOT:
Not not = (Not) expr;
return () -> visitor.not(visitExpr(not.child(), visitor));
case AND:
And and = (And) expr;
return () -> visitor.and(visitExpr(and.left(), visitor), visitExpr(and.right(), visitor));
case OR:
Or or = (Or) expr;
return () -> visitor.or(visitExpr(or.left(), visitor), visitExpr(or.right(), visitor));
default:
throw new UnsupportedOperationException("Unknown operation: " + expr.op());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ public static <T> UnboundPredicate<T> predicate(
return new UnboundPredicate<>(op, expr, values);
}

public static <T> UnboundPredicate<T> predicate(Operation op, UnboundTerm<T> expr) {
return new UnboundPredicate<>(op, expr);
}

public static True alwaysTrue() {
return True.INSTANCE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class NamedReference<T> implements UnboundTerm<T>, Reference<T> {
this.name = name;
}

@Override
public String name() {
return name;
}
Expand All @@ -44,7 +45,7 @@ public BoundReference<T> bind(Types.StructType struct, boolean caseSensitive) {
ValidationException.check(
field != null, "Cannot find field '%s' in struct: %s", name, schema.asStruct());

return new BoundReference<>(field, schema.accessorForField(field.fieldId()));
return new BoundReference<>(field, schema.accessorForField(field.fieldId()), name);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@
* @see BoundReference
* @see NamedReference
*/
public interface Reference<T> extends Term {}
public interface Reference<T> extends Term {
String name();
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
import org.apache.iceberg.util.DateTimeUtil;
import org.apache.iceberg.util.JsonUtil;

public class DefaultValueParser {
private DefaultValueParser() {}
public class SingleValueParser {
private SingleValueParser() {}

private static final String KEYS = "keys";
private static final String VALUES = "values";
Expand Down
Loading