@Override public <T> Set<Integer> predicate(BoundPredicate<T> pred) { references.add(pred.ref().fieldId()); return references; } }
public <T> R predicate(BoundPredicate<T> pred) { switch (pred.op()) { case IS_NULL: return isNull(pred.ref()); case NOT_NULL: return notNull(pred.ref()); case LT: return lt(pred.ref(), pred.literal()); case LT_EQ: return ltEq(pred.ref(), pred.literal()); case GT: return gt(pred.ref(), pred.literal()); case GT_EQ: return gtEq(pred.ref(), pred.literal()); case EQ: return eq(pred.ref(), pred.literal()); case NOT_EQ: return notEq(pred.ref(), pred.literal()); case IN: return in(pred.ref(), pred.literal()); case NOT_IN: return notIn(pred.ref(), pred.literal()); default: throw new UnsupportedOperationException( "Unknown operation for predicate: " + pred.op()); } }
@Override public Expression negate() { return new BoundPredicate<>(op().negate(), ref(), literal()); } }
@Override @SuppressWarnings("unchecked") public <T> Expression predicate(BoundPredicate<T> pred) { PartitionField part = spec.getFieldBySourceId(pred.ref().fieldId()); if (part == null) { // the predicate has no partition column return alwaysTrue(); } UnboundPredicate<?> result = ((Transform<T, ?>) part.transform()).project(part.name(), pred); if (result != null) { return result; } // if the predicate could not be projected, it always matches return alwaysTrue(); } }
@Override @SuppressWarnings("unchecked") public <T> Expression predicate(BoundPredicate<T> pred) { PartitionField part = spec.getFieldBySourceId(pred.ref().fieldId()); if (part == null) { // the predicate has no partition column return alwaysFalse(); } UnboundPredicate<?> result = ((Transform<T, ?>) part.transform()) .projectStrict(part.name(), pred); if (result != null) { return result; } // if the predicate could not be projected, it never matches return alwaysFalse(); } }
@Override @SuppressWarnings("unchecked") public <T> Expression predicate(BoundPredicate<T> pred) { // Get the strict projection of this predicate in partition data, then use it to determine // whether to return the original predicate. The strict projection returns true iff the // original predicate would have returned true, so the predicate can be eliminated if the // strict projection evaluates to true. // // If there is no strict projection or if it evaluates to false, then return the predicate. PartitionField part = spec.getFieldBySourceId(pred.ref().fieldId()); if (part == null) { return pred; // not associated inclusive a partition field, can't be evaluated } UnboundPredicate<?> strictProjection = ((Transform<T, ?>) part.transform()) .projectStrict(part.name(), pred); if (strictProjection != null) { Expression bound = strictProjection.bind(spec.partitionType()); if (bound instanceof BoundPredicate) { // the predicate methods will evaluate and return alwaysTrue or alwaysFalse return super.predicate((BoundPredicate<?>) bound); } return bound; // use the non-predicate residual (e.g. alwaysTrue) } // if the predicate could not be projected, it must be in the residual return pred; }
@Test public void testOr() { Expression expr = or(greaterThan("z", -100), lessThan("y", 100)); Expression boundExpr = Binder.bind(STRUCT, expr); TestHelpers.assertAllReferencesBound("Or", boundExpr); // make sure the result is an Or Or or = TestHelpers.assertAndUnwrap(boundExpr, Or.class); // make sure the refs are for the right fields BoundPredicate<?> left = TestHelpers.assertAndUnwrap(or.left()); Assert.assertEquals("Should bind z correctly", 2, left.ref().fieldId()); BoundPredicate<?> right = TestHelpers.assertAndUnwrap(or.right()); Assert.assertEquals("Should bind y correctly", 1, right.ref().fieldId()); }
@Test public void testAnd() { Expression expr = and(equal("x", 7), lessThan("y", 100)); Expression boundExpr = Binder.bind(STRUCT, expr); TestHelpers.assertAllReferencesBound("And", boundExpr); // make sure the result is an And And and = TestHelpers.assertAndUnwrap(boundExpr, And.class); // make sure the refs are for the right fields BoundPredicate<?> left = TestHelpers.assertAndUnwrap(and.left()); Assert.assertEquals("Should bind x correctly", 0, left.ref().fieldId()); BoundPredicate<?> right = TestHelpers.assertAndUnwrap(and.right()); Assert.assertEquals("Should bind y correctly", 1, right.ref().fieldId()); }
@Test public void testNot() { Expression expr = not(equal("x", 7)); Expression boundExpr = Binder.bind(STRUCT, expr); TestHelpers.assertAllReferencesBound("Not", boundExpr); // make sure the result is a Not Not not = TestHelpers.assertAndUnwrap(boundExpr, Not.class); // make sure the refs are for the right fields BoundPredicate<?> child = TestHelpers.assertAndUnwrap(not.child()); Assert.assertEquals("Should bind x correctly", 0, child.ref().fieldId()); }
@Test @SuppressWarnings("unchecked") public void testComparisonPredicateBinding() { StructType struct = StructType.of(required(14, "x", Types.IntegerType.get())); for (Expression.Operation op : COMPARISONS) { UnboundPredicate<Integer> unbound = new UnboundPredicate<>(op, ref("x"), 5); Expression expr = unbound.bind(struct); BoundPredicate<Integer> bound = assertAndUnwrap(expr); Assert.assertEquals("Should not alter literal value", Integer.valueOf(5), bound.literal().value()); Assert.assertEquals("Should reference correct field ID", 14, bound.ref().fieldId()); Assert.assertEquals("Should not change the comparison operation", op, bound.op()); } }
@Test @SuppressWarnings("unchecked") public void testLiteralConversion() { StructType struct = StructType.of(required(15, "d", Types.DecimalType.of(9, 2))); for (Expression.Operation op : COMPARISONS) { UnboundPredicate<String> unbound = new UnboundPredicate<>(op, ref("d"), "12.40"); Expression expr = unbound.bind(struct); BoundPredicate<BigDecimal> bound = assertAndUnwrap(expr); Assert.assertEquals("Should convert literal value to decimal", new BigDecimal("12.40"), bound.literal().value()); Assert.assertEquals("Should reference correct field ID", 15, bound.ref().fieldId()); Assert.assertEquals("Should not change the comparison operation", op, bound.op()); } }
@Override public <T> FilterPredicate predicate(BoundPredicate<T> pred) { Operation op = pred.op(); BoundReference<T> ref = pred.ref(); Literal<T> lit = pred.literal(); String path = schema.idToAlias(ref.fieldId());
@Test @SuppressWarnings("unchecked") public void testMultipleFields() { StructType struct = StructType.of( required(10, "x", Types.IntegerType.get()), required(11, "y", Types.IntegerType.get()), required(12, "z", Types.IntegerType.get()) ); UnboundPredicate<Integer> unbound = new UnboundPredicate<>(LT, ref("y"), 6); Expression expr = unbound.bind(struct); BoundPredicate<Integer> bound = assertAndUnwrap(expr); Assert.assertEquals("Should reference correct field ID", 11, bound.ref().fieldId()); Assert.assertEquals("Should not change the comparison operation", LT, bound.op()); Assert.assertEquals("Should not alter literal value", Integer.valueOf(6), bound.literal().value()); }
@Test @SuppressWarnings("unchecked") public void testIsNull() { StructType optional = StructType.of(optional(19, "s", Types.StringType.get())); UnboundPredicate<?> unbound = new UnboundPredicate<>(IS_NULL, ref("s")); Expression expr = unbound.bind(optional); BoundPredicate<?> bound = assertAndUnwrap(expr); Assert.assertEquals("Should use the same operation", IS_NULL, bound.op()); Assert.assertEquals("Should use the correct field", 19, bound.ref().fieldId()); Assert.assertNull("Should not have a literal value", bound.literal()); StructType required = StructType.of(required(20, "s", Types.StringType.get())); Assert.assertEquals("IsNull inclusive a required field should be alwaysFalse", Expressions.alwaysFalse(), unbound.bind(required)); }
@Test public void testNotNull() { StructType optional = StructType.of(optional(21, "s", Types.StringType.get())); UnboundPredicate<?> unbound = new UnboundPredicate<>(NOT_NULL, ref("s")); Expression expr = unbound.bind(optional); BoundPredicate<?> bound = assertAndUnwrap(expr); Assert.assertEquals("Should use the same operation", NOT_NULL, bound.op()); Assert.assertEquals("Should use the correct field", 21, bound.ref().fieldId()); Assert.assertNull("Should not have a literal value", bound.literal()); StructType required = StructType.of(required(22, "s", Types.StringType.get())); Assert.assertEquals("NotNull inclusive a required field should be alwaysTrue", Expressions.alwaysTrue(), unbound.bind(required)); } }
@Test public void testBasicSimplification() { // this tests that a basic simplification is done by calling the helpers in Expressions. those // are more thoroughly tested in TestExpressionHelpers. // the second predicate is always true once it is bound because z is an integer and the literal // is less than any 32-bit integer value Assert.assertEquals("Should simplify or expression to alwaysTrue", alwaysTrue(), Binder.bind(STRUCT, or(lessThan("y", 100), greaterThan("z", -9999999999L)))); // similarly, the second predicate is always false Assert.assertEquals("Should simplify and expression to predicate", alwaysFalse(), Binder.bind(STRUCT, and(lessThan("y", 100), lessThan("z", -9999999999L)))); Expression bound = Binder.bind(STRUCT, not(not(lessThan("y", 100)))); BoundPredicate<?> pred = TestHelpers.assertAndUnwrap(bound); Assert.assertEquals("Should have the correct bound field", 1, pred.ref().fieldId()); } }