1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package org.apache.spark.sql.catalyst.optimizer 19 20import org.apache.spark.sql.catalyst.analysis._ 21import org.apache.spark.sql.catalyst.dsl.expressions._ 22import org.apache.spark.sql.catalyst.dsl.plans._ 23import org.apache.spark.sql.catalyst.expressions._ 24import org.apache.spark.sql.catalyst.expressions.Literal.{FalseLiteral, TrueLiteral} 25import org.apache.spark.sql.catalyst.plans.PlanTest 26import org.apache.spark.sql.catalyst.plans.logical._ 27import org.apache.spark.sql.catalyst.rules._ 28 29class BinaryComparisonSimplificationSuite extends PlanTest with PredicateHelper { 30 31 object Optimize extends RuleExecutor[LogicalPlan] { 32 val batches = 33 Batch("AnalysisNodes", Once, 34 EliminateSubqueryAliases) :: 35 Batch("Constant Folding", FixedPoint(50), 36 NullPropagation, 37 ConstantFolding, 38 BooleanSimplification, 39 SimplifyBinaryComparison, 40 PruneFilters) :: Nil 41 } 42 43 val nullableRelation = LocalRelation('a.int.withNullability(true)) 44 val nonNullableRelation = LocalRelation('a.int.withNullability(false)) 45 46 test("Preserve nullable exprs in general") { 47 for (e <- Seq('a === 'a, 'a <= 'a, 'a >= 'a, 'a < 'a, 'a > 'a)) { 48 val plan = nullableRelation.where(e).analyze 49 val actual = Optimize.execute(plan) 50 val correctAnswer = plan 51 comparePlans(actual, correctAnswer) 52 } 53 } 54 55 test("Preserve non-deterministic exprs") { 56 val plan = nonNullableRelation 57 .where(Rand(0) === Rand(0) && Rand(1) <=> Rand(1)).analyze 58 val actual = Optimize.execute(plan) 59 val correctAnswer = plan 60 comparePlans(actual, correctAnswer) 61 } 62 63 test("Nullable Simplification Primitive: <=>") { 64 val plan = nullableRelation.select('a <=> 'a).analyze 65 val actual = Optimize.execute(plan) 66 val correctAnswer = nullableRelation.select(Alias(TrueLiteral, "(a <=> a)")()).analyze 67 comparePlans(actual, correctAnswer) 68 } 69 70 test("Non-Nullable Simplification Primitive") { 71 val plan = nonNullableRelation 72 .select('a === 'a, 'a <=> 'a, 'a <= 'a, 'a >= 'a, 'a < 'a, 'a > 'a).analyze 73 val actual = Optimize.execute(plan) 74 val correctAnswer = nonNullableRelation 75 .select( 76 Alias(TrueLiteral, "(a = a)")(), 77 Alias(TrueLiteral, "(a <=> a)")(), 78 Alias(TrueLiteral, "(a <= a)")(), 79 Alias(TrueLiteral, "(a >= a)")(), 80 Alias(FalseLiteral, "(a < a)")(), 81 Alias(FalseLiteral, "(a > a)")()) 82 .analyze 83 comparePlans(actual, correctAnswer) 84 } 85 86 test("Expression Normalization") { 87 val plan = nonNullableRelation.where( 88 'a * Literal(100) + Pi() === Pi() + Literal(100) * 'a && 89 DateAdd(CurrentDate(), 'a + Literal(2)) <= DateAdd(CurrentDate(), Literal(2) + 'a)) 90 .analyze 91 val actual = Optimize.execute(plan) 92 val correctAnswer = nonNullableRelation.analyze 93 comparePlans(actual, correctAnswer) 94 } 95} 96