From 528fd9039c322866285d2ba2b89c596cb40a2194 Mon Sep 17 00:00:00 2001 From: Uros Bojanic <221401595+uros-b@users.noreply.github.com> Date: Wed, 5 Aug 2026 14:50:16 +0000 Subject: [PATCH] API: Convert statement switches to arrow switches Converts the statement-form switch blocks in iceberg-api to expression form, clearing the 89 StatementSwitchToExpressionSwitch ErrorProne warnings the module emits and removing the risk of accidental fall-through in the converted code. --- .../org/apache/iceberg/ManifestContent.java | 12 +- .../java/org/apache/iceberg/NullOrder.java | 13 +- .../apache/iceberg/expressions/Aggregate.java | 22 +- .../iceberg/expressions/BoundAggregate.java | 22 +- .../expressions/BoundLiteralPredicate.java | 102 ++---- .../expressions/BoundSetPredicate.java | 27 +- .../expressions/BoundUnaryPredicate.java | 39 +- .../iceberg/expressions/Expression.java | 80 ++--- .../iceberg/expressions/ExpressionUtil.java | 246 +++++-------- .../expressions/ExpressionVisitors.java | 305 +++++++--------- .../apache/iceberg/expressions/Literals.java | 277 +++++++-------- .../iceberg/expressions/UnboundAggregate.java | 22 +- .../iceberg/expressions/UnboundPredicate.java | 137 ++++---- .../expressions/VariantExpressionUtil.java | 109 +++--- .../GeospatialPredicateEvaluators.java | 14 +- .../org/apache/iceberg/transforms/Bucket.java | 62 ++-- .../org/apache/iceberg/transforms/Dates.java | 32 +- .../iceberg/transforms/ProjectionUtil.java | 332 ++++++++---------- .../iceberg/transforms/TimeTransform.java | 19 +- .../apache/iceberg/transforms/Timestamps.java | 71 ++-- .../apache/iceberg/transforms/Transform.java | 41 +-- .../apache/iceberg/transforms/Transforms.java | 25 +- .../apache/iceberg/transforms/Truncate.java | 89 ++--- .../org/apache/iceberg/types/Conversions.java | 163 ++++----- .../org/apache/iceberg/types/JavaHash.java | 16 +- .../org/apache/iceberg/types/TypeUtil.java | 140 +++----- .../org/apache/iceberg/util/ByteBuffers.java | 38 +- .../apache/iceberg/util/StructProjection.java | 24 +- .../apache/iceberg/variants/PhysicalType.java | 72 ++-- .../iceberg/variants/SerializedPrimitive.java | 153 +++----- .../iceberg/variants/VariantPrimitive.java | 28 +- .../apache/iceberg/variants/VariantUtil.java | 37 +- 32 files changed, 1134 insertions(+), 1635 deletions(-) diff --git a/api/src/main/java/org/apache/iceberg/ManifestContent.java b/api/src/main/java/org/apache/iceberg/ManifestContent.java index 264fc8256559..586d84703565 100644 --- a/api/src/main/java/org/apache/iceberg/ManifestContent.java +++ b/api/src/main/java/org/apache/iceberg/ManifestContent.java @@ -34,12 +34,10 @@ public int id() { } public static ManifestContent fromId(int id) { - switch (id) { - case 0: - return DATA; - case 1: - return DELETES; - } - throw new IllegalArgumentException("Unknown manifest content: " + id); + return switch (id) { + case 0 -> DATA; + case 1 -> DELETES; + default -> throw new IllegalArgumentException("Unknown manifest content: " + id); + }; } } diff --git a/api/src/main/java/org/apache/iceberg/NullOrder.java b/api/src/main/java/org/apache/iceberg/NullOrder.java index 560649e37d2b..7a02c1468d6e 100644 --- a/api/src/main/java/org/apache/iceberg/NullOrder.java +++ b/api/src/main/java/org/apache/iceberg/NullOrder.java @@ -24,13 +24,10 @@ public enum NullOrder { @Override public String toString() { - switch (this) { - case NULLS_FIRST: - return "NULLS FIRST"; - case NULLS_LAST: - return "NULLS LAST"; - default: - throw new IllegalArgumentException("Unexpected null order: " + this); - } + return switch (this) { + case NULLS_FIRST -> "NULLS FIRST"; + case NULLS_LAST -> "NULLS LAST"; + default -> throw new IllegalArgumentException("Unexpected null order: " + this); + }; } } diff --git a/api/src/main/java/org/apache/iceberg/expressions/Aggregate.java b/api/src/main/java/org/apache/iceberg/expressions/Aggregate.java index cc3ea978fcff..b06ec0b2d370 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/Aggregate.java +++ b/api/src/main/java/org/apache/iceberg/expressions/Aggregate.java @@ -42,19 +42,13 @@ public C term() { @Override public String toString() { - switch (op()) { - case COUNT: - return "count(" + term() + ")"; - case COUNT_NULL: - return "count_if(" + term() + " is null)"; - case COUNT_STAR: - return "count(*)"; - case MAX: - return "max(" + term() + ")"; - case MIN: - return "min(" + term() + ")"; - default: - throw new UnsupportedOperationException("Invalid aggregate: " + op()); - } + return switch (op()) { + case COUNT -> "count(" + term() + ")"; + case COUNT_NULL -> "count_if(" + term() + " is null)"; + case COUNT_STAR -> "count(*)"; + case MAX -> "max(" + term() + ")"; + case MIN -> "min(" + term() + ")"; + default -> throw new UnsupportedOperationException("Invalid aggregate: " + op()); + }; } } diff --git a/api/src/main/java/org/apache/iceberg/expressions/BoundAggregate.java b/api/src/main/java/org/apache/iceberg/expressions/BoundAggregate.java index 72f611df201d..ac6103ca655b 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/BoundAggregate.java +++ b/api/src/main/java/org/apache/iceberg/expressions/BoundAggregate.java @@ -78,20 +78,14 @@ public String columnName() { } public String describe() { - switch (op()) { - case COUNT_STAR: - return "count(*)"; - case COUNT: - return "count(" + ExpressionUtil.describe(term()) + ")"; - case COUNT_NULL: - return "count_if(" + ExpressionUtil.describe(term()) + " is null)"; - case MAX: - return "max(" + ExpressionUtil.describe(term()) + ")"; - case MIN: - return "min(" + ExpressionUtil.describe(term()) + ")"; - default: - throw new UnsupportedOperationException("Unsupported aggregate type: " + op()); - } + return switch (op()) { + case COUNT_STAR -> "count(*)"; + case COUNT -> "count(" + ExpressionUtil.describe(term()) + ")"; + case COUNT_NULL -> "count_if(" + ExpressionUtil.describe(term()) + " is null)"; + case MAX -> "max(" + ExpressionUtil.describe(term()) + ")"; + case MIN -> "min(" + ExpressionUtil.describe(term()) + ")"; + default -> throw new UnsupportedOperationException("Unsupported aggregate type: " + op()); + }; } boolean safeContainsKey(Map map, int key) { diff --git a/api/src/main/java/org/apache/iceberg/expressions/BoundLiteralPredicate.java b/api/src/main/java/org/apache/iceberg/expressions/BoundLiteralPredicate.java index 127d46e6a48f..05eee3ad2802 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/BoundLiteralPredicate.java +++ b/api/src/main/java/org/apache/iceberg/expressions/BoundLiteralPredicate.java @@ -71,26 +71,18 @@ public BoundLiteralPredicate asLiteralPredicate() { @Override public boolean test(T value) { Comparator cmp = literal.comparator(); - switch (op()) { - case LT: - return cmp.compare(value, literal.value()) < 0; - case LT_EQ: - return cmp.compare(value, literal.value()) <= 0; - case GT: - return cmp.compare(value, literal.value()) > 0; - case GT_EQ: - return cmp.compare(value, literal.value()) >= 0; - case EQ: - return cmp.compare(value, literal.value()) == 0; - case NOT_EQ: - return cmp.compare(value, literal.value()) != 0; - case STARTS_WITH: - return String.valueOf(value).startsWith((String) literal.value()); - case NOT_STARTS_WITH: - return !String.valueOf(value).startsWith((String) literal.value()); - default: - throw new IllegalStateException("Invalid operation for BoundLiteralPredicate: " + op()); - } + return switch (op()) { + case LT -> cmp.compare(value, literal.value()) < 0; + case LT_EQ -> cmp.compare(value, literal.value()) <= 0; + case GT -> cmp.compare(value, literal.value()) > 0; + case GT_EQ -> cmp.compare(value, literal.value()) >= 0; + case EQ -> cmp.compare(value, literal.value()) == 0; + case NOT_EQ -> cmp.compare(value, literal.value()) != 0; + case STARTS_WITH -> String.valueOf(value).startsWith((String) literal.value()); + case NOT_STARTS_WITH -> !String.valueOf(value).startsWith((String) literal.value()); + default -> + throw new IllegalStateException("Invalid operation for BoundLiteralPredicate: " + op()); + }; } @Override @@ -108,32 +100,21 @@ public boolean isEquivalentTo(Expression expr) { } else if (expr instanceof BoundLiteralPredicate) { BoundLiteralPredicate other = (BoundLiteralPredicate) expr; if (INTEGRAL_TYPES.contains(term().type().typeId()) && term().isEquivalentTo(other.term())) { - switch (op()) { - case LT: - if (other.op() == Operation.LT_EQ) { + return switch (op()) { + case LT -> // < 6 is equivalent to <= 5 - return toLong(literal()) == toLong(other.literal()) + 1L; - } - break; - case LT_EQ: - if (other.op() == Operation.LT) { + other.op() == Operation.LT_EQ && toLong(literal()) == toLong(other.literal()) + 1L; + case LT_EQ -> // <= 5 is equivalent to < 6 - return toLong(literal()) == toLong(other.literal()) - 1L; - } - break; - case GT: - if (other.op() == Operation.GT_EQ) { + other.op() == Operation.LT && toLong(literal()) == toLong(other.literal()) - 1L; + case GT -> // > 5 is equivalent to >= 6 - return toLong(literal()) == toLong(other.literal()) - 1L; - } - break; - case GT_EQ: - if (other.op() == Operation.GT) { + other.op() == Operation.GT_EQ && toLong(literal()) == toLong(other.literal()) - 1L; + case GT_EQ -> // >= 5 is equivalent to > 4 - return toLong(literal()) == toLong(other.literal()) + 1L; - } - break; - } + other.op() == Operation.GT && toLong(literal()) == toLong(other.literal()) + 1L; + default -> false; + }; } } @@ -142,29 +123,18 @@ public boolean isEquivalentTo(Expression expr) { @Override public String toString() { - switch (op()) { - case LT: - return term() + " < " + literal; - case LT_EQ: - return term() + " <= " + literal; - case GT: - return term() + " > " + literal; - case GT_EQ: - return term() + " >= " + literal; - case EQ: - return term() + " == " + literal; - case NOT_EQ: - return term() + " != " + literal; - case STARTS_WITH: - return term() + " startsWith \"" + literal + "\""; - case NOT_STARTS_WITH: - return term() + " notStartsWith \"" + literal + "\""; - case IN: - return term() + " in { " + literal + " }"; - case NOT_IN: - return term() + " not in { " + literal + " }"; - default: - return "Invalid literal predicate: operation = " + op(); - } + return switch (op()) { + case LT -> term() + " < " + literal; + case LT_EQ -> term() + " <= " + literal; + case GT -> term() + " > " + literal; + case GT_EQ -> term() + " >= " + literal; + case EQ -> term() + " == " + literal; + case NOT_EQ -> term() + " != " + literal; + case STARTS_WITH -> term() + " startsWith \"" + literal + "\""; + case NOT_STARTS_WITH -> term() + " notStartsWith \"" + literal + "\""; + case IN -> term() + " in { " + literal + " }"; + case NOT_IN -> term() + " not in { " + literal + " }"; + default -> "Invalid literal predicate: operation = " + op(); + }; } } diff --git a/api/src/main/java/org/apache/iceberg/expressions/BoundSetPredicate.java b/api/src/main/java/org/apache/iceberg/expressions/BoundSetPredicate.java index 8f77bd7b0562..f1a21b51bb7a 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/BoundSetPredicate.java +++ b/api/src/main/java/org/apache/iceberg/expressions/BoundSetPredicate.java @@ -56,14 +56,12 @@ public Set literalSet() { @Override public boolean test(T value) { - switch (op()) { - case IN: - return value != null && literalSet.contains(value); - case NOT_IN: - return value == null || !literalSet.contains(value); - default: - throw new IllegalStateException("Invalid operation for BoundSetPredicate: " + op()); - } + return switch (op()) { + case IN -> value != null && literalSet.contains(value); + case NOT_IN -> value == null || !literalSet.contains(value); + default -> + throw new IllegalStateException("Invalid operation for BoundSetPredicate: " + op()); + }; } @Override @@ -80,13 +78,10 @@ public boolean isEquivalentTo(Expression other) { @Override public String toString() { - switch (op()) { - case IN: - return term() + " in (" + COMMA.join(literalSet) + ")"; - case NOT_IN: - return term() + " not in (" + COMMA.join(literalSet) + ")"; - default: - return "Invalid unary predicate: operation = " + op(); - } + return switch (op()) { + case IN -> term() + " in (" + COMMA.join(literalSet) + ")"; + case NOT_IN -> term() + " not in (" + COMMA.join(literalSet) + ")"; + default -> "Invalid unary predicate: operation = " + op(); + }; } } diff --git a/api/src/main/java/org/apache/iceberg/expressions/BoundUnaryPredicate.java b/api/src/main/java/org/apache/iceberg/expressions/BoundUnaryPredicate.java index fb7995a71877..2d72262e7695 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/BoundUnaryPredicate.java +++ b/api/src/main/java/org/apache/iceberg/expressions/BoundUnaryPredicate.java @@ -42,18 +42,14 @@ public BoundUnaryPredicate asUnaryPredicate() { @Override public boolean test(T value) { - switch (op()) { - case IS_NULL: - return value == null; - case NOT_NULL: - return value != null; - case IS_NAN: - return NaNUtil.isNaN(value); - case NOT_NAN: - return !NaNUtil.isNaN(value); - default: - throw new IllegalStateException("Invalid operation for BoundUnaryPredicate: " + op()); - } + return switch (op()) { + case IS_NULL -> value == null; + case NOT_NULL -> value != null; + case IS_NAN -> NaNUtil.isNaN(value); + case NOT_NAN -> !NaNUtil.isNaN(value); + default -> + throw new IllegalStateException("Invalid operation for BoundUnaryPredicate: " + op()); + }; } @Override @@ -67,17 +63,12 @@ public boolean isEquivalentTo(Expression other) { @Override public String toString() { - switch (op()) { - case IS_NULL: - return "is_null(" + term() + ")"; - case NOT_NULL: - return "not_null(" + term() + ")"; - case IS_NAN: - return "is_nan(" + term() + ")"; - case NOT_NAN: - return "not_nan(" + term() + ")"; - default: - return "Invalid unary predicate: operation = " + op(); - } + return switch (op()) { + case IS_NULL -> "is_null(" + term() + ")"; + case NOT_NULL -> "not_null(" + term() + ")"; + case IS_NAN -> "is_nan(" + term() + ")"; + case NOT_NAN -> "not_nan(" + term() + ")"; + default -> "Invalid unary predicate: operation = " + op(); + }; } } diff --git a/api/src/main/java/org/apache/iceberg/expressions/Expression.java b/api/src/main/java/org/apache/iceberg/expressions/Expression.java index 9ebd1df75419..6eab6daef968 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/Expression.java +++ b/api/src/main/java/org/apache/iceberg/expressions/Expression.java @@ -62,64 +62,40 @@ public static Operation fromString(String operationType) { /** Returns the operation used when this is negated. */ public Operation negate() { - switch (this) { - case IS_NULL: - return Operation.NOT_NULL; - case NOT_NULL: - return Operation.IS_NULL; - case IS_NAN: - return Operation.NOT_NAN; - case NOT_NAN: - return Operation.IS_NAN; - case LT: - return Operation.GT_EQ; - case LT_EQ: - return Operation.GT; - case GT: - return Operation.LT_EQ; - case GT_EQ: - return Operation.LT; - case EQ: - return Operation.NOT_EQ; - case NOT_EQ: - return Operation.EQ; - case IN: - return Operation.NOT_IN; - case NOT_IN: - return Operation.IN; - case STARTS_WITH: - return Operation.NOT_STARTS_WITH; - case NOT_STARTS_WITH: - return Operation.STARTS_WITH; - default: - throw new IllegalArgumentException("No negation for operation: " + this); - } + return switch (this) { + case IS_NULL -> Operation.NOT_NULL; + case NOT_NULL -> Operation.IS_NULL; + case IS_NAN -> Operation.NOT_NAN; + case NOT_NAN -> Operation.IS_NAN; + case LT -> Operation.GT_EQ; + case LT_EQ -> Operation.GT; + case GT -> Operation.LT_EQ; + case GT_EQ -> Operation.LT; + case EQ -> Operation.NOT_EQ; + case NOT_EQ -> Operation.EQ; + case IN -> Operation.NOT_IN; + case NOT_IN -> Operation.IN; + case STARTS_WITH -> Operation.NOT_STARTS_WITH; + case NOT_STARTS_WITH -> Operation.STARTS_WITH; + default -> throw new IllegalArgumentException("No negation for operation: " + this); + }; } /** Returns the equivalent operation when the left and right operands are exchanged. */ // Allow flipLR as a name because it's a public API @SuppressWarnings("checkstyle:AbbreviationAsWordInName") public Operation flipLR() { - switch (this) { - case LT: - return Operation.GT; - case LT_EQ: - return Operation.GT_EQ; - case GT: - return Operation.LT; - case GT_EQ: - return Operation.LT_EQ; - case EQ: - return Operation.EQ; - case NOT_EQ: - return Operation.NOT_EQ; - case AND: - return Operation.AND; - case OR: - return Operation.OR; - default: - throw new IllegalArgumentException("No left-right flip for operation: " + this); - } + return switch (this) { + case LT -> Operation.GT; + case LT_EQ -> Operation.GT_EQ; + case GT -> Operation.LT; + case GT_EQ -> Operation.LT_EQ; + case EQ -> Operation.EQ; + case NOT_EQ -> Operation.NOT_EQ; + case AND -> Operation.AND; + case OR -> Operation.OR; + default -> throw new IllegalArgumentException("No left-right flip for operation: " + this); + }; } } diff --git a/api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java b/api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java index af24ce40cac8..3fdab5d8e875 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java +++ b/api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java @@ -388,32 +388,22 @@ public Expression predicate(BoundPredicate pred) { @Override @SuppressWarnings("unchecked") public Expression predicate(UnboundPredicate pred) { - switch (pred.op()) { - case IS_NULL: - case NOT_NULL: - case IS_NAN: - case NOT_NAN: - // unary predicates don't need to be sanitized - return pred; - case LT: - case LT_EQ: - case GT: - case GT_EQ: - case EQ: - case NOT_EQ: - case STARTS_WITH: - case NOT_STARTS_WITH: - return new UnboundPredicate<>( - pred.op(), pred.term(), (T) sanitize(pred.literal(), now, today)); - case IN: - case NOT_IN: + return switch (pred.op()) { + case IS_NULL, NOT_NULL, IS_NAN, NOT_NAN -> + // unary predicates don't need to be sanitized + pred; + case LT, LT_EQ, GT, GT_EQ, EQ, NOT_EQ, STARTS_WITH, NOT_STARTS_WITH -> + new UnboundPredicate<>( + pred.op(), pred.term(), (T) sanitize(pred.literal(), now, today)); + case IN, NOT_IN -> { Iterable iter = () -> pred.literals().stream().map(lit -> (T) sanitize(lit, now, today)).iterator(); - return new UnboundPredicate<>(pred.op(), pred.term(), iter); - default: - throw new UnsupportedOperationException( - "Cannot sanitize unsupported predicate type: " + pred.op()); - } + yield new UnboundPredicate<>(pred.op(), pred.term(), iter); + } + default -> + throw new UnsupportedOperationException( + "Cannot sanitize unsupported predicate type: " + pred.op()); + }; } } @@ -460,105 +450,82 @@ private String value(BoundLiteralPredicate pred) { @Override public String predicate(BoundPredicate pred) { String term = describe(pred.term()); - switch (pred.op()) { - case IS_NULL: - return term + " IS NULL"; - case NOT_NULL: - return term + " IS NOT NULL"; - case IS_NAN: - return "is_nan(" + term + ")"; - case NOT_NAN: - return "not_nan(" + term + ")"; - case LT: - return term + " < " + value((BoundLiteralPredicate) pred); - case LT_EQ: - return term + " <= " + value((BoundLiteralPredicate) pred); - case GT: - return term + " > " + value((BoundLiteralPredicate) pred); - case GT_EQ: - return term + " >= " + value((BoundLiteralPredicate) pred); - case EQ: - return term + " = " + value((BoundLiteralPredicate) pred); - case NOT_EQ: - return term + " != " + value((BoundLiteralPredicate) pred); - case IN: - return term - + " IN " - + abbreviateValues( - pred.asSetPredicate().literalSet().stream() - .map(lit -> sanitize((Literal) lit, nowMicros, today)) - .collect(Collectors.toList())) - .stream() - .collect(Collectors.joining(", ", "(", ")")); - case NOT_IN: - return term - + " NOT IN " - + abbreviateValues( - pred.asSetPredicate().literalSet().stream() - .map(lit -> sanitize((Literal) lit, nowMicros, today)) - .collect(Collectors.toList())) - .stream() - .collect(Collectors.joining(", ", "(", ")")); - case STARTS_WITH: - return term + " STARTS WITH " + value((BoundLiteralPredicate) pred); - case NOT_STARTS_WITH: - return term + " NOT STARTS WITH " + value((BoundLiteralPredicate) pred); - default: - throw new UnsupportedOperationException( - "Cannot sanitize unsupported predicate type: " + pred.op()); - } + return switch (pred.op()) { + case IS_NULL -> term + " IS NULL"; + case NOT_NULL -> term + " IS NOT NULL"; + case IS_NAN -> "is_nan(" + term + ")"; + case NOT_NAN -> "not_nan(" + term + ")"; + case LT -> term + " < " + value((BoundLiteralPredicate) pred); + case LT_EQ -> term + " <= " + value((BoundLiteralPredicate) pred); + case GT -> term + " > " + value((BoundLiteralPredicate) pred); + case GT_EQ -> term + " >= " + value((BoundLiteralPredicate) pred); + case EQ -> term + " = " + value((BoundLiteralPredicate) pred); + case NOT_EQ -> term + " != " + value((BoundLiteralPredicate) pred); + case IN -> + term + + " IN " + + abbreviateValues( + pred.asSetPredicate().literalSet().stream() + .map(lit -> sanitize((Literal) lit, nowMicros, today)) + .collect(Collectors.toList())) + .stream() + .collect(Collectors.joining(", ", "(", ")")); + case NOT_IN -> + term + + " NOT IN " + + abbreviateValues( + pred.asSetPredicate().literalSet().stream() + .map(lit -> sanitize((Literal) lit, nowMicros, today)) + .collect(Collectors.toList())) + .stream() + .collect(Collectors.joining(", ", "(", ")")); + case STARTS_WITH -> term + " STARTS WITH " + value((BoundLiteralPredicate) pred); + case NOT_STARTS_WITH -> term + " NOT STARTS WITH " + value((BoundLiteralPredicate) pred); + default -> + throw new UnsupportedOperationException( + "Cannot sanitize unsupported predicate type: " + pred.op()); + }; } @Override public String predicate(UnboundPredicate pred) { String term = describe(pred.term()); - switch (pred.op()) { - case IS_NULL: - return term + " IS NULL"; - case NOT_NULL: - return term + " IS NOT NULL"; - case IS_NAN: - return "is_nan(" + term + ")"; - case NOT_NAN: - return "not_nan(" + term + ")"; - case LT: - return term + " < " + sanitize(pred.literal(), nowMicros, today); - case LT_EQ: - return term + " <= " + sanitize(pred.literal(), nowMicros, today); - case GT: - return term + " > " + sanitize(pred.literal(), nowMicros, today); - case GT_EQ: - return term + " >= " + sanitize(pred.literal(), nowMicros, today); - case EQ: - return term + " = " + sanitize(pred.literal(), nowMicros, today); - case NOT_EQ: - return term + " != " + sanitize(pred.literal(), nowMicros, today); - case IN: - return term - + " IN " - + abbreviateValues( - pred.literals().stream() - .map(lit -> sanitize(lit, nowMicros, today)) - .collect(Collectors.toList())) - .stream() - .collect(Collectors.joining(", ", "(", ")")); - case NOT_IN: - return term - + " NOT IN " - + abbreviateValues( - pred.literals().stream() - .map(lit -> sanitize(lit, nowMicros, today)) - .collect(Collectors.toList())) - .stream() - .collect(Collectors.joining(", ", "(", ")")); - case STARTS_WITH: - return term + " STARTS WITH " + sanitize(pred.literal(), nowMicros, today); - case NOT_STARTS_WITH: - return term + " NOT STARTS WITH " + sanitize(pred.literal(), nowMicros, today); - default: - throw new UnsupportedOperationException( - "Cannot sanitize unsupported predicate type: " + pred.op()); - } + return switch (pred.op()) { + case IS_NULL -> term + " IS NULL"; + case NOT_NULL -> term + " IS NOT NULL"; + case IS_NAN -> "is_nan(" + term + ")"; + case NOT_NAN -> "not_nan(" + term + ")"; + case LT -> term + " < " + sanitize(pred.literal(), nowMicros, today); + case LT_EQ -> term + " <= " + sanitize(pred.literal(), nowMicros, today); + case GT -> term + " > " + sanitize(pred.literal(), nowMicros, today); + case GT_EQ -> term + " >= " + sanitize(pred.literal(), nowMicros, today); + case EQ -> term + " = " + sanitize(pred.literal(), nowMicros, today); + case NOT_EQ -> term + " != " + sanitize(pred.literal(), nowMicros, today); + case IN -> + term + + " IN " + + abbreviateValues( + pred.literals().stream() + .map(lit -> sanitize(lit, nowMicros, today)) + .collect(Collectors.toList())) + .stream() + .collect(Collectors.joining(", ", "(", ")")); + case NOT_IN -> + term + + " NOT IN " + + abbreviateValues( + pred.literals().stream() + .map(lit -> sanitize(lit, nowMicros, today)) + .collect(Collectors.toList())) + .stream() + .collect(Collectors.joining(", ", "(", ")")); + case STARTS_WITH -> term + " STARTS WITH " + sanitize(pred.literal(), nowMicros, today); + case NOT_STARTS_WITH -> + term + " NOT STARTS WITH " + sanitize(pred.literal(), nowMicros, today); + default -> + throw new UnsupportedOperationException( + "Cannot sanitize unsupported predicate type: " + pred.op()); + }; } } @@ -725,38 +692,19 @@ private static String sanitizeVariantValue( VariantValue fieldValue, PhysicalType fieldType, long now, int today) { StringBuilder builder = new StringBuilder(); switch (fieldType) { - case INT8: - case INT16: - case INT32: - case INT64: - case FLOAT: - case DOUBLE: - case DECIMAL4: - case DECIMAL8: - case DECIMAL16: - builder.append(sanitizeNumber((Number) fieldValue.asPrimitive().get(), fieldType.name())); - break; - case DATE: - builder.append(sanitizeDate(((Number) fieldValue.asPrimitive().get()).intValue(), today)); - break; - case TIMESTAMPTZ: - case TIMESTAMPNTZ: - case TIMESTAMPTZ_NANOS: - case TIMESTAMPNTZ_NANOS: - builder.append( - sanitizeTimestamp(((Number) fieldValue.asPrimitive().get()).longValue(), now)); - break; - case TIME: + case INT8, INT16, INT32, INT64, FLOAT, DOUBLE, DECIMAL4, DECIMAL8, DECIMAL16 -> + builder.append(sanitizeNumber((Number) fieldValue.asPrimitive().get(), fieldType.name())); + case DATE -> + builder.append(sanitizeDate(((Number) fieldValue.asPrimitive().get()).intValue(), today)); + case TIMESTAMPTZ, TIMESTAMPNTZ, TIMESTAMPTZ_NANOS, TIMESTAMPNTZ_NANOS -> + builder.append( + sanitizeTimestamp(((Number) fieldValue.asPrimitive().get()).longValue(), now)); + case TIME -> { return "(time)"; - case ARRAY: - builder.append(sanitizeVariantArray((VariantArray) fieldValue, now, today)); - break; - case OBJECT: - builder.append(sanitizeVariantObject((VariantObject) fieldValue, now, today)); - break; - default: - builder.append(sanitizeSimpleString(fieldValue.toString())); - break; + } + case ARRAY -> builder.append(sanitizeVariantArray((VariantArray) fieldValue, now, today)); + case OBJECT -> builder.append(sanitizeVariantObject((VariantObject) fieldValue, now, today)); + default -> builder.append(sanitizeSimpleString(fieldValue.toString())); } return builder.toString(); } diff --git a/api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java b/api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java index 79ca6a712887..c30b9cc71a76 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java +++ b/api/src/main/java/org/apache/iceberg/expressions/ExpressionVisitors.java @@ -149,53 +149,40 @@ public R predicate(BoundPredicate pred) { if (pred.isLiteralPredicate()) { BoundLiteralPredicate literalPred = pred.asLiteralPredicate(); - switch (pred.op()) { - case LT: - return lt((BoundReference) pred.term(), literalPred.literal()); - case LT_EQ: - return ltEq((BoundReference) pred.term(), literalPred.literal()); - case GT: - return gt((BoundReference) pred.term(), literalPred.literal()); - case GT_EQ: - return gtEq((BoundReference) pred.term(), literalPred.literal()); - case EQ: - return eq((BoundReference) pred.term(), literalPred.literal()); - case NOT_EQ: - return notEq((BoundReference) pred.term(), literalPred.literal()); - case STARTS_WITH: - return startsWith((BoundReference) pred.term(), literalPred.literal()); - case NOT_STARTS_WITH: - return notStartsWith((BoundReference) pred.term(), literalPred.literal()); - default: - throw new IllegalStateException( - "Invalid operation for BoundLiteralPredicate: " + pred.op()); - } + return switch (pred.op()) { + case LT -> lt((BoundReference) pred.term(), literalPred.literal()); + case LT_EQ -> ltEq((BoundReference) pred.term(), literalPred.literal()); + case GT -> gt((BoundReference) pred.term(), literalPred.literal()); + case GT_EQ -> gtEq((BoundReference) pred.term(), literalPred.literal()); + case EQ -> eq((BoundReference) pred.term(), literalPred.literal()); + case NOT_EQ -> notEq((BoundReference) pred.term(), literalPred.literal()); + case STARTS_WITH -> startsWith((BoundReference) pred.term(), literalPred.literal()); + case NOT_STARTS_WITH -> + notStartsWith((BoundReference) 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((BoundReference) pred.term()); - case NOT_NULL: - return notNull((BoundReference) pred.term()); - case IS_NAN: - return isNaN((BoundReference) pred.term()); - case NOT_NAN: - return notNaN((BoundReference) pred.term()); - default: - throw new IllegalStateException( - "Invalid operation for BoundUnaryPredicate: " + pred.op()); - } + return switch (pred.op()) { + case IS_NULL -> isNull((BoundReference) pred.term()); + case NOT_NULL -> notNull((BoundReference) pred.term()); + case IS_NAN -> isNaN((BoundReference) pred.term()); + case NOT_NAN -> notNaN((BoundReference) pred.term()); + default -> + throw new IllegalStateException( + "Invalid operation for BoundUnaryPredicate: " + pred.op()); + }; } else if (pred.isSetPredicate()) { - switch (pred.op()) { - case IN: - return in((BoundReference) pred.term(), pred.asSetPredicate().literalSet()); - case NOT_IN: - return notIn((BoundReference) pred.term(), pred.asSetPredicate().literalSet()); - default: - throw new IllegalStateException( - "Invalid operation for BoundSetPredicate: " + pred.op()); - } + return switch (pred.op()) { + case IN -> in((BoundReference) pred.term(), pred.asSetPredicate().literalSet()); + case NOT_IN -> notIn((BoundReference) pred.term(), pred.asSetPredicate().literalSet()); + default -> + throw new IllegalStateException( + "Invalid operation for BoundSetPredicate: " + pred.op()); + }; } throw new IllegalStateException("Unsupported bound predicate: " + pred.getClass().getName()); @@ -270,53 +257,39 @@ public R notStartsWith(Bound expr, Literal lit) { public R predicate(BoundPredicate pred) { if (pred.isLiteralPredicate()) { BoundLiteralPredicate 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()); - } + return switch (pred.op()) { + case LT -> lt(pred.term(), literalPred.literal()); + case LT_EQ -> ltEq(pred.term(), literalPred.literal()); + case GT -> gt(pred.term(), literalPred.literal()); + case GT_EQ -> gtEq(pred.term(), literalPred.literal()); + case EQ -> eq(pred.term(), literalPred.literal()); + case NOT_EQ -> notEq(pred.term(), literalPred.literal()); + case STARTS_WITH -> startsWith(pred.term(), literalPred.literal()); + case NOT_STARTS_WITH -> 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()); - } + return switch (pred.op()) { + case IS_NULL -> isNull(pred.term()); + case NOT_NULL -> notNull(pred.term()); + case IS_NAN -> isNaN(pred.term()); + case NOT_NAN -> 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()); - } + return switch (pred.op()) { + case IN -> in(pred.term(), pred.asSetPredicate().literalSet()); + case NOT_IN -> 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()); @@ -353,23 +326,23 @@ public static R visit(Expression expr, ExpressionVisitor visitor) { return visitor.aggregate((UnboundAggregate) expr); } } else { - switch (expr.op()) { - case TRUE: - return visitor.alwaysTrue(); - case FALSE: - return visitor.alwaysFalse(); - case NOT: + return switch (expr.op()) { + case TRUE -> visitor.alwaysTrue(); + case FALSE -> visitor.alwaysFalse(); + case NOT -> { Not not = (Not) expr; - return visitor.not(visit(not.child(), visitor)); - case AND: + yield visitor.not(visit(not.child(), visitor)); + } + case AND -> { And and = (And) expr; - return visitor.and(visit(and.left(), visitor), visit(and.right(), visitor)); - case OR: + yield visitor.and(visit(and.left(), visitor), visit(and.right(), visitor)); + } + case OR -> { Or or = (Or) expr; - return visitor.or(visit(or.left(), visitor), visit(or.right(), visitor)); - default: - throw new UnsupportedOperationException("Unknown operation: " + expr.op()); - } + yield visitor.or(visit(or.left(), visitor), visit(or.right(), visitor)); + } + default -> throw new UnsupportedOperationException("Unknown operation: " + expr.op()); + }; } } @@ -392,31 +365,31 @@ public static Boolean visitEvaluator(Expression expr, ExpressionVisitor return visitor.predicate((UnboundPredicate) expr); } } else { - switch (expr.op()) { - case TRUE: - return visitor.alwaysTrue(); - case FALSE: - return visitor.alwaysFalse(); - case NOT: + return switch (expr.op()) { + case TRUE -> visitor.alwaysTrue(); + case FALSE -> visitor.alwaysFalse(); + case NOT -> { Not not = (Not) expr; - return visitor.not(visitEvaluator(not.child(), visitor)); - case AND: + yield visitor.not(visitEvaluator(not.child(), visitor)); + } + case AND -> { And and = (And) expr; Boolean andLeftOperand = visitEvaluator(and.left(), visitor); if (!andLeftOperand) { - return visitor.alwaysFalse(); + yield visitor.alwaysFalse(); } - return visitor.and(Boolean.TRUE, visitEvaluator(and.right(), visitor)); - case OR: + yield visitor.and(Boolean.TRUE, visitEvaluator(and.right(), visitor)); + } + case OR -> { Or or = (Or) expr; Boolean orLeftOperand = visitEvaluator(or.left(), visitor); if (orLeftOperand) { - return visitor.alwaysTrue(); + yield visitor.alwaysTrue(); } - return visitor.or(Boolean.FALSE, visitEvaluator(or.right(), visitor)); - default: - throw new UnsupportedOperationException("Unknown operation: " + expr.op()); - } + yield visitor.or(Boolean.FALSE, visitEvaluator(or.right(), visitor)); + } + default -> throw new UnsupportedOperationException("Unknown operation: " + expr.op()); + }; } } @@ -448,53 +421,39 @@ public R predicate(UnboundPredicate pred) { public R predicate(BoundPredicate pred) { if (pred.isLiteralPredicate()) { BoundLiteralPredicate 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()); - } + return switch (pred.op()) { + case LT -> lt(pred.term(), literalPred.literal()); + case LT_EQ -> ltEq(pred.term(), literalPred.literal()); + case GT -> gt(pred.term(), literalPred.literal()); + case GT_EQ -> gtEq(pred.term(), literalPred.literal()); + case EQ -> eq(pred.term(), literalPred.literal()); + case NOT_EQ -> notEq(pred.term(), literalPred.literal()); + case STARTS_WITH -> startsWith(pred.term(), literalPred.literal()); + case NOT_STARTS_WITH -> 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()); - } + return switch (pred.op()) { + case IS_NULL -> isNull(pred.term()); + case NOT_NULL -> notNull(pred.term()); + case IS_NAN -> isNaN(pred.term()); + case NOT_NAN -> 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()); - } + return switch (pred.op()) { + case IN -> in(pred.term(), pred.asSetPredicate().literalSet()); + case NOT_IN -> 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()); @@ -583,23 +542,23 @@ private static Supplier visitExpr( return () -> visitor.predicate((UnboundPredicate) expr); } } else { - switch (expr.op()) { - case TRUE: - return visitor::alwaysTrue; - case FALSE: - return visitor::alwaysFalse; - case NOT: + return switch (expr.op()) { + case TRUE -> visitor::alwaysTrue; + case FALSE -> visitor::alwaysFalse; + case NOT -> { Not not = (Not) expr; - return () -> visitor.not(visitExpr(not.child(), visitor)); - case AND: + yield () -> 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: + yield () -> 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()); - } + yield () -> visitor.or(visitExpr(or.left(), visitor), visitExpr(or.right(), visitor)); + } + default -> throw new UnsupportedOperationException("Unknown operation: " + expr.op()); + }; } } } diff --git a/api/src/main/java/org/apache/iceberg/expressions/Literals.java b/api/src/main/java/org/apache/iceberg/expressions/Literals.java index c54dff72f87e..aa3a0e7fb362 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/Literals.java +++ b/api/src/main/java/org/apache/iceberg/expressions/Literals.java @@ -253,25 +253,20 @@ static class IntegerLiteral extends ComparableLiteral { @Override @SuppressWarnings("unchecked") public Literal to(Type type) { - switch (type.typeId()) { - case INTEGER: - return (Literal) this; - case LONG: - return (Literal) new LongLiteral(value().longValue()); - case FLOAT: - return (Literal) new FloatLiteral(value().floatValue()); - case DOUBLE: - return (Literal) new DoubleLiteral(value().doubleValue()); - case DATE: - return (Literal) new DateLiteral(value()); - case DECIMAL: + return switch (type.typeId()) { + case INTEGER -> (Literal) this; + case LONG -> (Literal) new LongLiteral(value().longValue()); + case FLOAT -> (Literal) new FloatLiteral(value().floatValue()); + case DOUBLE -> (Literal) new DoubleLiteral(value().doubleValue()); + case DATE -> (Literal) new DateLiteral(value()); + case DECIMAL -> { int scale = ((Types.DecimalType) type).scale(); // rounding mode isn't necessary, but pass one to avoid warnings - return (Literal) + yield (Literal) new DecimalLiteral(BigDecimal.valueOf(value()).setScale(scale, RoundingMode.HALF_UP)); - default: - return null; - } + } + default -> null; + }; } @Override @@ -288,42 +283,39 @@ static class LongLiteral extends ComparableLiteral { @Override @SuppressWarnings("unchecked") public Literal to(Type type) { - switch (type.typeId()) { - case INTEGER: + return switch (type.typeId()) { + case INTEGER -> { if ((long) Integer.MAX_VALUE < value()) { - return aboveMax(); + yield aboveMax(); } else if ((long) Integer.MIN_VALUE > value()) { - return belowMin(); + yield belowMin(); } - return (Literal) new IntegerLiteral(value().intValue()); - case LONG: - return (Literal) this; - case FLOAT: - return (Literal) new FloatLiteral(value().floatValue()); - case DOUBLE: - return (Literal) new DoubleLiteral(value().doubleValue()); - case TIME: - return (Literal) new TimeLiteral(value()); - case TIMESTAMP: - return (Literal) new TimestampLiteral(value()); - case TIMESTAMP_NANO: - // assume micros and convert to nanos to match the behavior in the timestamp case above - return new TimestampLiteral(value()).to(type); - case DATE: + yield (Literal) new IntegerLiteral(value().intValue()); + } + case LONG -> (Literal) this; + case FLOAT -> (Literal) new FloatLiteral(value().floatValue()); + case DOUBLE -> (Literal) new DoubleLiteral(value().doubleValue()); + case TIME -> (Literal) new TimeLiteral(value()); + case TIMESTAMP -> (Literal) new TimestampLiteral(value()); + case TIMESTAMP_NANO -> + // assume micros and convert to nanos to match the behavior in the timestamp case above + new TimestampLiteral(value()).to(type); + case DATE -> { if ((long) Integer.MAX_VALUE < value()) { - return aboveMax(); + yield aboveMax(); } else if ((long) Integer.MIN_VALUE > value()) { - return belowMin(); + yield belowMin(); } - return (Literal) new DateLiteral(value().intValue()); - case DECIMAL: + yield (Literal) new DateLiteral(value().intValue()); + } + case DECIMAL -> { int scale = ((Types.DecimalType) type).scale(); // rounding mode isn't necessary, but pass one to avoid warnings - return (Literal) + yield (Literal) new DecimalLiteral(BigDecimal.valueOf(value()).setScale(scale, RoundingMode.HALF_UP)); - default: - return null; - } + } + default -> null; + }; } @Override @@ -340,18 +332,16 @@ static class FloatLiteral extends ComparableLiteral { @Override @SuppressWarnings("unchecked") public Literal to(Type type) { - switch (type.typeId()) { - case FLOAT: - return (Literal) this; - case DOUBLE: - return (Literal) new DoubleLiteral(value().doubleValue()); - case DECIMAL: + return switch (type.typeId()) { + case FLOAT -> (Literal) this; + case DOUBLE -> (Literal) new DoubleLiteral(value().doubleValue()); + case DECIMAL -> { int scale = ((Types.DecimalType) type).scale(); - return (Literal) + yield (Literal) new DecimalLiteral(BigDecimal.valueOf(value()).setScale(scale, RoundingMode.HALF_UP)); - default: - return null; - } + } + default -> null; + }; } @Override @@ -368,25 +358,25 @@ static class DoubleLiteral extends ComparableLiteral { @Override @SuppressWarnings("unchecked") public Literal to(Type type) { - switch (type.typeId()) { - case FLOAT: + return switch (type.typeId()) { + case FLOAT -> { if ((double) Float.MAX_VALUE < value()) { - return aboveMax(); + yield aboveMax(); } else if ((double) -Float.MAX_VALUE > value()) { // Compare with -Float.MAX_VALUE because it is the most negative float value. // Float.MIN_VALUE is the smallest non-negative floating point value. - return belowMin(); + yield belowMin(); } - return (Literal) new FloatLiteral(value().floatValue()); - case DOUBLE: - return (Literal) this; - case DECIMAL: + yield (Literal) new FloatLiteral(value().floatValue()); + } + case DOUBLE -> (Literal) this; + case DECIMAL -> { int scale = ((Types.DecimalType) type).scale(); - return (Literal) + yield (Literal) new DecimalLiteral(BigDecimal.valueOf(value()).setScale(scale, RoundingMode.HALF_UP)); - default: - return null; - } + } + default -> null; + }; } @Override @@ -443,16 +433,13 @@ static class TimestampLiteral extends ComparableLiteral { @Override @SuppressWarnings("unchecked") public Literal to(Type type) { - switch (type.typeId()) { - case TIMESTAMP: - return (Literal) this; - case DATE: - return (Literal) new DateLiteral(DateTimeUtil.microsToDays(value())); - case TIMESTAMP_NANO: - return (Literal) new TimestampNanoLiteral(DateTimeUtil.microsToNanos(value())); - default: - } - return null; + return switch (type.typeId()) { + case TIMESTAMP -> (Literal) this; + case DATE -> (Literal) new DateLiteral(DateTimeUtil.microsToDays(value())); + case TIMESTAMP_NANO -> + (Literal) new TimestampNanoLiteral(DateTimeUtil.microsToNanos(value())); + default -> null; + }; } @Override @@ -469,16 +456,12 @@ static class TimestampNanoLiteral extends ComparableLiteral { @Override @SuppressWarnings("unchecked") public Literal to(Type type) { - switch (type.typeId()) { - case DATE: - return (Literal) new DateLiteral(DateTimeUtil.nanosToDays(value())); - case TIMESTAMP: - return (Literal) new TimestampLiteral(DateTimeUtil.nanosToMicros(value())); - case TIMESTAMP_NANO: - return (Literal) this; - default: - } - return null; + return switch (type.typeId()) { + case DATE -> (Literal) new DateLiteral(DateTimeUtil.nanosToDays(value())); + case TIMESTAMP -> (Literal) new TimestampLiteral(DateTimeUtil.nanosToMicros(value())); + case TIMESTAMP_NANO -> (Literal) this; + default -> null; + }; } @Override @@ -495,13 +478,12 @@ static class DecimalLiteral extends ComparableLiteral { @Override @SuppressWarnings("unchecked") public Literal to(Type type) { - switch (type.typeId()) { - case DECIMAL: - // do not change decimal scale - return (Literal) this; - default: - return null; - } + return switch (type.typeId()) { + case DECIMAL -> + // do not change decimal scale + (Literal) this; + default -> null; + }; } @Override @@ -518,12 +500,10 @@ static class VariantLiteral extends BaseLiteral { @Override @SuppressWarnings("unchecked") public Literal to(Type type) { - switch (type.typeId()) { - case VARIANT: - return (Literal) this; - default: - return null; - } + return switch (type.typeId()) { + case VARIANT -> (Literal) this; + default -> null; + }; } @Override @@ -548,76 +528,71 @@ static class StringLiteral extends BaseLiteral { @Override @SuppressWarnings("unchecked") public Literal to(Type type) { - switch (type.typeId()) { - case DATE: + return switch (type.typeId()) { + case DATE -> { int date = (int) ChronoUnit.DAYS.between( EPOCH_DAY, LocalDate.parse(value(), DateTimeFormatter.ISO_LOCAL_DATE)); - return (Literal) new DateLiteral(date); - - case TIME: + yield (Literal) new DateLiteral(date); + } + case TIME -> { long timeMicros = LocalTime.parse(value(), DateTimeFormatter.ISO_LOCAL_TIME).toNanoOfDay() / 1000; - return (Literal) new TimeLiteral(timeMicros); - - case TIMESTAMP: + yield (Literal) new TimeLiteral(timeMicros); + } + case TIMESTAMP -> { if (((Types.TimestampType) type).shouldAdjustToUTC()) { long timestampMicros = DateTimeUtil.isoTimestamptzToMicros(value().toString()); - return (Literal) new TimestampLiteral(timestampMicros); + yield (Literal) new TimestampLiteral(timestampMicros); } else { long timestampMicros = DateTimeUtil.isoTimestampToMicros(value().toString()); - return (Literal) new TimestampLiteral(timestampMicros); + yield (Literal) new TimestampLiteral(timestampMicros); } - - case TIMESTAMP_NANO: + } + case TIMESTAMP_NANO -> { if (((Types.TimestampNanoType) type).shouldAdjustToUTC()) { - return (Literal) + yield (Literal) new TimestampNanoLiteral(DateTimeUtil.isoTimestamptzToNanos(value())); } else { - return (Literal) new TimestampNanoLiteral(DateTimeUtil.isoTimestampToNanos(value())); + yield (Literal) new TimestampNanoLiteral(DateTimeUtil.isoTimestampToNanos(value())); } - - case STRING: - return (Literal) this; - - case UUID: - return (Literal) new UUIDLiteral(UUID.fromString(value().toString())); - - case DECIMAL: + } + case STRING -> (Literal) this; + case UUID -> (Literal) new UUIDLiteral(UUID.fromString(value().toString())); + case DECIMAL -> { // do not change decimal scale BigDecimal decimal = new BigDecimal(value().toString()); - return (Literal) new DecimalLiteral(decimal); - - case FIXED: + yield (Literal) new DecimalLiteral(decimal); + } + case FIXED -> { try { ByteBuffer buffer = ByteBuffer.wrap( BASE16_ENCODING.decode(value().toString().toUpperCase(Locale.ROOT))); Types.FixedType fixed = (Types.FixedType) type; if (buffer.remaining() == fixed.length()) { - return (Literal) new FixedLiteral(buffer); + yield (Literal) new FixedLiteral(buffer); } - return null; + yield null; } catch (IllegalArgumentException e) { // Invalid hex string - return null; + yield null; } - - case BINARY: + } + case BINARY -> { try { - return (Literal) + yield (Literal) new BinaryLiteral( ByteBuffer.wrap( BASE16_ENCODING.decode(value().toString().toUpperCase(Locale.ROOT)))); } catch (IllegalArgumentException e) { // Invalid hex string - return null; + yield null; } - - default: - return null; - } + } + default -> null; + }; } @Override @@ -667,18 +642,17 @@ static class FixedLiteral extends BaseLiteral { @Override @SuppressWarnings("unchecked") public Literal to(Type type) { - switch (type.typeId()) { - case FIXED: + return switch (type.typeId()) { + case FIXED -> { Types.FixedType fixed = (Types.FixedType) type; if (value().remaining() == fixed.length()) { - return (Literal) this; + yield (Literal) this; } - return null; - case BINARY: - return (Literal) new BinaryLiteral(value()); - default: - return null; - } + yield null; + } + case BINARY -> (Literal) new BinaryLiteral(value()); + default -> null; + }; } @Override @@ -713,18 +687,17 @@ static class BinaryLiteral extends BaseLiteral { @Override @SuppressWarnings("unchecked") public Literal to(Type type) { - switch (type.typeId()) { - case FIXED: + return switch (type.typeId()) { + case FIXED -> { Types.FixedType fixed = (Types.FixedType) type; if (value().remaining() == fixed.length()) { - return (Literal) new FixedLiteral(value()); + yield (Literal) new FixedLiteral(value()); } - return null; - case BINARY: - return (Literal) this; - default: - return null; - } + yield null; + } + case BINARY -> (Literal) this; + default -> null; + }; } @Override diff --git a/api/src/main/java/org/apache/iceberg/expressions/UnboundAggregate.java b/api/src/main/java/org/apache/iceberg/expressions/UnboundAggregate.java index 6bff05e772e9..fead399d598d 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/UnboundAggregate.java +++ b/api/src/main/java/org/apache/iceberg/expressions/UnboundAggregate.java @@ -46,20 +46,14 @@ public NamedReference ref() { */ @Override public Expression bind(Types.StructType struct, boolean caseSensitive) { - switch (op()) { - case COUNT_STAR: - return new CountStar<>(null); - case COUNT: - return new CountNonNull<>(boundTerm(struct, caseSensitive)); - case COUNT_NULL: - return new CountNull<>(boundTerm(struct, caseSensitive)); - case MAX: - return new MaxAggregate<>(boundTerm(struct, caseSensitive)); - case MIN: - return new MinAggregate<>(boundTerm(struct, caseSensitive)); - default: - throw new UnsupportedOperationException("Unsupported aggregate type: " + op()); - } + return switch (op()) { + case COUNT_STAR -> new CountStar<>(null); + case COUNT -> new CountNonNull<>(boundTerm(struct, caseSensitive)); + case COUNT_NULL -> new CountNull<>(boundTerm(struct, caseSensitive)); + case MAX -> new MaxAggregate<>(boundTerm(struct, caseSensitive)); + case MIN -> new MinAggregate<>(boundTerm(struct, caseSensitive)); + default -> throw new UnsupportedOperationException("Unsupported aggregate type: " + op()); + }; } private BoundTerm boundTerm(Types.StructType struct, boolean caseSensitive) { diff --git a/api/src/main/java/org/apache/iceberg/expressions/UnboundPredicate.java b/api/src/main/java/org/apache/iceberg/expressions/UnboundPredicate.java index 75ca9d5835bc..23bd3e80404e 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/UnboundPredicate.java +++ b/api/src/main/java/org/apache/iceberg/expressions/UnboundPredicate.java @@ -124,38 +124,42 @@ public Expression bind(StructType struct, boolean caseSensitive) { } private Expression bindUnaryOperation(StructType struct, BoundTerm boundTerm) { - switch (op()) { - case IS_NULL: + return switch (op()) { + case IS_NULL -> { if (!boundTerm.producesNull() && allAncestorFieldsAreRequired(struct, boundTerm.ref().fieldId())) { - return Expressions.alwaysFalse(); + yield Expressions.alwaysFalse(); } else if (boundTerm.type().equals(Types.UnknownType.get())) { - return Expressions.alwaysTrue(); + yield Expressions.alwaysTrue(); } - return new BoundUnaryPredicate<>(Operation.IS_NULL, boundTerm); - case NOT_NULL: + yield new BoundUnaryPredicate<>(Operation.IS_NULL, boundTerm); + } + case NOT_NULL -> { if (!boundTerm.producesNull() && allAncestorFieldsAreRequired(struct, boundTerm.ref().fieldId())) { - return Expressions.alwaysTrue(); + yield Expressions.alwaysTrue(); } else if (boundTerm.type().equals(Types.UnknownType.get())) { - return Expressions.alwaysFalse(); + yield Expressions.alwaysFalse(); } - return new BoundUnaryPredicate<>(Operation.NOT_NULL, boundTerm); - case IS_NAN: + yield new BoundUnaryPredicate<>(Operation.NOT_NULL, boundTerm); + } + case IS_NAN -> { if (floatingType(boundTerm.type().typeId())) { - return new BoundUnaryPredicate<>(Operation.IS_NAN, boundTerm); + yield new BoundUnaryPredicate<>(Operation.IS_NAN, boundTerm); } else { throw new ValidationException("IsNaN cannot be used with a non-floating-point column"); } - case NOT_NAN: + } + case NOT_NAN -> { if (floatingType(boundTerm.type().typeId())) { - return new BoundUnaryPredicate<>(Operation.NOT_NAN, boundTerm); + yield new BoundUnaryPredicate<>(Operation.NOT_NAN, boundTerm); } else { throw new ValidationException("NotNaN cannot be used with a non-floating-point column"); } - default: - throw new ValidationException("Operation must be IS_NULL, NOT_NULL, IS_NAN, or NOT_NAN"); - } + } + default -> + throw new ValidationException("Operation must be IS_NULL, NOT_NULL, IS_NAN, or NOT_NAN"); + }; } private boolean allAncestorFieldsAreRequired(StructType struct, int fieldId) { @@ -185,25 +189,21 @@ private Expression bindLiteralOperation(BoundTerm boundTerm) { } else if (lit == Literals.aboveMax()) { switch (op()) { - case LT: - case LT_EQ: - case NOT_EQ: + case LT, LT_EQ, NOT_EQ -> { return Expressions.alwaysTrue(); - case GT: - case GT_EQ: - case EQ: + } + case GT, GT_EQ, EQ -> { return Expressions.alwaysFalse(); + } } } else if (lit == Literals.belowMin()) { switch (op()) { - case GT: - case GT_EQ: - case NOT_EQ: + case GT, GT_EQ, NOT_EQ -> { return Expressions.alwaysTrue(); - case LT: - case LT_EQ: - case EQ: + } + case LT, LT_EQ, EQ -> { return Expressions.alwaysFalse(); + } } } @@ -230,28 +230,24 @@ private Expression bindInOperation(BoundTerm boundTerm) { lit -> lit != Literals.aboveMax() && lit != Literals.belowMin())); if (convertedLiterals.isEmpty()) { - switch (op()) { - case IN: - return Expressions.alwaysFalse(); - case NOT_IN: - return Expressions.alwaysTrue(); - default: - throw new ValidationException("Operation must be IN or NOT_IN"); - } + return switch (op()) { + case IN -> Expressions.alwaysFalse(); + case NOT_IN -> Expressions.alwaysTrue(); + default -> throw new ValidationException("Operation must be IN or NOT_IN"); + }; } Set literalSet = setOf(convertedLiterals); if (literalSet.size() == 1) { - switch (op()) { - case IN: - return new BoundLiteralPredicate<>( - Operation.EQ, boundTerm, Iterables.get(convertedLiterals, 0)); - case NOT_IN: - return new BoundLiteralPredicate<>( - Operation.NOT_EQ, boundTerm, Iterables.get(convertedLiterals, 0)); - default: - throw new ValidationException("Operation must be IN or NOT_IN"); - } + return switch (op()) { + case IN -> + new BoundLiteralPredicate<>( + Operation.EQ, boundTerm, Iterables.get(convertedLiterals, 0)); + case NOT_IN -> + new BoundLiteralPredicate<>( + Operation.NOT_EQ, boundTerm, Iterables.get(convertedLiterals, 0)); + default -> throw new ValidationException("Operation must be IN or NOT_IN"); + }; } return new BoundSetPredicate<>(op(), boundTerm, literalSet); @@ -259,38 +255,23 @@ private Expression bindInOperation(BoundTerm boundTerm) { @Override public String toString() { - switch (op()) { - case IS_NULL: - return "is_null(" + term() + ")"; - case NOT_NULL: - return "not_null(" + term() + ")"; - case IS_NAN: - return "is_nan(" + term() + ")"; - case NOT_NAN: - return "not_nan(" + term() + ")"; - case LT: - return term() + " < " + literal(); - case LT_EQ: - return term() + " <= " + literal(); - case GT: - return term() + " > " + literal(); - case GT_EQ: - return term() + " >= " + literal(); - case EQ: - return term() + " == " + literal(); - case NOT_EQ: - return term() + " != " + literal(); - case STARTS_WITH: - return term() + " startsWith \"" + literal() + "\""; - case NOT_STARTS_WITH: - return term() + " notStartsWith \"" + literal() + "\""; - case IN: - return term() + " in (" + COMMA.join(literals()) + ")"; - case NOT_IN: - return term() + " not in (" + COMMA.join(literals()) + ")"; - default: - return "Invalid predicate: operation = " + op(); - } + return switch (op()) { + case IS_NULL -> "is_null(" + term() + ")"; + case NOT_NULL -> "not_null(" + term() + ")"; + case IS_NAN -> "is_nan(" + term() + ")"; + case NOT_NAN -> "not_nan(" + term() + ")"; + case LT -> term() + " < " + literal(); + case LT_EQ -> term() + " <= " + literal(); + case GT -> term() + " > " + literal(); + case GT_EQ -> term() + " >= " + literal(); + case EQ -> term() + " == " + literal(); + case NOT_EQ -> term() + " != " + literal(); + case STARTS_WITH -> term() + " startsWith \"" + literal() + "\""; + case NOT_STARTS_WITH -> term() + " notStartsWith \"" + literal() + "\""; + case IN -> term() + " in (" + COMMA.join(literals()) + ")"; + case NOT_IN -> term() + " not in (" + COMMA.join(literals()) + ")"; + default -> "Invalid predicate: operation = " + op(); + }; } @SuppressWarnings("unchecked") diff --git a/api/src/main/java/org/apache/iceberg/expressions/VariantExpressionUtil.java b/api/src/main/java/org/apache/iceberg/expressions/VariantExpressionUtil.java index daec5216f0ef..be00f2ca9cb3 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/VariantExpressionUtil.java +++ b/api/src/main/java/org/apache/iceberg/expressions/VariantExpressionUtil.java @@ -57,98 +57,91 @@ static T castTo(VariantValue value, Type type) { return (T) value.asPrimitive().get(); } - switch (type.typeId()) { - case INTEGER: - switch (value.type()) { - case INT8: - case INT16: - return (T) (Integer) ((Number) value.asPrimitive().get()).intValue(); - } - - break; - case LONG: - switch (value.type()) { - case INT8: - case INT16: - case INT32: - return (T) (Long) ((Number) value.asPrimitive().get()).longValue(); - } - - break; - case DOUBLE: + return switch (type.typeId()) { + case INTEGER -> + switch (value.type()) { + case INT8, INT16 -> (T) (Integer) ((Number) value.asPrimitive().get()).intValue(); + default -> null; + }; + case LONG -> + switch (value.type()) { + case INT8, INT16, INT32 -> (T) (Long) ((Number) value.asPrimitive().get()).longValue(); + default -> null; + }; + case DOUBLE -> { if (value.type() == PhysicalType.FLOAT) { - return (T) (Double) ((Number) value.asPrimitive().get()).doubleValue(); + yield (T) (Double) ((Number) value.asPrimitive().get()).doubleValue(); } - - break; - case FIXED: + yield null; + } + case FIXED -> { Types.FixedType fixedType = (Types.FixedType) type; if (value.type() == PhysicalType.BINARY) { ByteBuffer buffer = (ByteBuffer) value.asPrimitive().get(); if (buffer.remaining() == fixedType.length()) { - return (T) buffer; + yield (T) buffer; } } - - break; - case DECIMAL: + yield null; + } + case DECIMAL -> { Types.DecimalType decimalType = (Types.DecimalType) type; - switch (value.type()) { - case DECIMAL4: - case DECIMAL8: - case DECIMAL16: + yield switch (value.type()) { + case DECIMAL4, DECIMAL8, DECIMAL16 -> { BigDecimal decimalValue = (BigDecimal) value.asPrimitive().get(); if (decimalValue.scale() == decimalType.scale()) { - return (T) decimalValue; + yield (T) decimalValue; } - } - - break; - case BOOLEAN: - switch (value.type()) { - case BOOLEAN_FALSE: - return (T) Boolean.FALSE; - case BOOLEAN_TRUE: - return (T) Boolean.TRUE; - } - - break; - case TIMESTAMP: + yield null; + } + default -> null; + }; + } + case BOOLEAN -> + switch (value.type()) { + case BOOLEAN_FALSE -> (T) Boolean.FALSE; + case BOOLEAN_TRUE -> (T) Boolean.TRUE; + default -> null; + }; + case TIMESTAMP -> { if (value.type() == PhysicalType.TIMESTAMPTZ_NANOS || value.type() == PhysicalType.TIMESTAMPNTZ_NANOS) { - return (T) + yield (T) (Long) DateTimeUtil.nanosToMicros(((Number) value.asPrimitive().get()).longValue()); } else if (value.type() == PhysicalType.DATE) { - return (T) + yield (T) (Long) DateTimeUtil.microsFromTimestamp( DateTimeUtil.dateFromDays(((Number) value.asPrimitive().get()).intValue()) .atStartOfDay()); } - break; - case TIMESTAMP_NANO: + yield null; + } + case TIMESTAMP_NANO -> { if (value.type() == PhysicalType.TIMESTAMPTZ || value.type() == PhysicalType.TIMESTAMPNTZ) { - return (T) + yield (T) (Long) DateTimeUtil.microsToNanos(((Number) value.asPrimitive().get()).longValue()); } else if (value.type() == PhysicalType.DATE) { - return (T) + yield (T) (Long) DateTimeUtil.nanosFromTimestamp( DateTimeUtil.dateFromDays(((Number) value.asPrimitive().get()).intValue()) .atStartOfDay()); } - break; - case DATE: + yield null; + } + case DATE -> { if (value.type() == PhysicalType.TIMESTAMPTZ || value.type() == PhysicalType.TIMESTAMPNTZ) { - return (T) + yield (T) (Integer) DateTimeUtil.microsToDays(((Number) value.asPrimitive().get()).longValue()); } else if (value.type() == PhysicalType.TIMESTAMPTZ_NANOS || value.type() == PhysicalType.TIMESTAMPNTZ_NANOS) { - return (T) + yield (T) (Integer) DateTimeUtil.nanosToDays(((Number) value.asPrimitive().get()).longValue()); } - } - - return null; + yield null; + } + default -> null; + }; } } diff --git a/api/src/main/java/org/apache/iceberg/geospatial/GeospatialPredicateEvaluators.java b/api/src/main/java/org/apache/iceberg/geospatial/GeospatialPredicateEvaluators.java index 4e699e301e0a..619e4e84e1a4 100644 --- a/api/src/main/java/org/apache/iceberg/geospatial/GeospatialPredicateEvaluators.java +++ b/api/src/main/java/org/apache/iceberg/geospatial/GeospatialPredicateEvaluators.java @@ -42,14 +42,12 @@ public interface GeospatialPredicateEvaluator { * @return the evaluator */ public static GeospatialPredicateEvaluator create(Type type) { - switch (type.typeId()) { - case GEOMETRY: - return new GeometryEvaluator(); - case GEOGRAPHY: - return new GeographyEvaluator(); - default: - throw new UnsupportedOperationException("Unsupported type for BoundingBox: " + type); - } + return switch (type.typeId()) { + case GEOMETRY -> new GeometryEvaluator(); + case GEOGRAPHY -> new GeographyEvaluator(); + default -> + throw new UnsupportedOperationException("Unsupported type for BoundingBox: " + type); + }; } public static class GeometryEvaluator implements GeospatialPredicateEvaluator { diff --git a/api/src/main/java/org/apache/iceberg/transforms/Bucket.java b/api/src/main/java/org/apache/iceberg/transforms/Bucket.java index 2b2439e3ed0a..0045d306fa18 100644 --- a/api/src/main/java/org/apache/iceberg/transforms/Bucket.java +++ b/api/src/main/java/org/apache/iceberg/transforms/Bucket.java @@ -55,28 +55,16 @@ static & SerializableFunction> B get( Preconditions.checkArgument( numBuckets > 0, "Invalid number of buckets: %s (must be > 0)", numBuckets); - switch (type.typeId()) { - case DATE: - case INTEGER: - return (B) new BucketInteger(numBuckets); - case TIME: - case TIMESTAMP: - case LONG: - return (B) new BucketLong(numBuckets); - case DECIMAL: - return (B) new BucketDecimal(numBuckets); - case STRING: - return (B) new BucketString(numBuckets); - case FIXED: - case BINARY: - return (B) new BucketByteBuffer(numBuckets); - case TIMESTAMP_NANO: - return (B) new BucketTimestampNano(numBuckets); - case UUID: - return (B) new BucketUUID(numBuckets); - default: - throw new IllegalArgumentException("Cannot bucket by type: " + type); - } + return switch (type.typeId()) { + case DATE, INTEGER -> (B) new BucketInteger(numBuckets); + case TIME, TIMESTAMP, LONG -> (B) new BucketLong(numBuckets); + case DECIMAL -> (B) new BucketDecimal(numBuckets); + case STRING -> (B) new BucketString(numBuckets); + case FIXED, BINARY -> (B) new BucketByteBuffer(numBuckets); + case TIMESTAMP_NANO -> (B) new BucketTimestampNano(numBuckets); + case UUID -> (B) new BucketUUID(numBuckets); + default -> throw new IllegalArgumentException("Cannot bucket by type: " + type); + }; } private final int numBuckets; @@ -118,21 +106,21 @@ public Integer apply(T value) { @Override public boolean canTransform(Type type) { - switch (type.typeId()) { - case INTEGER: - case LONG: - case DATE: - case TIME: - case TIMESTAMP: - case TIMESTAMP_NANO: - case STRING: - case BINARY: - case FIXED: - case DECIMAL: - case UUID: - return true; - } - return false; + return switch (type.typeId()) { + case INTEGER, + LONG, + DATE, + TIME, + TIMESTAMP, + TIMESTAMP_NANO, + STRING, + BINARY, + FIXED, + DECIMAL, + UUID -> + true; + default -> false; + }; } @Override diff --git a/api/src/main/java/org/apache/iceberg/transforms/Dates.java b/api/src/main/java/org/apache/iceberg/transforms/Dates.java index 841e6dfa3a51..50fdcc0ccc23 100644 --- a/api/src/main/java/org/apache/iceberg/transforms/Dates.java +++ b/api/src/main/java/org/apache/iceberg/transforms/Dates.java @@ -50,16 +50,12 @@ public Integer apply(Integer days) { return null; } - switch (granularity) { - case YEARS: - return DateTimeUtil.daysToYears(days); - case MONTHS: - return DateTimeUtil.daysToMonths(days); - case DAYS: - return days; - default: - throw new UnsupportedOperationException("Unsupported time unit: " + granularity); - } + return switch (granularity) { + case YEARS -> DateTimeUtil.daysToYears(days); + case MONTHS -> DateTimeUtil.daysToMonths(days); + case DAYS -> days; + default -> throw new UnsupportedOperationException("Unsupported time unit: " + granularity); + }; } } @@ -199,16 +195,12 @@ public String toHumanString(Type outputType, Integer value) { return "null"; } - switch (granularity) { - case YEARS: - return TransformUtil.humanYear(value); - case MONTHS: - return TransformUtil.humanMonth(value); - case DAYS: - return TransformUtil.humanDay(value); - default: - throw new UnsupportedOperationException("Unsupported time unit: " + granularity); - } + return switch (granularity) { + case YEARS -> TransformUtil.humanYear(value); + case MONTHS -> TransformUtil.humanMonth(value); + case DAYS -> TransformUtil.humanDay(value); + default -> throw new UnsupportedOperationException("Unsupported time unit: " + granularity); + }; } @Override diff --git a/api/src/main/java/org/apache/iceberg/transforms/ProjectionUtil.java b/api/src/main/java/org/apache/iceberg/transforms/ProjectionUtil.java index 679f80a6f2dc..9f13e9b89a0e 100644 --- a/api/src/main/java/org/apache/iceberg/transforms/ProjectionUtil.java +++ b/api/src/main/java/org/apache/iceberg/transforms/ProjectionUtil.java @@ -42,114 +42,92 @@ private ProjectionUtil() {} static UnboundPredicate truncateInteger( String name, BoundLiteralPredicate pred, Function transform) { int boundary = pred.literal().value(); - switch (pred.op()) { - case LT: - // adjust closed and then transform ltEq - return predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary - 1)); - case LT_EQ: - return predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary)); - case GT: - // adjust closed and then transform gtEq - return predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary + 1)); - case GT_EQ: - return predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary)); - case EQ: - return predicate(pred.op(), name, transform.apply(boundary)); - default: - return null; - } + return switch (pred.op()) { + case LT -> + // adjust closed and then transform ltEq + predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary - 1)); + case LT_EQ -> predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary)); + case GT -> + // adjust closed and then transform gtEq + predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary + 1)); + case GT_EQ -> predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary)); + case EQ -> predicate(pred.op(), name, transform.apply(boundary)); + default -> null; + }; } static UnboundPredicate truncateIntegerStrict( String name, BoundLiteralPredicate pred, Function transform) { int boundary = pred.literal().value(); - switch (pred.op()) { - case LT: - return predicate(Expression.Operation.LT, name, transform.apply(boundary)); - case LT_EQ: - return predicate(Expression.Operation.LT, name, transform.apply(boundary + 1)); - case GT: - return predicate(Expression.Operation.GT, name, transform.apply(boundary)); - case GT_EQ: - return predicate(Expression.Operation.GT, name, transform.apply(boundary - 1)); - case NOT_EQ: - return predicate(Expression.Operation.NOT_EQ, name, transform.apply(boundary)); - case EQ: - // there is no predicate that guarantees equality because adjacent ints transform to the - // same value - return null; - default: - return null; - } + return switch (pred.op()) { + case LT -> predicate(Expression.Operation.LT, name, transform.apply(boundary)); + case LT_EQ -> predicate(Expression.Operation.LT, name, transform.apply(boundary + 1)); + case GT -> predicate(Expression.Operation.GT, name, transform.apply(boundary)); + case GT_EQ -> predicate(Expression.Operation.GT, name, transform.apply(boundary - 1)); + case NOT_EQ -> predicate(Expression.Operation.NOT_EQ, name, transform.apply(boundary)); + case EQ -> + // there is no predicate that guarantees equality because adjacent ints transform to the + // same value + null; + default -> null; + }; } static UnboundPredicate truncateLongStrict( String name, BoundLiteralPredicate pred, Function transform) { long boundary = pred.literal().value(); - switch (pred.op()) { - case LT: - return predicate(Expression.Operation.LT, name, transform.apply(boundary)); - case LT_EQ: - return predicate(Expression.Operation.LT, name, transform.apply(boundary + 1L)); - case GT: - return predicate(Expression.Operation.GT, name, transform.apply(boundary)); - case GT_EQ: - return predicate(Expression.Operation.GT, name, transform.apply(boundary - 1L)); - case NOT_EQ: - return predicate(Expression.Operation.NOT_EQ, name, transform.apply(boundary)); - case EQ: - // there is no predicate that guarantees equality because adjacent longs transform to the - // same value - return null; - default: - return null; - } + return switch (pred.op()) { + case LT -> predicate(Expression.Operation.LT, name, transform.apply(boundary)); + case LT_EQ -> predicate(Expression.Operation.LT, name, transform.apply(boundary + 1L)); + case GT -> predicate(Expression.Operation.GT, name, transform.apply(boundary)); + case GT_EQ -> predicate(Expression.Operation.GT, name, transform.apply(boundary - 1L)); + case NOT_EQ -> predicate(Expression.Operation.NOT_EQ, name, transform.apply(boundary)); + case EQ -> + // there is no predicate that guarantees equality because adjacent longs transform to the + // same value + null; + default -> null; + }; } static UnboundPredicate truncateLong( String name, BoundLiteralPredicate pred, Function transform) { long boundary = pred.literal().value(); - switch (pred.op()) { - case LT: - // adjust closed and then transform ltEq - return predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary - 1L)); - case LT_EQ: - return predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary)); - case GT: - // adjust closed and then transform gtEq - return predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary + 1L)); - case GT_EQ: - return predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary)); - case EQ: - return predicate(pred.op(), name, transform.apply(boundary)); - default: - return null; - } + return switch (pred.op()) { + case LT -> + // adjust closed and then transform ltEq + predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary - 1L)); + case LT_EQ -> predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary)); + case GT -> + // adjust closed and then transform gtEq + predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary + 1L)); + case GT_EQ -> predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary)); + case EQ -> predicate(pred.op(), name, transform.apply(boundary)); + default -> null; + }; } static UnboundPredicate truncateDecimal( String name, BoundLiteralPredicate pred, Function transform) { BigDecimal boundary = pred.literal().value(); - switch (pred.op()) { - case LT: + return switch (pred.op()) { + case LT -> { // adjust closed and then transform ltEq BigDecimal minusOne = new BigDecimal(boundary.unscaledValue().subtract(BigInteger.ONE), boundary.scale()); - return predicate(Expression.Operation.LT_EQ, name, transform.apply(minusOne)); - case LT_EQ: - return predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary)); - case GT: + yield predicate(Expression.Operation.LT_EQ, name, transform.apply(minusOne)); + } + case LT_EQ -> predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary)); + case GT -> { // adjust closed and then transform gtEq BigDecimal plusOne = new BigDecimal(boundary.unscaledValue().add(BigInteger.ONE), boundary.scale()); - return predicate(Expression.Operation.GT_EQ, name, transform.apply(plusOne)); - case GT_EQ: - return predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary)); - case EQ: - return predicate(pred.op(), name, transform.apply(boundary)); - default: - return null; - } + yield predicate(Expression.Operation.GT_EQ, name, transform.apply(plusOne)); + } + case GT_EQ -> predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary)); + case EQ -> predicate(pred.op(), name, transform.apply(boundary)); + default -> null; + }; } static UnboundPredicate truncateDecimalStrict( @@ -162,66 +140,49 @@ static UnboundPredicate truncateDecimalStrict( BigDecimal plusOne = new BigDecimal(boundary.unscaledValue().add(BigInteger.ONE), boundary.scale()); - switch (pred.op()) { - case LT: - return predicate(Expression.Operation.LT, name, transform.apply(boundary)); - case LT_EQ: - return predicate(Expression.Operation.LT, name, transform.apply(plusOne)); - case GT: - return predicate(Expression.Operation.GT, name, transform.apply(boundary)); - case GT_EQ: - return predicate(Expression.Operation.GT, name, transform.apply(minusOne)); - case NOT_EQ: - return predicate(Expression.Operation.NOT_EQ, name, transform.apply(boundary)); - case EQ: - // there is no predicate that guarantees equality because adjacent decimals transform to the - // same value - return null; - default: - return null; - } + return switch (pred.op()) { + case LT -> predicate(Expression.Operation.LT, name, transform.apply(boundary)); + case LT_EQ -> predicate(Expression.Operation.LT, name, transform.apply(plusOne)); + case GT -> predicate(Expression.Operation.GT, name, transform.apply(boundary)); + case GT_EQ -> predicate(Expression.Operation.GT, name, transform.apply(minusOne)); + case NOT_EQ -> predicate(Expression.Operation.NOT_EQ, name, transform.apply(boundary)); + case EQ -> + // there is no predicate that guarantees equality because adjacent decimals transform to + // the + // same value + null; + default -> null; + }; } static UnboundPredicate truncateArray( String name, BoundLiteralPredicate pred, Function transform) { S boundary = pred.literal().value(); - switch (pred.op()) { - case LT: - case LT_EQ: - return predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary)); - case GT: - case GT_EQ: - return predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary)); - case EQ: - return predicate(Expression.Operation.EQ, name, transform.apply(boundary)); - case STARTS_WITH: - return predicate(Expression.Operation.STARTS_WITH, name, transform.apply(boundary)); + return switch (pred.op()) { + case LT, LT_EQ -> predicate(Expression.Operation.LT_EQ, name, transform.apply(boundary)); + case GT, GT_EQ -> predicate(Expression.Operation.GT_EQ, name, transform.apply(boundary)); + case EQ -> predicate(Expression.Operation.EQ, name, transform.apply(boundary)); + case STARTS_WITH -> + predicate(Expression.Operation.STARTS_WITH, name, transform.apply(boundary)); // case IN: // TODO // return Expressions.predicate(Operation.IN, name, transform.apply(boundary)); - default: - return null; - } + default -> null; + }; } static UnboundPredicate truncateArrayStrict( String name, BoundLiteralPredicate pred, Function transform) { S boundary = pred.literal().value(); - switch (pred.op()) { - case LT: - case LT_EQ: - return predicate(Expression.Operation.LT, name, transform.apply(boundary)); - case GT: - case GT_EQ: - return predicate(Expression.Operation.GT, name, transform.apply(boundary)); - case NOT_EQ: - return predicate(Expression.Operation.NOT_EQ, name, transform.apply(boundary)); - case EQ: - // there is no predicate that guarantees equality because adjacent values transform to the - // same partition - return null; - default: - return null; - } + return switch (pred.op()) { + case LT, LT_EQ -> predicate(Expression.Operation.LT, name, transform.apply(boundary)); + case GT, GT_EQ -> predicate(Expression.Operation.GT, name, transform.apply(boundary)); + case NOT_EQ -> predicate(Expression.Operation.NOT_EQ, name, transform.apply(boundary)); + case EQ -> + // there is no predicate that guarantees equality because adjacent values transform to the + // same partition + null; + default -> null; + }; } /** @@ -278,37 +239,35 @@ static UnboundPredicate fixInclusiveTimeProjection(UnboundPredicate { if (projected.literal().value() < 0) { - return Expressions.lessThan(projected.term(), projected.literal().value() + 1); + yield Expressions.lessThan(projected.term(), projected.literal().value() + 1); } - return projected; - - case LT_EQ: + yield projected; + } + case LT_EQ -> { if (projected.literal().value() < 0) { - return Expressions.lessThanOrEqual(projected.term(), projected.literal().value() + 1); + yield Expressions.lessThanOrEqual(projected.term(), projected.literal().value() + 1); } - return projected; - - case GT: - case GT_EQ: - // incorrect projected values are already greater than the bound for GT, GT_EQ - return projected; - - case EQ: + yield projected; + } + case GT, GT_EQ -> + // incorrect projected values are already greater than the bound for GT, GT_EQ + projected; + case EQ -> { if (projected.literal().value() < 0) { // match either the incorrect value (projectedValue + 1) or the correct value // (projectedValue) - return Expressions.in( + yield Expressions.in( projected.term(), projected.literal().value(), projected.literal().value() + 1); } - return projected; - - case IN: + yield projected; + } + case IN -> { Set fixedSet = Sets.newHashSet(); boolean hasNegativeValue = false; for (Literal lit : projected.literals()) { @@ -321,19 +280,16 @@ static UnboundPredicate fixInclusiveTimeProjection(UnboundPredicate + // there is no inclusive projection for NOT_EQ and NOT_IN + null; + default -> projected; + }; } /** @@ -349,13 +305,12 @@ static UnboundPredicate fixStrictTimeProjection(UnboundPredicate + // the correct bound is a correct strict projection for the incorrectly transformed + // values. + projected; + case GT -> { // GT and GT_EQ need to be adjusted because values that do not match the predicate may have // been transformed // into partition values that match the projected predicate. For example, >= @@ -363,32 +318,30 @@ static UnboundPredicate fixStrictTimeProjection(UnboundPredicate { if (projected.literal().value() <= 0) { - return Expressions.greaterThanOrEqual(projected.term(), projected.literal().value() + 1); + yield Expressions.greaterThanOrEqual(projected.term(), projected.literal().value() + 1); } - return projected; - - case EQ: - case IN: - // there is no strict projection for EQ and IN - return null; - - case NOT_EQ: + yield projected; + } + case EQ, IN -> + // there is no strict projection for EQ and IN + null; + case NOT_EQ -> { if (projected.literal().value() < 0) { - return Expressions.notIn( + yield Expressions.notIn( projected.term(), projected.literal().value(), projected.literal().value() + 1); } - return projected; - - case NOT_IN: + yield projected; + } + case NOT_IN -> { Set fixedSet = Sets.newHashSet(); boolean hasNegativeValue = false; for (Literal lit : projected.literals()) { @@ -401,13 +354,12 @@ static UnboundPredicate fixStrictTimeProjection(UnboundPredicate null; + }; } } diff --git a/api/src/main/java/org/apache/iceberg/transforms/TimeTransform.java b/api/src/main/java/org/apache/iceberg/transforms/TimeTransform.java index c348fda52b02..e1f0bb72baf0 100644 --- a/api/src/main/java/org/apache/iceberg/transforms/TimeTransform.java +++ b/api/src/main/java/org/apache/iceberg/transforms/TimeTransform.java @@ -27,19 +27,18 @@ abstract class TimeTransform implements Transform { protected static R fromSourceType(Type type, R dateResult, R microsResult, R nanosResult) { - switch (type.typeId()) { - case DATE: + return switch (type.typeId()) { + case DATE -> { if (dateResult != null) { - return dateResult; + yield dateResult; } - break; - case TIMESTAMP: - return microsResult; - case TIMESTAMP_NANO: - return nanosResult; - } - throw new IllegalArgumentException("Unsupported type: " + type); + throw new IllegalArgumentException("Unsupported type: " + type); + } + case TIMESTAMP -> microsResult; + case TIMESTAMP_NANO -> nanosResult; + default -> throw new IllegalArgumentException("Unsupported type: " + type); + }; } protected abstract ChronoUnit granularity(); diff --git a/api/src/main/java/org/apache/iceberg/transforms/Timestamps.java b/api/src/main/java/org/apache/iceberg/transforms/Timestamps.java index 845725219438..f77c46f6cee2 100644 --- a/api/src/main/java/org/apache/iceberg/transforms/Timestamps.java +++ b/api/src/main/java/org/apache/iceberg/transforms/Timestamps.java @@ -63,36 +63,28 @@ public Integer apply(Long timestamp) { return null; } - switch (timestampUnit) { - case MICROS: - switch (granularity) { - case YEARS: - return DateTimeUtil.microsToYears(timestamp); - case MONTHS: - return DateTimeUtil.microsToMonths(timestamp); - case DAYS: - return DateTimeUtil.microsToDays(timestamp); - case HOURS: - return DateTimeUtil.microsToHours(timestamp); - default: - throw new UnsupportedOperationException("Unsupported time unit: " + granularity); - } - case NANOS: - switch (granularity) { - case YEARS: - return DateTimeUtil.nanosToYears(timestamp); - case MONTHS: - return DateTimeUtil.nanosToMonths(timestamp); - case DAYS: - return DateTimeUtil.nanosToDays(timestamp); - case HOURS: - return DateTimeUtil.nanosToHours(timestamp); - default: - throw new UnsupportedOperationException("Unsupported time unit: " + granularity); - } - default: - throw new UnsupportedOperationException("Unsupported time unit: " + timestampUnit); - } + return switch (timestampUnit) { + case MICROS -> + switch (granularity) { + case YEARS -> DateTimeUtil.microsToYears(timestamp); + case MONTHS -> DateTimeUtil.microsToMonths(timestamp); + case DAYS -> DateTimeUtil.microsToDays(timestamp); + case HOURS -> DateTimeUtil.microsToHours(timestamp); + default -> + throw new UnsupportedOperationException("Unsupported time unit: " + granularity); + }; + case NANOS -> + switch (granularity) { + case YEARS -> DateTimeUtil.nanosToYears(timestamp); + case MONTHS -> DateTimeUtil.nanosToMonths(timestamp); + case DAYS -> DateTimeUtil.nanosToDays(timestamp); + case HOURS -> DateTimeUtil.nanosToHours(timestamp); + default -> + throw new UnsupportedOperationException("Unsupported time unit: " + granularity); + }; + default -> + throw new UnsupportedOperationException("Unsupported time unit: " + timestampUnit); + }; } } @@ -216,18 +208,13 @@ public String toHumanString(Type outputType, Integer value) { return "null"; } - switch (granularity) { - case YEARS: - return TransformUtil.humanYear(value); - case MONTHS: - return TransformUtil.humanMonth(value); - case DAYS: - return TransformUtil.humanDay(value); - case HOURS: - return TransformUtil.humanHour(value); - default: - throw new UnsupportedOperationException("Unsupported time unit: " + granularity); - } + return switch (granularity) { + case YEARS -> TransformUtil.humanYear(value); + case MONTHS -> TransformUtil.humanMonth(value); + case DAYS -> TransformUtil.humanDay(value); + case HOURS -> TransformUtil.humanHour(value); + default -> throw new UnsupportedOperationException("Unsupported time unit: " + granularity); + }; } @Override diff --git a/api/src/main/java/org/apache/iceberg/transforms/Transform.java b/api/src/main/java/org/apache/iceberg/transforms/Transform.java index 78312b58b12f..d00316a86b1d 100644 --- a/api/src/main/java/org/apache/iceberg/transforms/Transform.java +++ b/api/src/main/java/org/apache/iceberg/transforms/Transform.java @@ -170,35 +170,28 @@ default String toHumanString(Type type, T value) { return "null"; } - switch (type.typeId()) { - case DATE: - return TransformUtil.humanDay((Integer) value); - case TIME: - return TransformUtil.humanTime((Long) value); - case TIMESTAMP: - if (((Types.TimestampType) type).shouldAdjustToUTC()) { - return TransformUtil.humanTimestampWithZone((Long) value); - } else { - return TransformUtil.humanTimestampWithoutZone((Long) value); - } - case TIMESTAMP_NANO: - if (((Types.TimestampNanoType) type).shouldAdjustToUTC()) { - return TransformUtil.humanTimestampNanoWithZone((Long) value); - } else { - return TransformUtil.humanTimestampNanoWithoutZone((Long) value); - } - case FIXED: - case BINARY: + return switch (type.typeId()) { + case DATE -> TransformUtil.humanDay((Integer) value); + case TIME -> TransformUtil.humanTime((Long) value); + case TIMESTAMP -> + ((Types.TimestampType) type).shouldAdjustToUTC() + ? TransformUtil.humanTimestampWithZone((Long) value) + : TransformUtil.humanTimestampWithoutZone((Long) value); + case TIMESTAMP_NANO -> + ((Types.TimestampNanoType) type).shouldAdjustToUTC() + ? TransformUtil.humanTimestampNanoWithZone((Long) value) + : TransformUtil.humanTimestampNanoWithoutZone((Long) value); + case FIXED, BINARY -> { if (value instanceof ByteBuffer) { - return TransformUtil.base64encode(((ByteBuffer) value).duplicate()); + yield TransformUtil.base64encode(((ByteBuffer) value).duplicate()); } else if (value instanceof byte[]) { - return TransformUtil.base64encode(ByteBuffer.wrap((byte[]) value)); + yield TransformUtil.base64encode(ByteBuffer.wrap((byte[]) value)); } else { throw new UnsupportedOperationException("Unsupported binary type: " + value.getClass()); } - default: - return value.toString(); - } + } + default -> value.toString(); + }; } /** diff --git a/api/src/main/java/org/apache/iceberg/transforms/Transforms.java b/api/src/main/java/org/apache/iceberg/transforms/Transforms.java index d204e1719fa9..95808269e409 100644 --- a/api/src/main/java/org/apache/iceberg/transforms/Transforms.java +++ b/api/src/main/java/org/apache/iceberg/transforms/Transforms.java @@ -84,22 +84,15 @@ private Transforms() {} } String lowerTransform = transform.toLowerCase(Locale.ROOT); - switch (lowerTransform) { - case "identity": - return Identity.get(type); - case "year": - return Years.get().toEnum(type); - case "month": - return Months.get().toEnum(type); - case "day": - return Days.get().toEnum(type); - case "hour": - return Hours.get().toEnum(type); - case "void": - return VoidTransform.get(); - } - - return new UnknownTransform<>(transform); + return switch (lowerTransform) { + case "identity" -> Identity.get(type); + case "year" -> Years.get().toEnum(type); + case "month" -> Months.get().toEnum(type); + case "day" -> Days.get().toEnum(type); + case "hour" -> Hours.get().toEnum(type); + case "void" -> VoidTransform.get(); + default -> new UnknownTransform<>(transform); + }; } /** diff --git a/api/src/main/java/org/apache/iceberg/transforms/Truncate.java b/api/src/main/java/org/apache/iceberg/transforms/Truncate.java index a111e4ca394b..6ae129597416 100644 --- a/api/src/main/java/org/apache/iceberg/transforms/Truncate.java +++ b/api/src/main/java/org/apache/iceberg/transforms/Truncate.java @@ -51,20 +51,14 @@ static Truncate get(int width) { static & SerializableFunction> R get(Type type, int width) { Preconditions.checkArgument(width > 0, "Invalid truncate width: %s (must be > 0)", width); - switch (type.typeId()) { - case INTEGER: - return (R) new TruncateInteger(width); - case LONG: - return (R) new TruncateLong(width); - case DECIMAL: - return (R) new TruncateDecimal(width); - case STRING: - return (R) new TruncateString(width); - case BINARY: - return (R) new TruncateByteBuffer(width); - default: - throw new UnsupportedOperationException("Cannot truncate type: " + type); - } + return switch (type.typeId()) { + case INTEGER -> (R) new TruncateInteger(width); + case LONG -> (R) new TruncateLong(width); + case DECIMAL -> (R) new TruncateDecimal(width); + case STRING -> (R) new TruncateString(width); + case BINARY -> (R) new TruncateByteBuffer(width); + default -> throw new UnsupportedOperationException("Cannot truncate type: " + type); + }; } @SuppressWarnings("checkstyle:VisibilityModifier") @@ -92,15 +86,10 @@ public SerializableFunction bind(Type type) { @Override public boolean canTransform(Type type) { - switch (type.typeId()) { - case INTEGER: - case LONG: - case STRING: - case BINARY: - case DECIMAL: - return true; - } - return false; + return switch (type.typeId()) { + case INTEGER, LONG, STRING, BINARY, DECIMAL -> true; + default -> false; + }; } @Override @@ -326,28 +315,27 @@ public UnboundPredicate project( return Expressions.predicate(predicate.op(), name); } else if (predicate.isLiteralPredicate()) { BoundLiteralPredicate pred = predicate.asLiteralPredicate(); - switch (pred.op()) { - case STARTS_WITH: + return switch (pred.op()) { + case STARTS_WITH -> { if (pred.literal().value().length() < width()) { - return Expressions.predicate(pred.op(), name, pred.literal().value()); + yield Expressions.predicate(pred.op(), name, pred.literal().value()); } else if (pred.literal().value().length() == width()) { - return Expressions.equal(name, pred.literal().value()); + yield Expressions.equal(name, pred.literal().value()); } - return ProjectionUtil.truncateArray(name, pred, this); - - case NOT_STARTS_WITH: + yield ProjectionUtil.truncateArray(name, pred, this); + } + case NOT_STARTS_WITH -> { if (pred.literal().value().length() < width()) { - return Expressions.predicate(pred.op(), name, pred.literal().value()); + yield Expressions.predicate(pred.op(), name, pred.literal().value()); } else if (pred.literal().value().length() == width()) { - return Expressions.notEqual(name, pred.literal().value()); + yield Expressions.notEqual(name, pred.literal().value()); } - return null; - - default: - return ProjectionUtil.truncateArray(name, pred, this); - } + yield null; + } + default -> ProjectionUtil.truncateArray(name, pred, this); + }; } else if (predicate.isSetPredicate() && predicate.op() == Expression.Operation.IN) { return ProjectionUtil.transformSet(name, predicate.asSetPredicate(), this); } @@ -365,28 +353,27 @@ public UnboundPredicate projectStrict( return Expressions.predicate(predicate.op(), name); } else if (predicate instanceof BoundLiteralPredicate) { BoundLiteralPredicate pred = predicate.asLiteralPredicate(); - switch (pred.op()) { - case STARTS_WITH: + return switch (pred.op()) { + case STARTS_WITH -> { if (pred.literal().value().length() < width()) { - return Expressions.predicate(pred.op(), name, pred.literal().value()); + yield Expressions.predicate(pred.op(), name, pred.literal().value()); } else if (pred.literal().value().length() == width()) { - return Expressions.equal(name, pred.literal().value()); + yield Expressions.equal(name, pred.literal().value()); } - return null; - - case NOT_STARTS_WITH: + yield null; + } + case NOT_STARTS_WITH -> { if (pred.literal().value().length() < width()) { - return Expressions.predicate(pred.op(), name, pred.literal().value()); + yield Expressions.predicate(pred.op(), name, pred.literal().value()); } else if (pred.literal().value().length() == width()) { - return Expressions.notEqual(name, pred.literal().value()); + yield Expressions.notEqual(name, pred.literal().value()); } - return Expressions.predicate(pred.op(), name, apply(pred.literal().value()).toString()); - - default: - return ProjectionUtil.truncateArrayStrict(name, pred, this); - } + yield Expressions.predicate(pred.op(), name, apply(pred.literal().value()).toString()); + } + default -> ProjectionUtil.truncateArrayStrict(name, pred, this); + }; } else if (predicate.isSetPredicate() && predicate.op() == Expression.Operation.NOT_IN) { return ProjectionUtil.transformSet(name, predicate.asSetPredicate(), this); } diff --git a/api/src/main/java/org/apache/iceberg/types/Conversions.java b/api/src/main/java/org/apache/iceberg/types/Conversions.java index 1ebf60c86890..1d865f2aea38 100644 --- a/api/src/main/java/org/apache/iceberg/types/Conversions.java +++ b/api/src/main/java/org/apache/iceberg/types/Conversions.java @@ -48,34 +48,25 @@ public static Object fromPartitionString(Type type, String asString) { return null; } - switch (type.typeId()) { - case BOOLEAN: - return Boolean.valueOf(asString); - case INTEGER: - return Integer.valueOf(asString); - case LONG: - return Long.valueOf(asString); - case FLOAT: - return Float.valueOf(asString); - case DOUBLE: - return Double.valueOf(asString); - case STRING: - return asString; - case UUID: - return UUID.fromString(asString); - case FIXED: + return switch (type.typeId()) { + case BOOLEAN -> Boolean.valueOf(asString); + case INTEGER -> Integer.valueOf(asString); + case LONG -> Long.valueOf(asString); + case FLOAT -> Float.valueOf(asString); + case DOUBLE -> Double.valueOf(asString); + case STRING -> asString; + case UUID -> UUID.fromString(asString); + case FIXED -> { Types.FixedType fixed = (Types.FixedType) type; - return Arrays.copyOf(asString.getBytes(StandardCharsets.UTF_8), fixed.length()); - case BINARY: - return asString.getBytes(StandardCharsets.UTF_8); - case DECIMAL: - return new BigDecimal(asString); - case DATE: - return Literal.of(asString).to(Types.DateType.get()).value(); - default: - throw new UnsupportedOperationException( - "Unsupported type for fromPartitionString: " + type); - } + yield Arrays.copyOf(asString.getBytes(StandardCharsets.UTF_8), fixed.length()); + } + case BINARY -> asString.getBytes(StandardCharsets.UTF_8); + case DECIMAL -> new BigDecimal(asString); + case DATE -> Literal.of(asString).to(Types.DateType.get()).value(); + default -> + throw new UnsupportedOperationException( + "Unsupported type for fromPartitionString: " + type); + }; } private static final ThreadLocal ENCODER = @@ -92,36 +83,28 @@ public static ByteBuffer toByteBuffer(Type.TypeID typeId, Object value) { return null; } - switch (typeId) { - case BOOLEAN: - return ByteBuffer.allocate(1).put(0, (Boolean) value ? (byte) 0x01 : (byte) 0x00); - case INTEGER: - case DATE: - return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(0, (int) value); - case LONG: - case TIME: - case TIMESTAMP: - case TIMESTAMP_NANO: - return ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(0, (long) value); - case FLOAT: - return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putFloat(0, (float) value); - case DOUBLE: - return ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putDouble(0, (double) value); - case STRING: + return switch (typeId) { + case BOOLEAN -> ByteBuffer.allocate(1).put(0, (Boolean) value ? (byte) 0x01 : (byte) 0x00); + case INTEGER, DATE -> + ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(0, (int) value); + case LONG, TIME, TIMESTAMP, TIMESTAMP_NANO -> + ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(0, (long) value); + case FLOAT -> + ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putFloat(0, (float) value); + case DOUBLE -> + ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putDouble(0, (double) value); + case STRING -> { CharBuffer buffer = CharBuffer.wrap((CharSequence) value); try { - return ENCODER.get().encode(buffer); + yield ENCODER.get().encode(buffer); } catch (CharacterCodingException e) { throw new RuntimeIOException(e, "Failed to encode value as UTF-8: %s", value); } - case UUID: - return UUIDUtil.convertToByteBuffer((UUID) value); - case FIXED: - case BINARY: - return (ByteBuffer) value; - case DECIMAL: - return ByteBuffer.wrap(((BigDecimal) value).unscaledValue().toByteArray()); - case VARIANT: + } + case UUID -> UUIDUtil.convertToByteBuffer((UUID) value); + case FIXED, BINARY -> (ByteBuffer) value; + case DECIMAL -> ByteBuffer.wrap(((BigDecimal) value).unscaledValue().toByteArray()); + case VARIANT -> { // Produce a concatenated buffer of metadata and value Variant variant = (Variant) value; VariantMetadata variantMetadata = variant.metadata(); @@ -131,19 +114,16 @@ public static ByteBuffer toByteBuffer(Type.TypeID typeId, Object value) { .order(ByteOrder.LITTLE_ENDIAN); variantMetadata.writeTo(variantBuffer, 0); variantValue.writeTo(variantBuffer, variantMetadata.sizeInBytes()); - return variantBuffer; - case GEOMETRY: - case GEOGRAPHY: + yield variantBuffer; + } // Geometry and geography lower/upper bounds are single points encoded as an // x:y:z:m concatenation of 8-byte little-endian IEEE 754 doubles. See the // Bound Serialization section of the Iceberg spec. - return ((GeospatialBound) value).toByteBuffer(); - case UNKNOWN: + case GEOMETRY, GEOGRAPHY -> ((GeospatialBound) value).toByteBuffer(); // underlying type not known - return null; - default: - throw new UnsupportedOperationException("Cannot serialize type: " + typeId); - } + case UNKNOWN -> null; + default -> throw new UnsupportedOperationException("Cannot serialize type: " + typeId); + }; } @SuppressWarnings("unchecked") @@ -162,55 +142,44 @@ private static Object internalFromByteBuffer(Type type, ByteBuffer buffer) { } else { tmp.order(ByteOrder.LITTLE_ENDIAN); } - switch (type.typeId()) { - case BOOLEAN: - return tmp.get() != 0x00; - case INTEGER: - case DATE: - return tmp.getInt(); - case LONG: - case TIME: - case TIMESTAMP: - case TIMESTAMP_NANO: + return switch (type.typeId()) { + case BOOLEAN -> tmp.get() != 0x00; + case INTEGER, DATE -> tmp.getInt(); + case LONG, TIME, TIMESTAMP, TIMESTAMP_NANO -> { if (tmp.remaining() < 8) { // type was later promoted to long - return (long) tmp.getInt(); + yield (long) tmp.getInt(); } - return tmp.getLong(); - case FLOAT: - return tmp.getFloat(); - case DOUBLE: + yield tmp.getLong(); + } + case FLOAT -> tmp.getFloat(); + case DOUBLE -> { if (tmp.remaining() < 8) { // type was later promoted to long - return (double) tmp.getFloat(); + yield (double) tmp.getFloat(); } - return tmp.getDouble(); - case STRING: + yield tmp.getDouble(); + } + case STRING -> { try { - return DECODER.get().decode(tmp); + yield DECODER.get().decode(tmp); } catch (CharacterCodingException e) { throw new RuntimeIOException(e, "Failed to decode value as UTF-8: %s", buffer); } - case UUID: - return UUIDUtil.convert(tmp); - case FIXED: - case BINARY: - return tmp; - case DECIMAL: + } + case UUID -> UUIDUtil.convert(tmp); + case FIXED, BINARY -> tmp; + case DECIMAL -> { Types.DecimalType decimal = (Types.DecimalType) type; byte[] unscaledBytes = new byte[buffer.remaining()]; tmp.get(unscaledBytes); - return new BigDecimal(new BigInteger(unscaledBytes), decimal.scale()); - case VARIANT: - return Variant.from(tmp); - case GEOMETRY: - case GEOGRAPHY: - return GeospatialBound.fromByteBuffer(tmp); - case UNKNOWN: + yield new BigDecimal(new BigInteger(unscaledBytes), decimal.scale()); + } + case VARIANT -> Variant.from(tmp); + case GEOMETRY, GEOGRAPHY -> GeospatialBound.fromByteBuffer(tmp); // underlying type not known - return null; - default: - throw new UnsupportedOperationException("Cannot deserialize type: " + type); - } + case UNKNOWN -> null; + default -> throw new UnsupportedOperationException("Cannot deserialize type: " + type); + }; } } diff --git a/api/src/main/java/org/apache/iceberg/types/JavaHash.java b/api/src/main/java/org/apache/iceberg/types/JavaHash.java index 1988a90322e4..b5e3f38179c2 100644 --- a/api/src/main/java/org/apache/iceberg/types/JavaHash.java +++ b/api/src/main/java/org/apache/iceberg/types/JavaHash.java @@ -26,15 +26,11 @@ public interface JavaHash { @SuppressWarnings("unchecked") static JavaHash forType(Type type) { - switch (type.typeId()) { - case STRING: - return (JavaHash) JavaHashes.strings(); - case STRUCT: - return (JavaHash) JavaHashes.struct(type.asStructType()); - case LIST: - return (JavaHash) JavaHashes.list(type.asListType()); - default: - return Objects::hashCode; - } + return switch (type.typeId()) { + case STRING -> (JavaHash) JavaHashes.strings(); + case STRUCT -> (JavaHash) JavaHashes.struct(type.asStructType()); + case LIST -> (JavaHash) JavaHashes.list(type.asListType()); + default -> Objects::hashCode; + }; } } diff --git a/api/src/main/java/org/apache/iceberg/types/TypeUtil.java b/api/src/main/java/org/apache/iceberg/types/TypeUtil.java index 8e39ae7a43bc..4b536720025a 100644 --- a/api/src/main/java/org/apache/iceberg/types/TypeUtil.java +++ b/api/src/main/java/org/apache/iceberg/types/TypeUtil.java @@ -475,25 +475,21 @@ public static boolean isPromotionAllowed(Type from, Type.PrimitiveType to) { return true; } - switch (from.typeId()) { - case INTEGER: - return to.typeId() == Type.TypeID.LONG; - - case FLOAT: - return to.typeId() == Type.TypeID.DOUBLE; - - case DECIMAL: + return switch (from.typeId()) { + case INTEGER -> to.typeId() == Type.TypeID.LONG; + case FLOAT -> to.typeId() == Type.TypeID.DOUBLE; + case DECIMAL -> { Types.DecimalType fromDecimal = (Types.DecimalType) from; if (to.typeId() != Type.TypeID.DECIMAL) { - return false; + yield false; } Types.DecimalType toDecimal = (Types.DecimalType) to; - return fromDecimal.scale() == toDecimal.scale() + yield fromDecimal.scale() == toDecimal.scale() && fromDecimal.precision() <= toDecimal.precision(); - } - - return false; + } + default -> false; + }; } /** @@ -579,61 +575,45 @@ public static int estimateSize(Types.NestedField field) { } private static int estimateSize(Type type) { - switch (type.typeId()) { - case BOOLEAN: + return switch (type.typeId()) { // the size of a boolean variable is virtual machine dependent // it is common to believe booleans occupy 1 byte in most JVMs - return 1; - case INTEGER: - case FLOAT: - case DATE: + case BOOLEAN -> 1; // ints and floats occupy 4 bytes // dates are internally represented as ints - return 4; - case LONG: - case DOUBLE: - case TIME: - case TIMESTAMP: - case TIMESTAMP_NANO: + case INTEGER, FLOAT, DATE -> 4; // longs and doubles occupy 8 bytes // times and timestamps are internally represented as longs - return 8; - case STRING: + case LONG, DOUBLE, TIME, TIMESTAMP, TIMESTAMP_NANO -> 8; // 12 (header) + 6 (fields) + 16 (array overhead) + 20 (10 chars, 2 bytes each) = 54 bytes - return 54; - case UUID: + case STRING -> 54; // 12 (header) + 16 (two long variables) = 28 bytes - return 28; - case FIXED: - return ((Types.FixedType) type).length(); - case BINARY: - case VARIANT: - return 80; - case GEOMETRY: - case GEOGRAPHY: + case UUID -> 28; + case FIXED -> ((Types.FixedType) type).length(); + case BINARY, VARIANT -> 80; // 80 bytes is an approximate size for a polygon or linestring with 4 to 5 coordinates. // This is a reasonable estimate for the size of a geometry or geography object without // additional details. - return 80; - case UNKNOWN: + case GEOMETRY, GEOGRAPHY -> 80; // Consider Unknown as null - return 0; - case DECIMAL: + case UNKNOWN -> 0; // 12 (header) + (12 + 12 + 4) (BigInteger) + 4 (scale) = 44 bytes - return 44; - case STRUCT: + case DECIMAL -> 44; + case STRUCT -> { Types.StructType struct = (Types.StructType) type; - return HEADER_SIZE + struct.fields().stream().mapToInt(TypeUtil::estimateSize).sum(); - case LIST: + yield HEADER_SIZE + struct.fields().stream().mapToInt(TypeUtil::estimateSize).sum(); + } + case LIST -> { Types.ListType list = (Types.ListType) type; - return HEADER_SIZE + 5 * estimateSize(list.elementType()); - case MAP: + yield HEADER_SIZE + 5 * estimateSize(list.elementType()); + } + case MAP -> { Types.MapType map = (Types.MapType) type; int entrySize = HEADER_SIZE + estimateSize(map.keyType()) + estimateSize(map.valueType()); - return HEADER_SIZE + 5 * entrySize; - default: - return 16; - } + yield HEADER_SIZE + 5 * entrySize; + } + default -> 16; + }; } /** Interface for passing a function that assigns column IDs. */ @@ -763,8 +743,8 @@ public static T visit(Schema schema, SchemaVisitor visitor) { } public static T visit(Type type, SchemaVisitor visitor) { - switch (type.typeId()) { - case STRUCT: + return switch (type.typeId()) { + case STRUCT -> { Types.StructType struct = type.asNestedType().asStructType(); List results = Lists.newArrayListWithExpectedSize(struct.fields().size()); for (Types.NestedField field : struct.fields()) { @@ -777,9 +757,9 @@ public static T visit(Type type, SchemaVisitor visitor) { } results.add(visitor.field(field, result)); } - return visitor.struct(struct, results); - - case LIST: + yield visitor.struct(struct, results); + } + case LIST -> { Types.ListType list = type.asNestedType().asListType(); T elementResult; @@ -791,9 +771,9 @@ public static T visit(Type type, SchemaVisitor visitor) { visitor.afterListElement(elementField); } - return visitor.list(list, elementResult); - - case MAP: + yield visitor.list(list, elementResult); + } + case MAP -> { Types.MapType map = type.asNestedType().asMapType(); T keyResult; T valueResult; @@ -814,14 +794,11 @@ public static T visit(Type type, SchemaVisitor visitor) { visitor.afterMapValue(valueField); } - return visitor.map(map, keyResult, valueResult); - - case VARIANT: - return visitor.variant(type.asVariantType()); - - default: - return visitor.primitive(type.asPrimitiveType()); - } + yield visitor.map(map, keyResult, valueResult); + } + case VARIANT -> visitor.variant(type.asVariantType()); + default -> visitor.primitive(type.asPrimitiveType()); + }; } public static class CustomOrderSchemaVisitor { @@ -903,8 +880,8 @@ public static T visit(Schema schema, CustomOrderSchemaVisitor visitor) { * @return the result of traversing the given type with the visitor */ public static T visit(Type type, CustomOrderSchemaVisitor visitor) { - switch (type.typeId()) { - case STRUCT: + return switch (type.typeId()) { + case STRUCT -> { Types.StructType struct = type.asNestedType().asStructType(); List> results = Lists.newArrayListWithExpectedSize(struct.fields().size()); @@ -912,25 +889,22 @@ public static T visit(Type type, CustomOrderSchemaVisitor visitor) { results.add(new VisitFieldFuture<>(field, visitor)); } - return visitor.struct(struct, Iterables.transform(results, VisitFieldFuture::get)); - - case LIST: + yield visitor.struct(struct, Iterables.transform(results, VisitFieldFuture::get)); + } + case LIST -> { Types.ListType list = type.asNestedType().asListType(); - return visitor.list(list, new VisitFuture<>(list.elementType(), visitor)); - - case MAP: + yield visitor.list(list, new VisitFuture<>(list.elementType(), visitor)); + } + case MAP -> { Types.MapType map = type.asNestedType().asMapType(); - return visitor.map( + yield visitor.map( map, new VisitFuture<>(map.keyType(), visitor), new VisitFuture<>(map.valueType(), visitor)); - - case VARIANT: - return visitor.variant(type.asVariantType()); - - default: - return visitor.primitive(type.asPrimitiveType()); - } + } + case VARIANT -> visitor.variant(type.asVariantType()); + default -> visitor.primitive(type.asPrimitiveType()); + }; } static int decimalMaxPrecision(int numBytes) { diff --git a/api/src/main/java/org/apache/iceberg/util/ByteBuffers.java b/api/src/main/java/org/apache/iceberg/util/ByteBuffers.java index ac8bcc2432ca..1117f4ec016f 100644 --- a/api/src/main/java/org/apache/iceberg/util/ByteBuffers.java +++ b/api/src/main/java/org/apache/iceberg/util/ByteBuffers.java @@ -82,22 +82,15 @@ public static void writeByte(ByteBuffer buffer, int value, int offset) { public static void writeLittleEndianUnsigned(ByteBuffer buffer, int value, int offset, int size) { int base = buffer.position() + offset; switch (size) { - case 4: - buffer.putInt(base, value); - return; - case 3: + case 4 -> buffer.putInt(base, value); + case 3 -> { buffer.putShort(base, (short) (value & 0xFFFF)); buffer.put(base + 2, (byte) ((value >> 16) & 0xFF)); - return; - case 2: - buffer.putShort(base, (short) (value & 0xFFFF)); - return; - case 1: - buffer.put(base, (byte) (value & 0xFF)); - return; + } + case 2 -> buffer.putShort(base, (short) (value & 0xFFFF)); + case 1 -> buffer.put(base, (byte) (value & 0xFF)); + default -> throw new IllegalArgumentException("Invalid size: " + size); } - - throw new IllegalArgumentException("Invalid size: " + size); } public static byte readLittleEndianInt8(ByteBuffer buffer, int offset) { @@ -114,18 +107,13 @@ public static int readByte(ByteBuffer buffer, int offset) { public static int readLittleEndianUnsigned(ByteBuffer buffer, int offset, int size) { int base = buffer.position() + offset; - switch (size) { - case 4: - return buffer.getInt(base); - case 3: - return (((int) buffer.getShort(base)) & 0xFFFF) | ((buffer.get(base + 2) & 0xFF) << 16); - case 2: - return ((int) buffer.getShort(base)) & 0xFFFF; - case 1: - return buffer.get(base) & 0xFF; - } - - throw new IllegalArgumentException("Invalid size: " + size); + return switch (size) { + case 4 -> buffer.getInt(base); + case 3 -> (((int) buffer.getShort(base)) & 0xFFFF) | ((buffer.get(base + 2) & 0xFF) << 16); + case 2 -> ((int) buffer.getShort(base)) & 0xFFFF; + case 1 -> buffer.get(base) & 0xFF; + default -> throw new IllegalArgumentException("Invalid size: " + size); + }; } public static int readLittleEndianInt32(ByteBuffer buffer, int offset) { diff --git a/api/src/main/java/org/apache/iceberg/util/StructProjection.java b/api/src/main/java/org/apache/iceberg/util/StructProjection.java index 9db90a061cab..fb66d0af9103 100644 --- a/api/src/main/java/org/apache/iceberg/util/StructProjection.java +++ b/api/src/main/java/org/apache/iceberg/util/StructProjection.java @@ -120,14 +120,13 @@ private StructProjection(StructType structType, StructType projection, boolean a found = true; positionMap[pos] = i; switch (projectedField.type().typeId()) { - case STRUCT: - nestedProjections[pos] = - new StructProjection( - dataField.type().asStructType(), - projectedField.type().asStructType(), - allowMissing); - break; - case MAP: + case STRUCT -> + nestedProjections[pos] = + new StructProjection( + dataField.type().asStructType(), + projectedField.type().asStructType(), + allowMissing); + case MAP -> { MapType projectedMap = projectedField.type().asMapType(); MapType originalMap = dataField.type().asMapType(); @@ -144,8 +143,8 @@ private StructProjection(StructType structType, StructType projection, boolean a dataField); nestedProjections[pos] = null; - break; - case LIST: + } + case LIST -> { ListType projectedList = projectedField.type().asListType(); ListType originalList = dataField.type().asListType(); @@ -159,9 +158,8 @@ private StructProjection(StructType structType, StructType projection, boolean a dataField); nestedProjections[pos] = null; - break; - default: - nestedProjections[pos] = null; + } + default -> nestedProjections[pos] = null; } } } diff --git a/api/src/main/java/org/apache/iceberg/variants/PhysicalType.java b/api/src/main/java/org/apache/iceberg/variants/PhysicalType.java index bcffeaff92e2..17a74478da38 100644 --- a/api/src/main/java/org/apache/iceberg/variants/PhysicalType.java +++ b/api/src/main/java/org/apache/iceberg/variants/PhysicalType.java @@ -65,51 +65,31 @@ public Class javaClass() { } public static PhysicalType from(int primitiveType) { - switch (primitiveType) { - case Primitives.TYPE_NULL: - return NULL; - case Primitives.TYPE_TRUE: - return BOOLEAN_TRUE; - case Primitives.TYPE_FALSE: - return BOOLEAN_FALSE; - case Primitives.TYPE_INT8: - return INT8; - case Primitives.TYPE_INT16: - return INT16; - case Primitives.TYPE_INT32: - return INT32; - case Primitives.TYPE_INT64: - return INT64; - case Primitives.TYPE_DATE: - return DATE; - case Primitives.TYPE_TIMESTAMPTZ: - return TIMESTAMPTZ; - case Primitives.TYPE_TIMESTAMPNTZ: - return TIMESTAMPNTZ; - case Primitives.TYPE_FLOAT: - return FLOAT; - case Primitives.TYPE_DOUBLE: - return DOUBLE; - case Primitives.TYPE_DECIMAL4: - return DECIMAL4; - case Primitives.TYPE_DECIMAL8: - return DECIMAL8; - case Primitives.TYPE_DECIMAL16: - return DECIMAL16; - case Primitives.TYPE_BINARY: - return BINARY; - case Primitives.TYPE_STRING: - return STRING; - case Primitives.TYPE_TIME: - return TIME; - case Primitives.TYPE_TIMESTAMPTZ_NANOS: - return TIMESTAMPTZ_NANOS; - case Primitives.TYPE_TIMESTAMPNTZ_NANOS: - return TIMESTAMPNTZ_NANOS; - case Primitives.TYPE_UUID: - return UUID; - } - - throw new UnsupportedOperationException("Unknown primitive physical type: " + primitiveType); + return switch (primitiveType) { + case Primitives.TYPE_NULL -> NULL; + case Primitives.TYPE_TRUE -> BOOLEAN_TRUE; + case Primitives.TYPE_FALSE -> BOOLEAN_FALSE; + case Primitives.TYPE_INT8 -> INT8; + case Primitives.TYPE_INT16 -> INT16; + case Primitives.TYPE_INT32 -> INT32; + case Primitives.TYPE_INT64 -> INT64; + case Primitives.TYPE_DATE -> DATE; + case Primitives.TYPE_TIMESTAMPTZ -> TIMESTAMPTZ; + case Primitives.TYPE_TIMESTAMPNTZ -> TIMESTAMPNTZ; + case Primitives.TYPE_FLOAT -> FLOAT; + case Primitives.TYPE_DOUBLE -> DOUBLE; + case Primitives.TYPE_DECIMAL4 -> DECIMAL4; + case Primitives.TYPE_DECIMAL8 -> DECIMAL8; + case Primitives.TYPE_DECIMAL16 -> DECIMAL16; + case Primitives.TYPE_BINARY -> BINARY; + case Primitives.TYPE_STRING -> STRING; + case Primitives.TYPE_TIME -> TIME; + case Primitives.TYPE_TIMESTAMPTZ_NANOS -> TIMESTAMPTZ_NANOS; + case Primitives.TYPE_TIMESTAMPNTZ_NANOS -> TIMESTAMPNTZ_NANOS; + case Primitives.TYPE_UUID -> UUID; + default -> + throw new UnsupportedOperationException( + "Unknown primitive physical type: " + primitiveType); + }; } } diff --git a/api/src/main/java/org/apache/iceberg/variants/SerializedPrimitive.java b/api/src/main/java/org/apache/iceberg/variants/SerializedPrimitive.java index 150a0c2a6b1f..09b81d1ce15a 100644 --- a/api/src/main/java/org/apache/iceberg/variants/SerializedPrimitive.java +++ b/api/src/main/java/org/apache/iceberg/variants/SerializedPrimitive.java @@ -60,37 +60,18 @@ private SerializedPrimitive(ByteBuffer value, int header) { } private static long payloadSize(PhysicalType type, ByteBuffer value) { - switch (type) { - case NULL: - case BOOLEAN_TRUE: - case BOOLEAN_FALSE: - return 0; - case INT8: - return 1; - case INT16: - return 2; - case INT32: - case DATE: - case FLOAT: - return 4; - case INT64: - case TIMESTAMPTZ: - case TIMESTAMPNTZ: - case TIME: - case TIMESTAMPTZ_NANOS: - case TIMESTAMPNTZ_NANOS: - case DOUBLE: - return 8; - case DECIMAL4: - return 5; - case DECIMAL8: - return 9; - case DECIMAL16: - return 17; - case UUID: - return 16; - case BINARY: - case STRING: + return switch (type) { + case NULL, BOOLEAN_TRUE, BOOLEAN_FALSE -> 0; + case INT8 -> 1; + case INT16 -> 2; + case INT32, DATE, FLOAT -> 4; + case INT64, TIMESTAMPTZ, TIMESTAMPNTZ, TIME, TIMESTAMPTZ_NANOS, TIMESTAMPNTZ_NANOS, DOUBLE -> + 8; + case DECIMAL4 -> 5; + case DECIMAL8 -> 9; + case DECIMAL16 -> 17; + case UUID -> 16; + case BINARY, STRING -> { Preconditions.checkArgument( PRIMITIVE_OFFSET + 4 <= value.remaining(), "Invalid variant primitive: %s size field extends past buffer", @@ -98,75 +79,55 @@ private static long payloadSize(PhysicalType type, ByteBuffer value) { int size = ByteBuffers.readLittleEndianInt32(value, PRIMITIVE_OFFSET); Preconditions.checkArgument( size >= 0, "Invalid variant primitive: negative %s size %s", type, size); - return 4L + size; - } - - throw new UnsupportedOperationException("Unsupported primitive type: " + type); + yield 4L + size; + } + default -> throw new UnsupportedOperationException("Unsupported primitive type: " + type); + }; } private Object read() { - switch (type) { - case NULL: - return null; - case BOOLEAN_TRUE: - return true; - case BOOLEAN_FALSE: - return false; - case INT8: - return ByteBuffers.readLittleEndianInt8(value, PRIMITIVE_OFFSET); - case INT16: - return ByteBuffers.readLittleEndianInt16(value, PRIMITIVE_OFFSET); - case INT32: - case DATE: - return ByteBuffers.readLittleEndianInt32(value, PRIMITIVE_OFFSET); - case INT64: - case TIMESTAMPTZ: - case TIMESTAMPNTZ: - case TIME: - case TIMESTAMPTZ_NANOS: - case TIMESTAMPNTZ_NANOS: - return ByteBuffers.readLittleEndianInt64(value, PRIMITIVE_OFFSET); - case FLOAT: - return VariantUtil.readFloat(value, PRIMITIVE_OFFSET); - case DOUBLE: - return VariantUtil.readDouble(value, PRIMITIVE_OFFSET); - case DECIMAL4: - { - int scale = ByteBuffers.readByte(value, PRIMITIVE_OFFSET); - int unscaled = ByteBuffers.readLittleEndianInt32(value, PRIMITIVE_OFFSET + 1); - return new BigDecimal(BigInteger.valueOf(unscaled), scale); - } - case DECIMAL8: - { - int scale = ByteBuffers.readByte(value, PRIMITIVE_OFFSET); - long unscaled = ByteBuffers.readLittleEndianInt64(value, PRIMITIVE_OFFSET + 1); - return new BigDecimal(BigInteger.valueOf(unscaled), scale); - } - case DECIMAL16: - { - int scale = ByteBuffers.readByte(value, PRIMITIVE_OFFSET); - byte[] unscaled = new byte[16]; - for (int i = 0; i < 16; i += 1) { - unscaled[i] = (byte) ByteBuffers.readByte(value, PRIMITIVE_OFFSET + 16 - i); - } - return new BigDecimal(new BigInteger(unscaled), scale); - } - case BINARY: - { - int size = ByteBuffers.readLittleEndianInt32(value, PRIMITIVE_OFFSET); - return VariantUtil.slice(value, PRIMITIVE_OFFSET + 4, size); + return switch (type) { + case NULL -> null; + case BOOLEAN_TRUE -> true; + case BOOLEAN_FALSE -> false; + case INT8 -> ByteBuffers.readLittleEndianInt8(value, PRIMITIVE_OFFSET); + case INT16 -> ByteBuffers.readLittleEndianInt16(value, PRIMITIVE_OFFSET); + case INT32, DATE -> ByteBuffers.readLittleEndianInt32(value, PRIMITIVE_OFFSET); + case INT64, TIMESTAMPTZ, TIMESTAMPNTZ, TIME, TIMESTAMPTZ_NANOS, TIMESTAMPNTZ_NANOS -> + ByteBuffers.readLittleEndianInt64(value, PRIMITIVE_OFFSET); + case FLOAT -> VariantUtil.readFloat(value, PRIMITIVE_OFFSET); + case DOUBLE -> VariantUtil.readDouble(value, PRIMITIVE_OFFSET); + case DECIMAL4 -> { + int scale = ByteBuffers.readByte(value, PRIMITIVE_OFFSET); + int unscaled = ByteBuffers.readLittleEndianInt32(value, PRIMITIVE_OFFSET + 1); + yield new BigDecimal(BigInteger.valueOf(unscaled), scale); + } + case DECIMAL8 -> { + int scale = ByteBuffers.readByte(value, PRIMITIVE_OFFSET); + long unscaled = ByteBuffers.readLittleEndianInt64(value, PRIMITIVE_OFFSET + 1); + yield new BigDecimal(BigInteger.valueOf(unscaled), scale); + } + case DECIMAL16 -> { + int scale = ByteBuffers.readByte(value, PRIMITIVE_OFFSET); + byte[] unscaled = new byte[16]; + for (int i = 0; i < 16; i += 1) { + unscaled[i] = (byte) ByteBuffers.readByte(value, PRIMITIVE_OFFSET + 16 - i); } - case STRING: - { - int size = ByteBuffers.readLittleEndianInt32(value, PRIMITIVE_OFFSET); - return VariantUtil.readString(value, PRIMITIVE_OFFSET + 4, size); - } - case UUID: - return UUIDUtil.convert( - VariantUtil.slice(value, PRIMITIVE_OFFSET, 16).order(ByteOrder.BIG_ENDIAN)); - } - - throw new UnsupportedOperationException("Unsupported primitive type: " + type); + yield new BigDecimal(new BigInteger(unscaled), scale); + } + case BINARY -> { + int size = ByteBuffers.readLittleEndianInt32(value, PRIMITIVE_OFFSET); + yield VariantUtil.slice(value, PRIMITIVE_OFFSET + 4, size); + } + case STRING -> { + int size = ByteBuffers.readLittleEndianInt32(value, PRIMITIVE_OFFSET); + yield VariantUtil.readString(value, PRIMITIVE_OFFSET + 4, size); + } + case UUID -> + UUIDUtil.convert( + VariantUtil.slice(value, PRIMITIVE_OFFSET, 16).order(ByteOrder.BIG_ENDIAN)); + default -> throw new UnsupportedOperationException("Unsupported primitive type: " + type); + }; } @Override diff --git a/api/src/main/java/org/apache/iceberg/variants/VariantPrimitive.java b/api/src/main/java/org/apache/iceberg/variants/VariantPrimitive.java index 7e9bfe0e3c73..da318ae6b08c 100644 --- a/api/src/main/java/org/apache/iceberg/variants/VariantPrimitive.java +++ b/api/src/main/java/org/apache/iceberg/variants/VariantPrimitive.java @@ -34,24 +34,16 @@ default VariantPrimitive asPrimitive() { } private String valueAsString() { - switch (type()) { - case DATE: - return DateTimeUtil.daysToIsoDate((Integer) get()); - case TIME: - return DateTimeUtil.microsToIsoTime((Long) get()); - case TIMESTAMPTZ: - return DateTimeUtil.microsToIsoTimestamptz((Long) get()); - case TIMESTAMPNTZ: - return DateTimeUtil.microsToIsoTimestamp((Long) get()); - case TIMESTAMPTZ_NANOS: - return DateTimeUtil.nanosToIsoTimestamptz((Long) get()); - case TIMESTAMPNTZ_NANOS: - return DateTimeUtil.nanosToIsoTimestamp((Long) get()); - case BINARY: - return BaseEncoding.base16().encode(ByteBuffers.toByteArray((ByteBuffer) get())); - default: - return String.valueOf(get()); - } + return switch (type()) { + case DATE -> DateTimeUtil.daysToIsoDate((Integer) get()); + case TIME -> DateTimeUtil.microsToIsoTime((Long) get()); + case TIMESTAMPTZ -> DateTimeUtil.microsToIsoTimestamptz((Long) get()); + case TIMESTAMPNTZ -> DateTimeUtil.microsToIsoTimestamp((Long) get()); + case TIMESTAMPTZ_NANOS -> DateTimeUtil.nanosToIsoTimestamptz((Long) get()); + case TIMESTAMPNTZ_NANOS -> DateTimeUtil.nanosToIsoTimestamp((Long) get()); + case BINARY -> BaseEncoding.base16().encode(ByteBuffers.toByteArray((ByteBuffer) get())); + default -> String.valueOf(get()); + }; } static String asString(VariantPrimitive primitive) { diff --git a/api/src/main/java/org/apache/iceberg/variants/VariantUtil.java b/api/src/main/java/org/apache/iceberg/variants/VariantUtil.java index 3c88e38157a5..0302266346ef 100644 --- a/api/src/main/java/org/apache/iceberg/variants/VariantUtil.java +++ b/api/src/main/java/org/apache/iceberg/variants/VariantUtil.java @@ -57,18 +57,12 @@ static VariantValue fromBuffer(VariantMetadata metadata, ByteBuffer value, int d Preconditions.checkArgument(value.remaining() >= 1, "Invalid variant: empty value buffer"); int header = ByteBuffers.readByte(value, 0); BasicType basicType = basicType(header); - switch (basicType) { - case PRIMITIVE: - return SerializedPrimitive.from(value, header); - case SHORT_STRING: - return SerializedShortString.from(value, header); - case OBJECT: - return SerializedObject.from(metadata, value, header, depth); - case ARRAY: - return SerializedArray.from(metadata, value, header, depth); - } - - throw new UnsupportedOperationException("Unsupported basic type: " + basicType); + return switch (basicType) { + case PRIMITIVE -> SerializedPrimitive.from(value, header); + case SHORT_STRING -> SerializedShortString.from(value, header); + case OBJECT -> SerializedObject.from(metadata, value, header, depth); + case ARRAY -> SerializedArray.from(metadata, value, header, depth); + }; } static float readFloat(ByteBuffer buffer, int offset) { @@ -153,17 +147,12 @@ static byte shortStringHeader(int length) { static BasicType basicType(int header) { int basicType = header & BASIC_TYPE_MASK; - switch (basicType) { - case BASIC_TYPE_PRIMITIVE: - return BasicType.PRIMITIVE; - case BASIC_TYPE_SHORT_STRING: - return BasicType.SHORT_STRING; - case BASIC_TYPE_OBJECT: - return BasicType.OBJECT; - case BASIC_TYPE_ARRAY: - return BasicType.ARRAY; - } - - throw new UnsupportedOperationException("Unsupported basic type: " + basicType); + return switch (basicType) { + case BASIC_TYPE_PRIMITIVE -> BasicType.PRIMITIVE; + case BASIC_TYPE_SHORT_STRING -> BasicType.SHORT_STRING; + case BASIC_TYPE_OBJECT -> BasicType.OBJECT; + case BASIC_TYPE_ARRAY -> BasicType.ARRAY; + default -> throw new UnsupportedOperationException("Unsupported basic type: " + basicType); + }; } }