| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.tajo.engine.planner; |
| |
| import org.apache.tajo.BuiltinStorages; |
| import org.apache.tajo.LocalTajoTestingUtility; |
| import org.apache.tajo.QueryVars; |
| import org.apache.tajo.TajoTestingCluster; |
| import org.apache.tajo.algebra.*; |
| import org.apache.tajo.benchmark.TPCH; |
| import org.apache.tajo.catalog.*; |
| import org.apache.tajo.engine.function.FunctionLoader; |
| import org.apache.tajo.engine.query.QueryContext; |
| import org.apache.tajo.exception.TajoException; |
| import org.apache.tajo.parser.sql.SQLAnalyzer; |
| import org.apache.tajo.plan.LogicalOptimizer; |
| import org.apache.tajo.plan.LogicalPlan; |
| import org.apache.tajo.plan.LogicalPlanner; |
| import org.apache.tajo.plan.expr.AlgebraicUtil; |
| import org.apache.tajo.plan.logical.LogicalNode; |
| import org.apache.tajo.plan.logical.NodeType; |
| import org.apache.tajo.plan.logical.ScanNode; |
| import org.apache.tajo.plan.util.EvalNodeToExprConverter; |
| import org.apache.tajo.plan.util.PlannerUtil; |
| import org.apache.tajo.schema.IdentifierUtil; |
| import org.apache.tajo.session.Session; |
| import org.apache.tajo.storage.TablespaceManager; |
| import org.apache.tajo.util.CommonTestingUtil; |
| import org.junit.AfterClass; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| |
| import java.util.Stack; |
| |
| import static org.apache.tajo.TajoConstants.DEFAULT_DATABASE_NAME; |
| import static org.apache.tajo.TajoConstants.DEFAULT_TABLESPACE_NAME; |
| import static org.junit.Assert.*; |
| |
| public class TestEvalNodeToExprConverter { |
| private static TajoTestingCluster util; |
| private static CatalogService catalog; |
| private static SQLAnalyzer sqlAnalyzer; |
| private static LogicalPlanner planner; |
| private static TPCH tpch; |
| private static Session session = LocalTajoTestingUtility.createDummySession(); |
| |
| @BeforeClass |
| public static void setUp() throws Exception { |
| util = new TajoTestingCluster(); |
| util.startCatalogCluster(); |
| catalog = util.getCatalogService(); |
| catalog.createTablespace(DEFAULT_TABLESPACE_NAME, "hdfs://localhost:1234"); |
| catalog.createDatabase(DEFAULT_DATABASE_NAME, DEFAULT_TABLESPACE_NAME); |
| |
| for (FunctionDesc funcDesc : FunctionLoader.findLegacyFunctions()) { |
| catalog.createFunction(funcDesc); |
| } |
| |
| // TPC-H Schema for Complex Queries |
| String [] tpchTables = { |
| "part", "supplier", "partsupp", "nation", "region", "lineitem" |
| }; |
| tpch = new TPCH(); |
| tpch.loadSchemas(); |
| tpch.loadOutSchema(); |
| for (String table : tpchTables) { |
| TableMeta m = CatalogUtil.newTableMeta(BuiltinStorages.TEXT, util.getConfiguration()); |
| TableDesc d = CatalogUtil.newTableDesc( |
| IdentifierUtil.buildFQName(DEFAULT_DATABASE_NAME, table), tpch.getSchema(table), m, |
| CommonTestingUtil.getTestDir()); |
| catalog.createTable(d); |
| } |
| |
| sqlAnalyzer = new SQLAnalyzer(); |
| planner = new LogicalPlanner(catalog, TablespaceManager.getInstance()); |
| } |
| |
| @AfterClass |
| public static void tearDown() throws Exception { |
| util.shutdownCatalogCluster(); |
| } |
| |
| static String[] QUERIES = { |
| "select * from lineitem where L_ORDERKEY > 500", //0 |
| "select * from region where r_name = 'EUROPE'", //1 |
| "select * from lineitem where L_DISCOUNT >= 0.05 and L_DISCOUNT <= 0.07 OR L_QUANTITY < 24.0 ", //2 |
| "select * from lineitem where L_DISCOUNT between 0.06 - 0.01 and 0.08 + 0.02 and L_ORDERKEY < 24 ", //3 |
| "select * from lineitem where (case when L_DISCOUNT > 0.0 then L_DISCOUNT / L_TAX else null end) > 1.2 ", //4 |
| "select * from part where p_brand = 'Brand#23' and p_container in ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK') " + |
| "and p_size between 1 and 10", //5 |
| }; |
| |
| private static QueryContext createQueryContext() { |
| QueryContext qc = new QueryContext(util.getConfiguration(), session); |
| qc.put(QueryVars.DEFAULT_SPACE_URI, "file:/"); |
| qc.put(QueryVars.DEFAULT_SPACE_ROOT_URI, "file:/"); |
| return qc; |
| } |
| |
| @Test |
| public final void testBinaryOperator1() throws CloneNotSupportedException, TajoException { |
| QueryContext qc = createQueryContext(); |
| |
| Expr expr = sqlAnalyzer.parse(QUERIES[0]); |
| |
| LogicalPlan plan = planner.createPlan(qc, expr); |
| LogicalOptimizer optimizer = new LogicalOptimizer(util.getConfiguration(), catalog, TablespaceManager.getInstance()); |
| optimizer.optimize(plan); |
| |
| LogicalNode node = plan.getRootBlock().getRoot(); |
| ScanNode scanNode = PlannerUtil.findTopNode(node, NodeType.SCAN); |
| |
| EvalNodeToExprConverter convertor = new EvalNodeToExprConverter(scanNode.getTableName()); |
| convertor.visit(null, scanNode.getQual(), new Stack<>()); |
| |
| Expr resultExpr = convertor.getResult(); |
| |
| BinaryOperator binaryOperator = AlgebraicUtil.findTopExpr(resultExpr, OpType.GreaterThan); |
| assertNotNull(binaryOperator); |
| |
| ColumnReferenceExpr column = binaryOperator.getLeft(); |
| assertEquals("default.lineitem", column.getQualifier()); |
| assertEquals("l_orderkey", column.getName()); |
| |
| LiteralValue literalValue = binaryOperator.getRight(); |
| assertEquals("500", literalValue.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Integer, literalValue.getValueType()); |
| } |
| |
| @Test |
| public final void testBinaryOperator2() throws CloneNotSupportedException, TajoException { |
| QueryContext qc = createQueryContext(); |
| |
| Expr expr = sqlAnalyzer.parse(QUERIES[1]); |
| |
| LogicalPlan plan = planner.createPlan(qc, expr); |
| LogicalOptimizer optimizer = new LogicalOptimizer(util.getConfiguration(), catalog, TablespaceManager.getInstance()); |
| optimizer.optimize(plan); |
| |
| LogicalNode node = plan.getRootBlock().getRoot(); |
| ScanNode scanNode = PlannerUtil.findTopNode(node, NodeType.SCAN); |
| |
| EvalNodeToExprConverter convertor = new EvalNodeToExprConverter(scanNode.getTableName()); |
| convertor.visit(null, scanNode.getQual(), new Stack<>()); |
| |
| Expr resultExpr = convertor.getResult(); |
| BinaryOperator equals = AlgebraicUtil.findTopExpr(resultExpr, OpType.Equals); |
| assertNotNull(equals); |
| |
| ColumnReferenceExpr column = equals.getLeft(); |
| assertEquals("default.region", column.getQualifier()); |
| assertEquals("r_name", column.getName()); |
| |
| LiteralValue literalValue = equals.getRight(); |
| assertEquals("EUROPE", literalValue.getValue()); |
| assertEquals(LiteralValue.LiteralType.String, literalValue.getValueType()); |
| } |
| |
| @Test |
| public final void testBinaryOperator3() throws CloneNotSupportedException, TajoException { |
| QueryContext qc = createQueryContext(); |
| |
| Expr expr = sqlAnalyzer.parse(QUERIES[2]); |
| |
| LogicalPlan plan = planner.createPlan(qc, expr); |
| LogicalOptimizer optimizer = new LogicalOptimizer(util.getConfiguration(), catalog, TablespaceManager.getInstance()); |
| optimizer.optimize(plan); |
| |
| LogicalNode node = plan.getRootBlock().getRoot(); |
| ScanNode scanNode = PlannerUtil.findTopNode(node, NodeType.SCAN); |
| |
| EvalNodeToExprConverter convertor = new EvalNodeToExprConverter(scanNode.getTableName()); |
| convertor.visit(null, scanNode.getQual(), new Stack<>()); |
| |
| Expr resultExpr = convertor.getResult(); |
| |
| BinaryOperator greaterThanOrEquals = AlgebraicUtil.findTopExpr(resultExpr, OpType.GreaterThanOrEquals); |
| assertNotNull(greaterThanOrEquals); |
| |
| ColumnReferenceExpr greaterThanOrEqualsLeft = greaterThanOrEquals.getLeft(); |
| assertEquals("default.lineitem", greaterThanOrEqualsLeft.getQualifier()); |
| assertEquals("l_discount", greaterThanOrEqualsLeft.getName()); |
| |
| LiteralValue greaterThanOrEqualsRight = greaterThanOrEquals.getRight(); |
| assertEquals("0.05", greaterThanOrEqualsRight.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Float, greaterThanOrEqualsRight.getValueType()); |
| |
| BinaryOperator lessThanOrEquals = AlgebraicUtil.findTopExpr(resultExpr, OpType.LessThanOrEquals); |
| assertNotNull(lessThanOrEquals); |
| |
| ColumnReferenceExpr lessThanOrEqualsLeft = lessThanOrEquals.getLeft(); |
| assertEquals("default.lineitem", lessThanOrEqualsLeft.getQualifier()); |
| assertEquals("l_discount", lessThanOrEqualsLeft.getName()); |
| |
| LiteralValue lessThanOrEqualsRight = lessThanOrEquals.getRight(); |
| assertEquals("0.07", lessThanOrEqualsRight.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Float, lessThanOrEqualsRight.getValueType()); |
| |
| BinaryOperator lessThan = AlgebraicUtil.findTopExpr(resultExpr, OpType.LessThan); |
| assertNotNull(lessThan); |
| |
| ColumnReferenceExpr lessThanLeft = lessThan.getLeft(); |
| assertEquals("default.lineitem", lessThanLeft.getQualifier()); |
| assertEquals("l_quantity", lessThanLeft.getName()); |
| |
| LiteralValue lessThanRight = lessThan.getRight(); |
| assertEquals("24.0", lessThanRight.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Float, lessThanRight.getValueType()); |
| |
| BinaryOperator leftExpr = new BinaryOperator(OpType.And, greaterThanOrEquals, lessThanOrEquals); |
| |
| BinaryOperator topExpr = AlgebraicUtil.findTopExpr(resultExpr, OpType.Or); |
| assertEquals(leftExpr, topExpr.getLeft()); |
| assertEquals(lessThan, topExpr.getRight()); |
| } |
| |
| @Test |
| public final void testBetweenPredicate() throws CloneNotSupportedException, TajoException { |
| QueryContext qc = createQueryContext(); |
| |
| Expr expr = sqlAnalyzer.parse(QUERIES[3]); |
| |
| LogicalPlan plan = planner.createPlan(qc, expr); |
| LogicalOptimizer optimizer = new LogicalOptimizer(util.getConfiguration(), catalog, TablespaceManager.getInstance()); |
| optimizer.optimize(plan); |
| |
| LogicalNode node = plan.getRootBlock().getRoot(); |
| ScanNode scanNode = PlannerUtil.findTopNode(node, NodeType.SCAN); |
| |
| EvalNodeToExprConverter convertor = new EvalNodeToExprConverter(scanNode.getTableName()); |
| convertor.visit(null, scanNode.getQual(), new Stack<>()); |
| |
| Expr resultExpr = convertor.getResult(); |
| |
| BinaryOperator binaryOperator = AlgebraicUtil.findTopExpr(resultExpr, OpType.LessThan); |
| assertNotNull(binaryOperator); |
| ColumnReferenceExpr column = binaryOperator.getLeft(); |
| assertEquals("default.lineitem", column.getQualifier()); |
| assertEquals("l_orderkey", column.getName()); |
| |
| LiteralValue literalValue = binaryOperator.getRight(); |
| assertEquals("24", literalValue.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Integer, literalValue.getValueType()); |
| |
| BetweenPredicate between = AlgebraicUtil.findTopExpr(resultExpr, OpType.Between); |
| assertFalse(between.isNot()); |
| assertFalse(between.isSymmetric()); |
| |
| ColumnReferenceExpr predicand = (ColumnReferenceExpr)between.predicand(); |
| assertEquals("default.lineitem", predicand.getQualifier()); |
| assertEquals("l_discount", predicand.getName()); |
| |
| BinaryOperator begin = (BinaryOperator)between.begin(); |
| assertEquals(OpType.Minus, begin.getType()); |
| LiteralValue left = begin.getLeft(); |
| assertEquals("0.06", left.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Float, left.getValueType()); |
| LiteralValue right = begin.getRight(); |
| assertEquals("0.01", right.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Float, right.getValueType()); |
| |
| BinaryOperator end = (BinaryOperator)between.end(); |
| assertEquals(OpType.Plus, end.getType()); |
| left = end.getLeft(); |
| assertEquals("0.08", left.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Float, left.getValueType()); |
| right = end.getRight(); |
| assertEquals("0.02", right.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Float, right.getValueType()); |
| } |
| |
| @Test |
| public final void testCaseWhenPredicate() throws CloneNotSupportedException, TajoException { |
| QueryContext qc = createQueryContext(); |
| |
| Expr expr = sqlAnalyzer.parse(QUERIES[4]); |
| |
| LogicalPlan plan = planner.createPlan(qc, expr); |
| LogicalOptimizer optimizer = new LogicalOptimizer(util.getConfiguration(), catalog, TablespaceManager.getInstance()); |
| optimizer.optimize(plan); |
| |
| LogicalNode node = plan.getRootBlock().getRoot(); |
| ScanNode scanNode = PlannerUtil.findTopNode(node, NodeType.SCAN); |
| |
| EvalNodeToExprConverter convertor = new EvalNodeToExprConverter(scanNode.getTableName()); |
| convertor.visit(null, scanNode.getQual(), new Stack<>()); |
| |
| Expr resultExpr = convertor.getResult(); |
| |
| CaseWhenPredicate caseWhen = AlgebraicUtil.findTopExpr(resultExpr, OpType.CaseWhen); |
| assertNotNull(caseWhen); |
| |
| CaseWhenPredicate.WhenExpr[] whenExprs = new CaseWhenPredicate.WhenExpr[1]; |
| caseWhen.getWhens().toArray(whenExprs); |
| |
| BinaryOperator condition = (BinaryOperator) whenExprs[0].getCondition(); |
| assertEquals(OpType.GreaterThan, condition.getType()); |
| |
| ColumnReferenceExpr conditionLeft = condition.getLeft(); |
| assertEquals("default.lineitem", conditionLeft.getQualifier()); |
| assertEquals("l_discount", conditionLeft.getName()); |
| |
| LiteralValue conditionRight = condition.getRight(); |
| assertEquals("0.0", conditionRight.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Float, conditionRight.getValueType()); |
| |
| BinaryOperator result = (BinaryOperator) whenExprs[0].getResult(); |
| assertEquals(OpType.Divide, result.getType()); |
| ColumnReferenceExpr resultLeft = result.getLeft(); |
| assertEquals("default.lineitem", resultLeft.getQualifier()); |
| assertEquals("l_discount", resultLeft.getName()); |
| |
| ColumnReferenceExpr resultRight = result.getRight(); |
| assertEquals("default.lineitem", resultRight.getQualifier()); |
| assertEquals("l_tax", resultRight.getName()); |
| |
| BinaryOperator greaterThan = AlgebraicUtil.findMostBottomExpr(resultExpr, OpType.GreaterThan); |
| assertNotNull(greaterThan); |
| |
| assertEquals(greaterThan.getLeft(), caseWhen); |
| |
| LiteralValue binaryOperatorRight = greaterThan.getRight(); |
| assertEquals("1.2", binaryOperatorRight.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Float, conditionRight.getValueType()); |
| } |
| |
| @Test |
| public final void testThreeFilters() throws CloneNotSupportedException, TajoException { |
| QueryContext qc = createQueryContext(); |
| |
| Expr expr = sqlAnalyzer.parse(QUERIES[5]); |
| |
| LogicalPlan plan = planner.createPlan(qc, expr); |
| LogicalOptimizer optimizer = new LogicalOptimizer(util.getConfiguration(), catalog, TablespaceManager.getInstance()); |
| optimizer.optimize(plan); |
| |
| LogicalNode node = plan.getRootBlock().getRoot(); |
| ScanNode scanNode = PlannerUtil.findTopNode(node, NodeType.SCAN); |
| |
| EvalNodeToExprConverter convertor = new EvalNodeToExprConverter(scanNode.getTableName()); |
| convertor.visit(null, scanNode.getQual(), new Stack<>()); |
| |
| Expr resultExpr = convertor.getResult(); |
| |
| BetweenPredicate between = AlgebraicUtil.findTopExpr(resultExpr, OpType.Between); |
| assertFalse(between.isNot()); |
| assertFalse(between.isSymmetric()); |
| |
| ColumnReferenceExpr predicand = (ColumnReferenceExpr)between.predicand(); |
| assertEquals("default.part", predicand.getQualifier()); |
| assertEquals("p_size", predicand.getName()); |
| |
| LiteralValue begin = (LiteralValue)between.begin(); |
| assertEquals("1", begin.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Integer, begin.getValueType()); |
| |
| LiteralValue end = (LiteralValue)between.end(); |
| assertEquals("10", end.getValue()); |
| assertEquals(LiteralValue.LiteralType.Unsigned_Integer, end.getValueType()); |
| |
| BinaryOperator equals = AlgebraicUtil.findTopExpr(resultExpr, OpType.Equals); |
| assertNotNull(equals); |
| |
| ColumnReferenceExpr equalsLeft = equals.getLeft(); |
| assertEquals("default.part", equalsLeft.getQualifier()); |
| assertEquals("p_brand", equalsLeft.getName()); |
| |
| LiteralValue equalsRight = equals.getRight(); |
| assertEquals("Brand#23", equalsRight.getValue()); |
| assertEquals(LiteralValue.LiteralType.String, equalsRight.getValueType()); |
| |
| InPredicate inPredicate = AlgebraicUtil.findTopExpr(resultExpr, OpType.InPredicate); |
| assertNotNull(inPredicate); |
| |
| ValueListExpr valueList = (ValueListExpr)inPredicate.getInValue(); |
| assertEquals(4, valueList.getValues().length); |
| for(int i = 0; i < valueList.getValues().length; i++) { |
| LiteralValue literalValue = (LiteralValue) valueList.getValues()[i]; |
| |
| if (i == 0) { |
| assertEquals("MED BAG", literalValue.getValue()); |
| } else if (i == 1) { |
| assertEquals("MED BOX", literalValue.getValue()); |
| } else if (i == 2) { |
| assertEquals("MED PKG", literalValue.getValue()); |
| } else { |
| assertEquals("MED PACK", literalValue.getValue()); |
| } |
| } |
| } |
| } |