Skip to content

Commit dd47957

Browse files
author
Jennifer Baldwin
committed
cherry pick of OTF-1500
1 parent b53a988 commit dd47957

File tree

20 files changed

+2254
-35
lines changed

20 files changed

+2254
-35
lines changed

api/src/main/java/org/apache/iceberg/expressions/BoundPredicate.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ protected BoundPredicate(Operation op, BoundTerm<T> term) {
2626
super(op, term);
2727
}
2828

29+
protected BoundPredicate(Operation op, BoundTerm<T> term, BoundTerm<T> rightTerm) {
30+
super(op, term, rightTerm);
31+
}
32+
2933
public boolean test(StructLike struct) {
3034
return test(term().eval(struct));
3135
}
@@ -58,6 +62,14 @@ public BoundLiteralPredicate<T> asLiteralPredicate() {
5862
throw new IllegalStateException("Not a literal predicate: " + this);
5963
}
6064

65+
public boolean isTermPredicate() {
66+
return false;
67+
}
68+
69+
public BoundTermPredicate<T> asTermPredicate() {
70+
throw new IllegalStateException("Not a term predicate: " + this);
71+
}
72+
6173
public boolean isSetPredicate() {
6274
return false;
6375
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.iceberg.expressions;
20+
21+
import org.apache.iceberg.util.NaNUtil;
22+
23+
public class BoundTermPredicate<T> extends BoundPredicate<T> {
24+
25+
BoundTermPredicate(Operation op, BoundTerm<T> term, BoundTerm<T> rightTerm) {
26+
super(op, term, rightTerm);
27+
}
28+
29+
@Override
30+
public Expression negate() {
31+
return new BoundTermPredicate<>(op().negate(), term(), rightTerm());
32+
}
33+
34+
@Override
35+
public boolean isTermPredicate() {
36+
return true;
37+
}
38+
39+
@Override
40+
public BoundTermPredicate<T> asTermPredicate() {
41+
return this;
42+
}
43+
44+
@Override
45+
public boolean test(T value) {
46+
switch (op()) {
47+
case IS_NULL:
48+
return value == null;
49+
case NOT_NULL:
50+
return value != null;
51+
case IS_NAN:
52+
return NaNUtil.isNaN(value);
53+
case NOT_NAN:
54+
return !NaNUtil.isNaN(value);
55+
default:
56+
throw new IllegalStateException("Invalid operation for BoundTermPredicate: " + op());
57+
}
58+
}
59+
60+
@Override
61+
public boolean isEquivalentTo(Expression other) {
62+
if (op() == other.op()) {
63+
return term().isEquivalentTo(((BoundTermPredicate<?>) other).term());
64+
}
65+
66+
return false;
67+
}
68+
69+
@Override
70+
public String toString() {
71+
switch (op()) {
72+
case LT:
73+
return term() + " < " + rightTerm();
74+
case LT_EQ:
75+
return term() + " <= " + rightTerm();
76+
case GT:
77+
return term() + " > " + rightTerm();
78+
case GT_EQ:
79+
return term() + " >= " + rightTerm();
80+
case EQ:
81+
return term() + " == " + rightTerm();
82+
case NOT_EQ:
83+
return term() + " != " + rightTerm();
84+
default:
85+
return "Invalid term predicate: operation = " + op();
86+
}
87+
}
88+
}

api/src/main/java/org/apache/iceberg/expressions/Evaluator.java

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.Set;
2424
import org.apache.iceberg.StructLike;
2525
import org.apache.iceberg.expressions.ExpressionVisitors.BoundVisitor;
26+
import org.apache.iceberg.types.Comparators;
2627
import org.apache.iceberg.types.Types.StructType;
2728
import org.apache.iceberg.util.NaNUtil;
2829

@@ -107,35 +108,107 @@ public <T> Boolean lt(Bound<T> valueExpr, Literal<T> lit) {
107108
return cmp.compare(valueExpr.eval(struct), lit.value()) < 0;
108109
}
109110

111+
@Override
112+
public <T> Boolean lt(Bound<T> valueExpr, Bound<T> valueExpr2) {
113+
validateDataTypes(valueExpr, valueExpr2);
114+
T value = valueExpr.eval(struct);
115+
T value2 = valueExpr2.eval(struct);
116+
if (value == null || value2 == null) {
117+
return false;
118+
}
119+
Comparator<T> cmp = Comparators.forType(valueExpr.ref().type().asPrimitiveType());
120+
return cmp.compare(value, value2) < 0;
121+
}
122+
110123
@Override
111124
public <T> Boolean ltEq(Bound<T> valueExpr, Literal<T> lit) {
112125
Comparator<T> cmp = lit.comparator();
113126
return cmp.compare(valueExpr.eval(struct), lit.value()) <= 0;
114127
}
115128

129+
@Override
130+
public <T> Boolean ltEq(Bound<T> valueExpr, Bound<T> valueExpr2) {
131+
validateDataTypes(valueExpr, valueExpr2);
132+
T value = valueExpr.eval(struct);
133+
T value2 = valueExpr2.eval(struct);
134+
if (value == null || value2 == null) {
135+
return false;
136+
}
137+
Comparator<T> cmp = Comparators.forType(valueExpr.ref().type().asPrimitiveType());
138+
return cmp.compare(value, value2) <= 0;
139+
}
140+
116141
@Override
117142
public <T> Boolean gt(Bound<T> valueExpr, Literal<T> lit) {
118143
Comparator<T> cmp = lit.comparator();
119144
return cmp.compare(valueExpr.eval(struct), lit.value()) > 0;
120145
}
121146

147+
@Override
148+
public <T> Boolean gt(Bound<T> valueExpr, Bound<T> valueExpr2) {
149+
validateDataTypes(valueExpr, valueExpr2);
150+
T value = valueExpr.eval(struct);
151+
T value2 = valueExpr2.eval(struct);
152+
if (value == null || value2 == null) {
153+
return false;
154+
}
155+
Comparator<T> cmp = Comparators.forType(valueExpr.ref().type().asPrimitiveType());
156+
return cmp.compare(value, value2) > 0;
157+
}
158+
122159
@Override
123160
public <T> Boolean gtEq(Bound<T> valueExpr, Literal<T> lit) {
124161
Comparator<T> cmp = lit.comparator();
125162
return cmp.compare(valueExpr.eval(struct), lit.value()) >= 0;
126163
}
127164

165+
@Override
166+
public <T> Boolean gtEq(Bound<T> valueExpr, Bound<T> valueExpr2) {
167+
validateDataTypes(valueExpr, valueExpr2);
168+
T value = valueExpr.eval(struct);
169+
T value2 = valueExpr2.eval(struct);
170+
if (value == null || value2 == null) {
171+
return false;
172+
}
173+
Comparator<T> cmp = Comparators.forType(valueExpr.ref().type().asPrimitiveType());
174+
return cmp.compare(value, value2) >= 0;
175+
}
176+
128177
@Override
129178
public <T> Boolean eq(Bound<T> valueExpr, Literal<T> lit) {
130179
Comparator<T> cmp = lit.comparator();
131180
return cmp.compare(valueExpr.eval(struct), lit.value()) == 0;
132181
}
133182

183+
@Override
184+
public <T> Boolean eq(Bound<T> valueExpr, Bound<T> valueExpr2) {
185+
validateDataTypes(valueExpr, valueExpr2);
186+
T value = valueExpr.eval(struct);
187+
T value2 = valueExpr2.eval(struct);
188+
if (value == null || value2 == null) {
189+
return false;
190+
}
191+
Comparator<T> cmp = Comparators.forType(valueExpr.ref().type().asPrimitiveType());
192+
return cmp.compare(value, value2) == 0;
193+
}
194+
134195
@Override
135196
public <T> Boolean notEq(Bound<T> valueExpr, Literal<T> lit) {
136197
return !eq(valueExpr, lit);
137198
}
138199

200+
@Override
201+
public <T> Boolean notEq(Bound<T> valueExpr, Bound<T> valueExpr2) {
202+
validateDataTypes(valueExpr, valueExpr2);
203+
T value = valueExpr.eval(struct);
204+
T value2 = valueExpr2.eval(struct);
205+
if (value == null || value2 == null) {
206+
return false;
207+
}
208+
Comparator<T> cmp = Comparators.forType(valueExpr.ref().type().asPrimitiveType());
209+
return !(cmp.compare(value, value2) == 0);
210+
}
211+
139212
@Override
140213
public <T> Boolean in(Bound<T> valueExpr, Set<T> literalSet) {
141214
return literalSet.contains(valueExpr.eval(struct));
@@ -156,5 +229,15 @@ public <T> Boolean startsWith(Bound<T> valueExpr, Literal<T> lit) {
156229
public <T> Boolean notStartsWith(Bound<T> valueExpr, Literal<T> lit) {
157230
return !startsWith(valueExpr, lit);
158231
}
232+
233+
private <T> void validateDataTypes(Bound<T> valueExpr, Bound<T> valueExpr2) {
234+
if (valueExpr.ref().type().typeId() != valueExpr2.ref().type().typeId()) {
235+
throw new IllegalArgumentException(
236+
"Cannot compare different types: "
237+
+ valueExpr.ref().type()
238+
+ " and "
239+
+ valueExpr2.ref().type());
240+
}
241+
}
159242
}
160243
}

api/src/main/java/org/apache/iceberg/expressions/ExpressionUtil.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ public <T> Expression predicate(BoundPredicate<T> pred) {
318318
@Override
319319
@SuppressWarnings("unchecked")
320320
public <T> Expression predicate(UnboundPredicate<T> pred) {
321+
if (pred.rightTerm() != null) {
322+
return new UnboundPredicate<>(pred.op(), pred.term(), pred.rightTerm());
323+
}
321324
switch (pred.op()) {
322325
case IS_NULL:
323326
case NOT_NULL:
@@ -390,6 +393,9 @@ private String value(BoundLiteralPredicate<?> pred) {
390393
@Override
391394
public <T> String predicate(BoundPredicate<T> pred) {
392395
String term = describe(pred.term());
396+
if (pred.rightTerm() != null) {
397+
return termPredicate(pred, term);
398+
}
393399
switch (pred.op()) {
394400
case IS_NULL:
395401
return term + " IS NULL";
@@ -439,9 +445,33 @@ public <T> String predicate(BoundPredicate<T> pred) {
439445
}
440446
}
441447

448+
private static String termPredicate(Predicate pred, String term) {
449+
String rightTerm = describe(pred.rightTerm());
450+
switch (pred.op()) {
451+
case LT:
452+
return term + " < " + rightTerm;
453+
case LT_EQ:
454+
return term + " <= " + rightTerm;
455+
case GT:
456+
return term + " > " + rightTerm;
457+
case GT_EQ:
458+
return term + " >= " + rightTerm;
459+
case EQ:
460+
return term + " = " + rightTerm;
461+
case NOT_EQ:
462+
return term + " != " + rightTerm;
463+
default:
464+
throw new UnsupportedOperationException(
465+
"Cannot sanitize unsupported predicate type: " + pred.op());
466+
}
467+
}
468+
442469
@Override
443470
public <T> String predicate(UnboundPredicate<T> pred) {
444471
String term = describe(pred.term());
472+
if (pred.rightTerm() != null) {
473+
return termPredicate(pred, term);
474+
}
445475
switch (pred.op()) {
446476
case IS_NULL:
447477
return term + " IS NULL";

0 commit comments

Comments
 (0)