/** * 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 com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.apache.tajo.TajoTestingCluster; import org.apache.tajo.algebra.Expr; import org.apache.tajo.algebra.JoinType; import org.apache.tajo.benchmark.TPCH; import org.apache.tajo.catalog.*; import org.apache.tajo.catalog.proto.CatalogProtos.FunctionType; import org.apache.tajo.catalog.proto.CatalogProtos.StoreType; import org.apache.tajo.common.TajoDataTypes.Type; import org.apache.tajo.engine.eval.EvalType; import org.apache.tajo.engine.function.builtin.SumInt; import org.apache.tajo.engine.json.CoreGsonHelper; import org.apache.tajo.engine.parser.SQLAnalyzer; import org.apache.tajo.engine.planner.logical.*; import org.apache.tajo.master.TajoMaster; import org.apache.tajo.util.CommonTestingUtil; import org.apache.tajo.util.FileUtil; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import java.io.File; import java.io.IOException; import java.util.*; import static org.junit.Assert.*; public class TestLogicalPlanner { private static TajoTestingCluster util; private static CatalogService catalog; private static SQLAnalyzer sqlAnalyzer; private static LogicalPlanner planner; private static TPCH tpch; @BeforeClass public static void setUp() throws Exception { util = new TajoTestingCluster(); util.startCatalogCluster(); catalog = util.getMiniCatalogCluster().getCatalog(); for (FunctionDesc funcDesc : TajoMaster.initBuiltinFunctions()) { catalog.createFunction(funcDesc); } Schema schema = new Schema(); schema.addColumn("name", Type.TEXT); schema.addColumn("empid", Type.INT4); schema.addColumn("deptname", Type.TEXT); Schema schema2 = new Schema(); schema2.addColumn("deptname", Type.TEXT); schema2.addColumn("manager", Type.TEXT); Schema schema3 = new Schema(); schema3.addColumn("deptname", Type.TEXT); schema3.addColumn("score", Type.INT4); TableMeta meta = CatalogUtil.newTableMeta(StoreType.CSV); TableDesc people = new TableDesc("employee", schema, meta, CommonTestingUtil.getTestDir()); catalog.addTable(people); TableDesc student = new TableDesc("dept", schema2, StoreType.CSV, new Options(), CommonTestingUtil.getTestDir()); catalog.addTable(student); TableDesc score = new TableDesc("score", schema3, StoreType.CSV, new Options(), CommonTestingUtil.getTestDir()); catalog.addTable(score); FunctionDesc funcDesc = new FunctionDesc("sumtest", SumInt.class, FunctionType.AGGREGATION, CatalogUtil.newSimpleDataType(Type.INT4), CatalogUtil.newSimpleDataTypeArray(Type.INT4)); // 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(StoreType.CSV); TableDesc d = CatalogUtil.newTableDesc(table, tpch.getSchema(table), m, CommonTestingUtil.getTestDir()); catalog.addTable(d); } catalog.createFunction(funcDesc); sqlAnalyzer = new SQLAnalyzer(); planner = new LogicalPlanner(catalog); } @AfterClass public static void tearDown() throws Exception { util.shutdownCatalogCluster(); } static String[] QUERIES = { "select name, empid, deptname from employee where empId > 500", // 0 "select name, empid, e.deptname, manager from employee as e, dept as dp", // 1 "select name, empid, e.deptname, manager, score from employee as e, dept, score", // 2 "select p.deptname, sumtest(score) from dept as p, score group by p.deptName having sumtest(score) > 30", // 3 "select p.deptname, score from dept as p, score order by score asc", // 4 "select name from employee where empId = 100", // 5 "select name, score from employee, score", // 6 "select p.deptName, sumtest(score) from dept as p, score group by p.deptName", // 7 "create table store1 as select p.deptName, sumtest(score) from dept as p, score group by p.deptName", // 8 "select deptName, sumtest(score) from score group by deptName having sumtest(score) > 30", // 9 "select 7 + 8 as res1, 8 * 9 as res2, 10 * 10 as res3", // 10 "create index idx_employee on employee using bitmap (name null first, empId desc) with ('fillfactor' = 70)", // 11 "select name, score from employee, score order by score limit 3", // 12 "select length(name), length(deptname), *, empid+10 from employee where empId > 500", // 13 }; @Test public final void testSingleRelation() throws CloneNotSupportedException, PlanningException { Expr expr = sqlAnalyzer.parse(QUERIES[0]); LogicalPlan planNode = planner.createPlan(expr); LogicalNode plan = planNode.getRootBlock().getRoot(); assertEquals(NodeType.ROOT, plan.getType()); TestLogicalNode.testCloneLogicalNode(plan); LogicalRootNode root = (LogicalRootNode) plan; testJsonSerDerObject(root); assertEquals(NodeType.PROJECTION, root.getChild().getType()); ProjectionNode projNode = root.getChild(); assertEquals(NodeType.SELECTION, projNode.getChild().getType()); SelectionNode selNode = projNode.getChild(); assertEquals(NodeType.SCAN, selNode.getChild().getType()); ScanNode scanNode = selNode.getChild(); assertEquals("employee", scanNode.getTableName()); } public static void assertSchema(Schema expected, Schema schema) { Column expectedColumn; Column column; for (int i = 0; i < expected.size(); i++) { expectedColumn = expected.getColumn(i); column = schema.getColumn(expectedColumn.getSimpleName()); assertEquals(expectedColumn.getSimpleName(), column.getSimpleName()); assertEquals(expectedColumn.getDataType(), column.getDataType()); } } @Test public final void testImplicityJoinPlan() throws CloneNotSupportedException, PlanningException { // two relations Expr expr = sqlAnalyzer.parse(QUERIES[1]); LogicalPlan planNode = planner.createPlan(expr); LogicalNode plan = planNode.getRootBlock().getRoot(); assertEquals(NodeType.ROOT, plan.getType()); LogicalRootNode root = (LogicalRootNode) plan; testJsonSerDerObject(root); TestLogicalNode.testCloneLogicalNode(root); Schema expectedSchema = new Schema(); expectedSchema.addColumn("name", Type.TEXT); expectedSchema.addColumn("empid", Type.INT4); expectedSchema.addColumn("deptname", Type.TEXT); expectedSchema.addColumn("manager", Type.TEXT); for (int i = 0; i < expectedSchema.size(); i++) { Column found = root.getOutSchema().getColumn(expectedSchema.getColumn(i).getSimpleName()); assertEquals(expectedSchema.getColumn(i).getDataType(), found.getDataType()); } assertEquals(NodeType.PROJECTION, root.getChild().getType()); ProjectionNode projNode = root.getChild(); assertEquals(NodeType.JOIN, projNode.getChild().getType()); JoinNode joinNode = projNode.getChild(); assertEquals(NodeType.SCAN, joinNode.getLeftChild().getType()); ScanNode leftNode = joinNode.getLeftChild(); assertEquals("employee", leftNode.getTableName()); assertEquals(NodeType.SCAN, joinNode.getRightChild().getType()); ScanNode rightNode = joinNode.getRightChild(); assertEquals("dept", rightNode.getTableName()); // three relations expr = sqlAnalyzer.parse(QUERIES[2]); plan = planner.createPlan(expr).getRootBlock().getRoot(); testJsonSerDerObject(plan); TestLogicalNode.testCloneLogicalNode(plan); expectedSchema.addColumn("score", Type.INT4); assertSchema(expectedSchema, plan.getOutSchema()); assertEquals(NodeType.ROOT, plan.getType()); root = (LogicalRootNode) plan; assertEquals(NodeType.PROJECTION, root.getChild().getType()); projNode = root.getChild(); assertEquals(NodeType.JOIN, projNode.getChild().getType()); joinNode = projNode.getChild(); assertEquals(NodeType.JOIN, joinNode.getLeftChild().getType()); assertEquals(NodeType.SCAN, joinNode.getRightChild().getType()); ScanNode scan1 = joinNode.getRightChild(); assertEquals("score", scan1.getTableName()); JoinNode leftNode2 = joinNode.getLeftChild(); assertEquals(NodeType.JOIN, leftNode2.getType()); assertEquals(NodeType.SCAN, leftNode2.getLeftChild().getType()); ScanNode leftScan = leftNode2.getLeftChild(); assertEquals("employee", leftScan.getTableName()); assertEquals(NodeType.SCAN, leftNode2.getRightChild().getType()); ScanNode rightScan = leftNode2.getRightChild(); assertEquals("dept", rightScan.getTableName()); } String [] JOINS = { "select name, dept.deptName, score from employee natural join dept natural join score", // 0 "select name, dept.deptName, score from employee inner join dept on employee.deptName = dept.deptName inner join score on dept.deptName = score.deptName", // 1 "select name, dept.deptName, score from employee left outer join dept on employee.deptName = dept.deptName right outer join score on dept.deptName = score.deptName" // 2 }; static Schema expectedJoinSchema; static { expectedJoinSchema = new Schema(); expectedJoinSchema.addColumn("name", Type.TEXT); expectedJoinSchema.addColumn("deptName", Type.TEXT); expectedJoinSchema.addColumn("score", Type.INT4); } @Test public final void testNaturalJoinPlan() throws PlanningException { // two relations Expr context = sqlAnalyzer.parse(JOINS[0]); LogicalNode plan = planner.createPlan(context).getRootBlock().getRoot(); testJsonSerDerObject(plan); assertSchema(expectedJoinSchema, plan.getOutSchema()); assertEquals(NodeType.ROOT, plan.getType()); LogicalRootNode root = (LogicalRootNode) plan; assertEquals(NodeType.PROJECTION, root.getChild().getType()); ProjectionNode proj = root.getChild(); assertEquals(NodeType.JOIN, proj.getChild().getType()); JoinNode join = proj.getChild(); assertEquals(JoinType.INNER, join.getJoinType()); assertEquals(NodeType.SCAN, join.getRightChild().getType()); assertTrue(join.hasJoinQual()); ScanNode scan = join.getRightChild(); assertEquals("score", scan.getTableName()); assertEquals(NodeType.JOIN, join.getLeftChild().getType()); join = join.getLeftChild(); assertEquals(JoinType.INNER, join.getJoinType()); assertEquals(NodeType.SCAN, join.getLeftChild().getType()); ScanNode outer = join.getLeftChild(); assertEquals("employee", outer.getTableName()); assertEquals(NodeType.SCAN, join.getRightChild().getType()); ScanNode inner = join.getRightChild(); assertEquals("dept", inner.getTableName()); } @Test public final void testInnerJoinPlan() throws PlanningException { // two relations Expr expr = sqlAnalyzer.parse(JOINS[1]); LogicalPlan plan = planner.createPlan(expr); LogicalNode root = plan.getRootBlock().getRoot(); testJsonSerDerObject(root); assertSchema(expectedJoinSchema, root.getOutSchema()); assertEquals(NodeType.ROOT, root.getType()); assertEquals(NodeType.PROJECTION, ((LogicalRootNode)root).getChild().getType()); ProjectionNode proj = ((LogicalRootNode)root).getChild(); assertEquals(NodeType.JOIN, proj.getChild().getType()); JoinNode join = proj.getChild(); assertEquals(JoinType.INNER, join.getJoinType()); assertEquals(NodeType.SCAN, join.getRightChild().getType()); ScanNode scan = join.getRightChild(); assertEquals("score", scan.getTableName()); assertEquals(NodeType.JOIN, join.getLeftChild().getType()); join = join.getLeftChild(); assertEquals(JoinType.INNER, join.getJoinType()); assertEquals(NodeType.SCAN, join.getLeftChild().getType()); ScanNode outer = join.getLeftChild(); assertEquals("employee", outer.getTableName()); assertEquals(NodeType.SCAN, join.getRightChild().getType()); ScanNode inner = join.getRightChild(); assertEquals("dept", inner.getTableName()); assertTrue(join.hasJoinQual()); assertEquals(EvalType.EQUAL, join.getJoinQual().getType()); } @Test public final void testOuterJoinPlan() throws PlanningException { // two relations Expr expr = sqlAnalyzer.parse(JOINS[2]); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); testJsonSerDerObject(plan); assertSchema(expectedJoinSchema, plan.getOutSchema()); assertEquals(NodeType.ROOT, plan.getType()); LogicalRootNode root = (LogicalRootNode) plan; assertEquals(NodeType.PROJECTION, root.getChild().getType()); ProjectionNode proj = root.getChild(); assertEquals(NodeType.JOIN, proj.getChild().getType()); JoinNode join = proj.getChild(); assertEquals(JoinType.RIGHT_OUTER, join.getJoinType()); assertEquals(NodeType.SCAN, join.getRightChild().getType()); ScanNode scan = join.getRightChild(); assertEquals("score", scan.getTableName()); assertEquals(NodeType.JOIN, join.getLeftChild().getType()); join = join.getLeftChild(); assertEquals(JoinType.LEFT_OUTER, join.getJoinType()); assertEquals(NodeType.SCAN, join.getLeftChild().getType()); ScanNode outer = join.getLeftChild(); assertEquals("employee", outer.getTableName()); assertEquals(NodeType.SCAN, join.getRightChild().getType()); ScanNode inner = join.getRightChild(); assertEquals("dept", inner.getTableName()); assertTrue(join.hasJoinQual()); assertEquals(EvalType.EQUAL, join.getJoinQual().getType()); } @Test public final void testGroupby() throws CloneNotSupportedException, PlanningException { // without 'having clause' Expr context = sqlAnalyzer.parse(QUERIES[7]); LogicalNode plan = planner.createPlan(context).getRootBlock().getRoot(); assertEquals(NodeType.ROOT, plan.getType()); LogicalRootNode root = (LogicalRootNode) plan; testJsonSerDerObject(root); testQuery7(root.getChild()); // with having clause context = sqlAnalyzer.parse(QUERIES[3]); plan = planner.createPlan(context).getRootBlock().getRoot(); TestLogicalNode.testCloneLogicalNode(plan); assertEquals(NodeType.ROOT, plan.getType()); root = (LogicalRootNode) plan; assertEquals(NodeType.PROJECTION, root.getChild().getType()); ProjectionNode projNode = root.getChild(); assertEquals(NodeType.HAVING, projNode.getChild().getType()); HavingNode havingNode = projNode.getChild(); assertEquals(NodeType.GROUP_BY, havingNode.getChild().getType()); GroupbyNode groupByNode = havingNode.getChild(); assertEquals(NodeType.JOIN, groupByNode.getChild().getType()); JoinNode joinNode = groupByNode.getChild(); assertEquals(NodeType.SCAN, joinNode.getLeftChild().getType()); ScanNode leftNode = joinNode.getLeftChild(); assertEquals("dept", leftNode.getTableName()); assertEquals(NodeType.SCAN, joinNode.getRightChild().getType()); ScanNode rightNode = joinNode.getRightChild(); assertEquals("score", rightNode.getTableName()); //LogicalOptimizer.optimize(context, plan); } @Test public final void testMultipleJoin() throws IOException, PlanningException { Expr expr = sqlAnalyzer.parse( FileUtil.readTextFile(new File("src/test/resources/queries/TestJoinQuery/testTPCHQ2Join.sql"))); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); testJsonSerDerObject(plan); Schema expected = tpch.getOutSchema("q2"); assertSchema(expected, plan.getOutSchema()); } static void testQuery7(LogicalNode plan) { assertEquals(NodeType.PROJECTION, plan.getType()); ProjectionNode projNode = (ProjectionNode) plan; assertEquals(NodeType.GROUP_BY, projNode.getChild().getType()); GroupbyNode groupByNode = projNode.getChild(); assertEquals(NodeType.JOIN, groupByNode.getChild().getType()); JoinNode joinNode = groupByNode.getChild(); assertEquals(NodeType.SCAN, joinNode.getLeftChild().getType()); ScanNode leftNode = joinNode.getLeftChild(); assertEquals("dept", leftNode.getTableName()); assertEquals(NodeType.SCAN, joinNode.getRightChild().getType()); ScanNode rightNode = joinNode.getRightChild(); assertEquals("score", rightNode.getTableName()); } @Test public final void testStoreTable() throws CloneNotSupportedException, PlanningException { Expr context = sqlAnalyzer.parse(QUERIES[8]); LogicalNode plan = planner.createPlan(context).getRootBlock().getRoot(); TestLogicalNode.testCloneLogicalNode(plan); testJsonSerDerObject(plan); assertEquals(NodeType.ROOT, plan.getType()); LogicalRootNode root = (LogicalRootNode) plan; assertEquals(NodeType.CREATE_TABLE, root.getChild().getType()); StoreTableNode storeNode = root.getChild(); testQuery7(storeNode.getChild()); } @Test public final void testOrderBy() throws CloneNotSupportedException, PlanningException { Expr expr = sqlAnalyzer.parse(QUERIES[4]); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); testJsonSerDerObject(plan); TestLogicalNode.testCloneLogicalNode(plan); assertEquals(NodeType.ROOT, plan.getType()); LogicalRootNode root = (LogicalRootNode) plan; assertEquals(NodeType.PROJECTION, root.getChild().getType()); ProjectionNode projNode = root.getChild(); assertEquals(NodeType.SORT, projNode.getChild().getType()); SortNode sortNode = projNode.getChild(); assertEquals(NodeType.JOIN, sortNode.getChild().getType()); JoinNode joinNode = sortNode.getChild(); assertEquals(NodeType.SCAN, joinNode.getLeftChild().getType()); ScanNode leftNode = joinNode.getLeftChild(); assertEquals("dept", leftNode.getTableName()); assertEquals(NodeType.SCAN, joinNode.getRightChild().getType()); ScanNode rightNode = joinNode.getRightChild(); assertEquals("score", rightNode.getTableName()); } @Test public final void testLimit() throws CloneNotSupportedException, PlanningException { Expr expr = sqlAnalyzer.parse(QUERIES[12]); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); testJsonSerDerObject(plan); TestLogicalNode.testCloneLogicalNode(plan); assertEquals(NodeType.ROOT, plan.getType()); LogicalRootNode root = (LogicalRootNode) plan; assertEquals(NodeType.PROJECTION, root.getChild().getType()); ProjectionNode projNode = root.getChild(); assertEquals(NodeType.LIMIT, projNode.getChild().getType()); LimitNode limitNode = projNode.getChild(); assertEquals(NodeType.SORT, limitNode.getChild().getType()); } @Test public final void testSPJPush() throws CloneNotSupportedException, PlanningException { Expr expr = sqlAnalyzer.parse(QUERIES[5]); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); testJsonSerDerObject(plan); TestLogicalNode.testCloneLogicalNode(plan); assertEquals(NodeType.ROOT, plan.getType()); LogicalRootNode root = (LogicalRootNode) plan; assertEquals(NodeType.PROJECTION, root.getChild().getType()); ProjectionNode projNode = root.getChild(); assertEquals(NodeType.SELECTION, projNode.getChild().getType()); SelectionNode selNode = projNode.getChild(); assertEquals(NodeType.SCAN, selNode.getChild().getType()); ScanNode scanNode = selNode.getChild(); assertEquals(scanNode.getTableName(), "employee"); } @Test public final void testSPJ() throws CloneNotSupportedException, PlanningException { Expr expr = sqlAnalyzer.parse(QUERIES[6]); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); testJsonSerDerObject(plan); TestLogicalNode.testCloneLogicalNode(plan); } @Test public final void testJson() throws PlanningException { Expr expr = sqlAnalyzer.parse(QUERIES[9]); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); testJsonSerDerObject(plan); String json = plan.toJson(); LogicalNode fromJson = CoreGsonHelper.fromJson(json, LogicalNode.class); assertEquals(NodeType.ROOT, fromJson.getType()); LogicalNode project = ((LogicalRootNode)fromJson).getChild(); assertEquals(NodeType.PROJECTION, project.getType()); assertEquals(NodeType.HAVING, ((ProjectionNode) project).getChild().getType()); HavingNode havingNode = ((ProjectionNode) project).getChild(); assertEquals(NodeType.GROUP_BY, havingNode.getChild().getType()); GroupbyNode groupbyNode = havingNode.getChild(); assertEquals(NodeType.SCAN, groupbyNode.getChild().getType()); LogicalNode scan = groupbyNode.getChild(); assertEquals(NodeType.SCAN, scan.getType()); } @Test public final void testVisitor() throws PlanningException { // two relations Expr expr = sqlAnalyzer.parse(QUERIES[1]); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); TestVisitor vis = new TestVisitor(); plan.postOrder(vis); assertEquals(NodeType.ROOT, vis.stack.pop().getType()); assertEquals(NodeType.PROJECTION, vis.stack.pop().getType()); assertEquals(NodeType.JOIN, vis.stack.pop().getType()); assertEquals(NodeType.SCAN, vis.stack.pop().getType()); assertEquals(NodeType.SCAN, vis.stack.pop().getType()); } private static class TestVisitor implements LogicalNodeVisitor { Stack<LogicalNode> stack = new Stack<LogicalNode>(); @Override public void visit(LogicalNode node) { stack.push(node); } } @Test public final void testExprNode() throws PlanningException { Expr expr = sqlAnalyzer.parse(QUERIES[10]); LogicalPlan rootNode = planner.createPlan(expr); LogicalNode plan = rootNode.getRootBlock().getRoot(); testJsonSerDerObject(plan); assertEquals(NodeType.ROOT, plan.getType()); LogicalRootNode root = (LogicalRootNode) plan; assertEquals(NodeType.EXPRS, root.getChild().getType()); Schema out = root.getOutSchema(); Iterator<Column> it = out.getColumns().iterator(); Column col = it.next(); assertEquals("res1", col.getSimpleName()); col = it.next(); assertEquals("res2", col.getSimpleName()); col = it.next(); assertEquals("res3", col.getSimpleName()); } @Test public final void testAsterisk() throws CloneNotSupportedException, PlanningException { Expr expr = sqlAnalyzer.parse(QUERIES[13]); LogicalPlan planNode = planner.createPlan(expr); LogicalNode plan = planNode.getRootBlock().getRoot(); assertEquals(NodeType.ROOT, plan.getType()); TestLogicalNode.testCloneLogicalNode(plan); LogicalRootNode root = (LogicalRootNode) plan; testJsonSerDerObject(root); assertEquals(NodeType.PROJECTION, root.getChild().getType()); ProjectionNode projNode = root.getChild(); assertEquals(6, projNode.getOutSchema().size()); assertEquals(NodeType.SELECTION, projNode.getChild().getType()); SelectionNode selNode = projNode.getChild(); assertEquals(NodeType.SCAN, selNode.getChild().getType()); ScanNode scanNode = selNode.getChild(); assertEquals("employee", scanNode.getTableName()); } static final String ALIAS [] = { "select deptName, sum(score) as total from score group by deptName", "select em.empId as id, sum(score) as total from employee as em inner join score using (em.deptName) group by id" }; @Test public final void testAlias1() throws PlanningException { Expr expr = sqlAnalyzer.parse(ALIAS[0]); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); LogicalRootNode root = (LogicalRootNode) plan; testJsonSerDerObject(root); Schema finalSchema = root.getOutSchema(); Iterator<Column> it = finalSchema.getColumns().iterator(); Column col = it.next(); assertEquals("deptname", col.getSimpleName()); col = it.next(); assertEquals("total", col.getSimpleName()); expr = sqlAnalyzer.parse(ALIAS[1]); plan = planner.createPlan(expr).getRootBlock().getRoot(); root = (LogicalRootNode) plan; finalSchema = root.getOutSchema(); it = finalSchema.getColumns().iterator(); col = it.next(); assertEquals("id", col.getSimpleName()); col = it.next(); assertEquals("total", col.getSimpleName()); } @Test public final void testAlias2() throws PlanningException { Expr expr = sqlAnalyzer.parse(ALIAS[1]); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); LogicalRootNode root = (LogicalRootNode) plan; testJsonSerDerObject(root); Schema finalSchema = root.getOutSchema(); Iterator<Column> it = finalSchema.getColumns().iterator(); Column col = it.next(); assertEquals("id", col.getSimpleName()); col = it.next(); assertEquals("total", col.getSimpleName()); } static final String CREATE_TABLE [] = { "create external table table1 (name text, age int, earn bigint, score real) using csv with ('csv.delimiter'='|') location '/tmp/data'" }; @Test public final void testCreateTableDef() throws PlanningException { Expr expr = sqlAnalyzer.parse(CREATE_TABLE[0]); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); LogicalRootNode root = (LogicalRootNode) plan; testJsonSerDerObject(root); assertEquals(NodeType.CREATE_TABLE, root.getChild().getType()); CreateTableNode createTable = root.getChild(); Schema def = createTable.getTableSchema(); assertEquals("name", def.getColumn(0).getSimpleName()); assertEquals(Type.TEXT, def.getColumn(0).getDataType().getType()); assertEquals("age", def.getColumn(1).getSimpleName()); assertEquals(Type.INT4, def.getColumn(1).getDataType().getType()); assertEquals("earn", def.getColumn(2).getSimpleName()); assertEquals(Type.INT8, def.getColumn(2).getDataType().getType()); assertEquals("score", def.getColumn(3).getSimpleName()); assertEquals(Type.FLOAT4, def.getColumn(3).getDataType().getType()); assertEquals(StoreType.CSV, createTable.getStorageType()); assertEquals("/tmp/data", createTable.getPath().toString()); assertTrue(createTable.hasOptions()); assertEquals("|", createTable.getOptions().get("csv.delimiter")); } private static final List<Set<Column>> testGenerateCuboidsResult = Lists.newArrayList(); private static final int numCubeColumns = 3; private static final Column [] testGenerateCuboids = new Column[numCubeColumns]; private static final List<Set<Column>> testCubeByResult = Lists.newArrayList(); private static final Column [] testCubeByCuboids = new Column[2]; static { testGenerateCuboids[0] = new Column("col1", Type.INT4); testGenerateCuboids[1] = new Column("col2", Type.INT8); testGenerateCuboids[2] = new Column("col3", Type.FLOAT4); testGenerateCuboidsResult.add(new HashSet<Column>()); testGenerateCuboidsResult.add(Sets.newHashSet(testGenerateCuboids[0])); testGenerateCuboidsResult.add(Sets.newHashSet(testGenerateCuboids[1])); testGenerateCuboidsResult.add(Sets.newHashSet(testGenerateCuboids[2])); testGenerateCuboidsResult.add(Sets.newHashSet(testGenerateCuboids[0], testGenerateCuboids[1])); testGenerateCuboidsResult.add(Sets.newHashSet(testGenerateCuboids[0], testGenerateCuboids[2])); testGenerateCuboidsResult.add(Sets.newHashSet(testGenerateCuboids[1], testGenerateCuboids[2])); testGenerateCuboidsResult.add(Sets.newHashSet(testGenerateCuboids[0], testGenerateCuboids[1], testGenerateCuboids[2])); testCubeByCuboids[0] = new Column("employee.name", Type.TEXT); testCubeByCuboids[1] = new Column("employee.empid", Type.INT4); testCubeByResult.add(new HashSet<Column>()); testCubeByResult.add(Sets.newHashSet(testCubeByCuboids[0])); testCubeByResult.add(Sets.newHashSet(testCubeByCuboids[1])); testCubeByResult.add(Sets.newHashSet(testCubeByCuboids[0], testCubeByCuboids[1])); } @Test public final void testGenerateCuboids() { Column [] columns = new Column[3]; columns[0] = new Column("col1", Type.INT4); columns[1] = new Column("col2", Type.INT8); columns[2] = new Column("col3", Type.FLOAT4); List<Column[]> cube = LogicalPlanner.generateCuboids(columns); assertEquals(((int)Math.pow(2, numCubeColumns)), cube.size()); Set<Set<Column>> cuboids = Sets.newHashSet(); for (Column [] cols : cube) { cuboids.add(Sets.newHashSet(cols)); } for (Set<Column> result : testGenerateCuboidsResult) { assertTrue(cuboids.contains(result)); } } static final String setStatements [] = { "select deptName from employee where deptName like 'data%' union select deptName from score where deptName like 'data%'", }; @Test public final void testSetPlan() throws PlanningException { Expr expr = sqlAnalyzer.parse(setStatements[0]); LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot(); testJsonSerDerObject(plan); assertEquals(NodeType.ROOT, plan.getType()); LogicalRootNode root = (LogicalRootNode) plan; assertEquals(NodeType.UNION, root.getChild().getType()); UnionNode union = root.getChild(); assertEquals(NodeType.PROJECTION, union.getLeftChild().getType()); assertEquals(NodeType.PROJECTION, union.getRightChild().getType()); } static final String [] setQualifiers = { "select name, empid from employee", "select distinct name, empid from employee", "select all name, empid from employee", }; @Test public void testSetQualifier() throws PlanningException { Expr context = sqlAnalyzer.parse(setQualifiers[0]); LogicalNode plan = planner.createPlan(context).getRootBlock().getRoot(); testJsonSerDerObject(plan); assertEquals(NodeType.ROOT, plan.getType()); LogicalRootNode root = (LogicalRootNode) plan; assertEquals(NodeType.PROJECTION, root.getChild().getType()); ProjectionNode projectionNode = root.getChild(); assertEquals(NodeType.SCAN, projectionNode.getChild().getType()); context = sqlAnalyzer.parse(setQualifiers[1]); plan = planner.createPlan(context).getRootBlock().getRoot(); testJsonSerDerObject(plan); assertEquals(NodeType.ROOT, plan.getType()); root = (LogicalRootNode) plan; assertEquals(NodeType.PROJECTION, root.getChild().getType()); projectionNode = root.getChild(); assertEquals(NodeType.GROUP_BY, projectionNode.getChild().getType()); context = sqlAnalyzer.parse(setQualifiers[2]); plan = planner.createPlan(context).getRootBlock().getRoot(); testJsonSerDerObject(plan); root = (LogicalRootNode) plan; assertEquals(NodeType.PROJECTION, root.getChild().getType()); projectionNode = root.getChild(); assertEquals(NodeType.SCAN, projectionNode.getChild().getType()); } public void testJsonSerDerObject(LogicalNode rootNode) { String json = rootNode.toJson(); LogicalNode fromJson = CoreGsonHelper.fromJson(json, LogicalNode.class); assertTrue("JSON (de) serialization equivalence check", rootNode.deepEquals(fromJson)); } // Table descriptions // // employee (name text, empid int4, deptname text) // dept (deptname text, nameger text) // score (deptname text, score inet4) static final String [] insertStatements = { "insert into score select name from employee", // 0 "insert into score select name, empid from employee", // 1 "insert into employee (name, deptname) select * from dept", // 2 "insert into location '/tmp/data' select name, empid from employee", // 3 "insert overwrite into employee (name, deptname) select * from dept", // 4 "insert overwrite into LOCATION '/tmp/data' select * from dept" // 5 }; @Test public final void testInsertInto0() throws PlanningException { Expr expr = sqlAnalyzer.parse(insertStatements[0]); LogicalPlan plan = planner.createPlan(expr); assertEquals(1, plan.getQueryBlocks().size()); InsertNode insertNode = getInsertNode(plan); assertFalse(insertNode.isOverwrite()); assertTrue(insertNode.hasTargetTable()); assertEquals("score", insertNode.getTableName()); } @Test public final void testInsertInto1() throws PlanningException { Expr expr = sqlAnalyzer.parse(insertStatements[1]); LogicalPlan plan = planner.createPlan(expr); assertEquals(1, plan.getQueryBlocks().size()); InsertNode insertNode = getInsertNode(plan); assertFalse(insertNode.isOverwrite()); assertEquals("score", insertNode.getTableName()); } @Test public final void testInsertInto2() throws PlanningException { Expr expr = sqlAnalyzer.parse(insertStatements[2]); LogicalPlan plan = planner.createPlan(expr); assertEquals(1, plan.getQueryBlocks().size()); InsertNode insertNode = getInsertNode(plan); assertFalse(insertNode.isOverwrite()); assertEquals("employee", insertNode.getTableName()); assertTrue(insertNode.hasTargetSchema()); assertEquals(insertNode.getTargetSchema().getColumn(0).getSimpleName(), "name"); assertEquals(insertNode.getTargetSchema().getColumn(1).getSimpleName(), "deptname"); } @Test public final void testInsertInto3() throws PlanningException { Expr expr = sqlAnalyzer.parse(insertStatements[3]); LogicalPlan plan = planner.createPlan(expr); assertEquals(1, plan.getQueryBlocks().size()); InsertNode insertNode = getInsertNode(plan); assertFalse(insertNode.isOverwrite()); assertTrue(insertNode.hasPath()); } @Test public final void testInsertInto4() throws PlanningException { Expr expr = sqlAnalyzer.parse(insertStatements[4]); LogicalPlan plan = planner.createPlan(expr); assertEquals(1, plan.getQueryBlocks().size()); InsertNode insertNode = getInsertNode(plan); assertTrue(insertNode.isOverwrite()); assertTrue(insertNode.hasTargetTable()); assertEquals("employee", insertNode.getTableName()); assertTrue(insertNode.hasTargetSchema()); assertEquals(insertNode.getTargetSchema().getColumn(0).getSimpleName(), "name"); assertEquals(insertNode.getTargetSchema().getColumn(1).getSimpleName(), "deptname"); } @Test public final void testInsertInto5() throws PlanningException { Expr expr = sqlAnalyzer.parse(insertStatements[5]); LogicalPlan plan = planner.createPlan(expr); assertEquals(1, plan.getQueryBlocks().size()); InsertNode insertNode = getInsertNode(plan); assertTrue(insertNode.isOverwrite()); assertTrue(insertNode.hasPath()); } private static InsertNode getInsertNode(LogicalPlan plan) { LogicalRootNode root = plan.getRootBlock().getRoot(); assertEquals(NodeType.INSERT, root.getChild().getType()); return root.getChild(); } }