http://git-wip-us.apache.org/repos/asf/tajo/blob/a4106883/tajo-core-tests/src/test/java/org/apache/tajo/client/v2/TestTajoClientV2.java ---------------------------------------------------------------------- diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/client/v2/TestTajoClientV2.java b/tajo-core-tests/src/test/java/org/apache/tajo/client/v2/TestTajoClientV2.java new file mode 100644 index 0000000..e1fca63 --- /dev/null +++ b/tajo-core-tests/src/test/java/org/apache/tajo/client/v2/TestTajoClientV2.java @@ -0,0 +1,274 @@ +/** + * 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.client.v2; + +import com.facebook.presto.hive.shaded.com.google.common.collect.Lists; +import org.apache.tajo.QueryTestCaseBase; +import org.apache.tajo.exception.*; +import org.apache.tajo.service.ServiceTracker; +import org.apache.tajo.service.ServiceTrackerFactory; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.junit.Assert.*; + +public class TestTajoClientV2 extends QueryTestCaseBase { + private static TajoClient clientv2; + + @BeforeClass + public static void setUp() throws Exception { + conf = testingCluster.getConfiguration(); + + clientv2 = new TajoClient(new ServiceDiscovery() { + ServiceTracker tracker = ServiceTrackerFactory.get(conf); + @Override + public InetSocketAddress clientAddress() { + return tracker.getClientServiceAddress(); + } + }); + } + + @AfterClass + public static void tearDown() throws Exception { + clientv2.close(); + } + + @Test + public void testExecuteUpdate() throws TajoException { + clientv2.executeUpdate("create database tajoclientv2"); + clientv2.selectDB("tajoclientv2"); + clientv2.selectDB("default"); + clientv2.executeUpdate("drop database tajoclientv2"); + + try { + clientv2.selectDB("tajoclientv2"); + fail(); + } catch (UndefinedDatabaseException e) { + } + } + + @Test + public void testExecuteQueryType1() throws TajoException, IOException, SQLException { + ResultSet res = null; + try { + res = clientv2.executeQuery("select * from lineitem"); + assertResultSet(res); + } finally { + if (res != null) { + res.close(); + } + } + } + + @Test + public void testExecuteQueryType2() throws TajoException, IOException, SQLException { + ResultSet res = null; + try { + res = clientv2.executeQuery("select * from lineitem where l_orderkey > 2"); + assertResultSet(res); + } finally { + if (res != null) { + res.close(); + } + } + } + + @Test + public void testExecuteQueryType3() throws TajoException, IOException, SQLException { + ResultSet res = null; + try { + clientv2.executeUpdate("create database client_v2_type3"); + clientv2.selectDB("client_v2_type3"); + clientv2.executeUpdate("create table t1 (c1 int)"); + clientv2.executeUpdate("create table t2 (c2 int)"); + + // why we shouldn't use join directly on virtual tables? Currently, join on virtual tables is not supported. + res = clientv2.executeQuery("select db_id from information_schema.databases where db_name = 'client_v2_type3'"); + assertTrue(res.next()); + int dbId = res.getInt(1); + res.close(); + + res = clientv2.executeQuery( + "select table_name from information_schema.tables where db_id = " + dbId + " order by table_name"); + assertResultSet(res); + } finally { + if (res != null) { + res.close(); + } + + clientv2.executeUpdate("drop database IF EXISTS client_v2_types3"); + } + } + + @Test + public void testExecuteQueryAsync() throws TajoException, IOException, SQLException, ExecutionException, + InterruptedException { + QueryFuture future = clientv2.executeQueryAsync("select * from lineitem where l_orderkey > 0"); + + ResultSet result = future.get(); + assertResultSet(result); + + assertTrue(future.isDone()); + assertEquals(QueryState.COMPLETED, future.state()); + assertTrue(future.isSuccessful()); + assertFalse(future.isFailed()); + assertFalse(future.isKilled()); + assertTrue(1.0f == future.progress()); + assertEquals("default", future.queue()); + + assertTrue(future.submitTime() > 0); + assertTrue(future.startTime() > 0); + assertTrue(future.finishTime() > 0); + + result.close(); + } + + @Test(timeout = 10 * 1000) + public void testExecuteQueryAsyncWithListener() throws TajoException, IOException, SQLException, ExecutionException, + InterruptedException { + QueryFuture future = clientv2.executeQueryAsync( + "select l_orderkey, sleep(1) from lineitem where l_orderkey > 3"); + + final AtomicBoolean success = new AtomicBoolean(false); + final List<ResultSet> resultContainer = Lists.newArrayList(); + + future.addListener(new FutureListener<QueryFuture>() { + @Override + public void processingCompleted(QueryFuture future) { + try { + ResultSet result = future.get(); + resultContainer.add(result); // for better error handling, it should be verified outside this future. + + assertTrue(future.isDone()); + assertEquals(QueryState.COMPLETED, future.state()); + assertTrue(future.isSuccessful()); + assertFalse(future.isFailed()); + assertFalse(future.isKilled()); + assertTrue(1.0f == future.progress()); + assertEquals("default", future.queue()); + + assertTrue(future.submitTime() > 0); + assertTrue(future.startTime() > 0); + assertTrue(future.finishTime() > 0); + + success.set(true); + + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + }); + + while(!future.isDone()) { + Thread.sleep(100); + } + + assertTrue(success.get()); + assertResultSet(resultContainer.get(0)); + resultContainer.get(0).close(); + } + + @Test(expected = QueryKilledException.class, timeout = 10 * 1000) + public void testQueryFutureKill() throws Throwable { + QueryFuture future = clientv2.executeQueryAsync("select sleep(1) from lineitem where l_orderkey > 4"); + + assertTrue(future.isOk()); + assertFalse(future.isDone()); + assertFalse(future.isSuccessful()); + assertFalse(future.isFailed()); + assertFalse(future.isKilled()); + + future.kill(); + while(!future.isDone()) { + Thread.sleep(100); + } + + assertTrue(future.isOk()); + assertTrue(future.isDone()); + assertFalse(future.isSuccessful()); + assertFalse(future.isFailed()); + assertTrue(future.isKilled()); + + try { + future.get(); + } catch (ExecutionException e) { + throw e.getCause(); + } finally { + future.release(); + } + } + + + @Test(expected = DuplicateDatabaseException.class) + public void testErrorOnExecuteUpdate() throws TajoException, IOException, SQLException { + clientv2.executeUpdate("create database default"); + } + + @Test(expected = UndefinedTableException.class) + public void testErrorOnExecuteQuery() throws TajoException, IOException, SQLException { + clientv2.executeQuery("select * from unknown_table"); + } + + @Test(expected = UndefinedTableException.class) + public void testErrorOnExecuteQueryAsync() throws TajoException { + clientv2.executeQueryAsync("select * from unknown_table"); + } + + @Test(expected = SQLSyntaxError.class) + public void testSyntaxErrorOnUpdateQuery() throws TajoException { + clientv2.executeUpdate("drap table unknown-table"); + } + + @Test(expected = SQLSyntaxError.class) + public void testSyntaxErrorOnExecuteQuery() throws TajoException { + clientv2.executeQuery("select fail(3, "); + } + + @Test(expected = SQLSyntaxError.class) + public void testSyntaxErrorOnExecuteQueryAsync() throws TajoException { + clientv2.executeQueryAsync("select fail(3, "); + } + + @Test(expected = QueryFailedException.class) + public void testFailedExecuteQuery() throws TajoException { + clientv2.executeQuery("select fail(3, l_orderkey, 'testQueryFailure') from default.lineitem"); + } + + @Test(expected = QueryFailedException.class) + public void testFailedExecuteQueryAsync() throws Throwable { + QueryFuture future = clientv2.executeQueryAsync( + "select fail(3, l_orderkey, 'testQueryFailure') from default.lineitem"); + try { + future.get(); + } catch (ExecutionException e) { + throw e.getCause(); + } finally { + future.release(); + } + } +}
http://git-wip-us.apache.org/repos/asf/tajo/blob/a4106883/tajo-core-tests/src/test/java/org/apache/tajo/cluster/TestWorkerConnectionInfo.java ---------------------------------------------------------------------- diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/cluster/TestWorkerConnectionInfo.java b/tajo-core-tests/src/test/java/org/apache/tajo/cluster/TestWorkerConnectionInfo.java new file mode 100644 index 0000000..03be125 --- /dev/null +++ b/tajo-core-tests/src/test/java/org/apache/tajo/cluster/TestWorkerConnectionInfo.java @@ -0,0 +1,36 @@ +/** + * 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.cluster; + +import org.apache.tajo.master.cluster.WorkerConnectionInfo; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class TestWorkerConnectionInfo { + + @Test + public void testWorkerId() { + WorkerConnectionInfo worker = new WorkerConnectionInfo("host", 28091, 28092, 21000, 28093, 28080); + WorkerConnectionInfo worker2 = new WorkerConnectionInfo("host2", 28091, 28092, 21000, 28093, 28080); + + assertNotEquals(worker.getId(), worker2.getId()); + assertEquals(worker.getId(), new WorkerConnectionInfo("host", 28091, 28092, 21000, 28093, 28080).getId()); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/a4106883/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestEvalCodeGenerator.java ---------------------------------------------------------------------- diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestEvalCodeGenerator.java b/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestEvalCodeGenerator.java new file mode 100644 index 0000000..da59e8a --- /dev/null +++ b/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestEvalCodeGenerator.java @@ -0,0 +1,310 @@ +/** + * 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.codegen; + + +import org.apache.tajo.catalog.CatalogUtil; +import org.apache.tajo.catalog.Schema; +import org.apache.tajo.common.TajoDataTypes; +import org.apache.tajo.engine.eval.ExprTestBase; +import org.apache.tajo.exception.TajoException; +import org.junit.Test; + +public class TestEvalCodeGenerator extends ExprTestBase { + private static Schema schema; + static { + schema = new Schema(); + schema.addColumn("col0", TajoDataTypes.Type.INT1); + schema.addColumn("col1", TajoDataTypes.Type.INT2); + schema.addColumn("col2", TajoDataTypes.Type.INT4); + schema.addColumn("col3", TajoDataTypes.Type.INT8); + schema.addColumn("col4", TajoDataTypes.Type.FLOAT4); + schema.addColumn("col5", TajoDataTypes.Type.FLOAT8); + schema.addColumn("col6", TajoDataTypes.Type.TEXT); + schema.addColumn("col7", CatalogUtil.newDataType(TajoDataTypes.Type.CHAR, "", 3)); + schema.addColumn("col8", TajoDataTypes.Type.BOOLEAN); + schema.addColumn("nullable", TajoDataTypes.Type.NULL_TYPE); + } + + @Test + public void testArithmetic() throws TajoException { + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1+1;", new String [] {"2"}); + testEval(schema, "table1", "0,1,2,3,4.5,5.5", "select col1 + col2 from table1;", new String [] {"3"}); + testEval(schema, "table1", "0,1,2,3,4.5,5.5", "select col1 + col3 from table1;", new String [] {"4"}); + testEval(schema, "table1", "0,1,2,3,4.5,5.5", "select col1 + col4 from table1;", new String [] {"5.5"}); + testEval(schema, "table1", "0,1,2,3,4.5,5.5", "select col1 + col5 from table1;", new String [] {"6.5"}); + } + + @Test + public void testGetField() throws TajoException { + testEval(schema, "table1", "0,1,2,3,4.5,5.5,F6", "select col1 from table1;", new String [] {"1"}); + testEval(schema, "table1", "0,1,2,3,4.5,5.5,F6", "select col2 from table1;", new String [] {"2"}); + testEval(schema, "table1", "0,1,2,3,4.5,5.5,F6", "select col3 from table1;", new String [] {"3"}); + testEval(schema, "table1", "0,1,2,3,4.5,5.5,F6", "select col4 from table1;", new String [] {"4.5"}); + testEval(schema, "table1", "0,1,2,3,4.5,5.5,F6", "select col5 from table1;", new String [] {"5.5"}); + testEval(schema, "table1", "0,1,2,3,4.5,5.5,F6", "select col6 from table1;", new String [] {"F6"}); + testEval(schema, "table1", "0,1,2,3,4.5,5.5,F6,abc,t", "select col8 from table1;", new String [] {"t"}); + } + + @Test + public void testNullHandling() throws TajoException { + schema = new Schema(); + schema.addColumn("col0", TajoDataTypes.Type.INT1); + schema.addColumn("col1", TajoDataTypes.Type.INT2); + schema.addColumn("col2", TajoDataTypes.Type.INT4); + schema.addColumn("col3", TajoDataTypes.Type.INT8); + schema.addColumn("col4", TajoDataTypes.Type.FLOAT4); + schema.addColumn("col5", TajoDataTypes.Type.FLOAT8); + schema.addColumn("col6", TajoDataTypes.Type.TEXT); + schema.addColumn("col7", CatalogUtil.newDataType(TajoDataTypes.Type.CHAR, "", 1)); + schema.addColumn("col8", CatalogUtil.newDataType(TajoDataTypes.Type.CHAR, "", 3)); + schema.addColumn("col9", TajoDataTypes.Type.BOOLEAN); + schema.addColumn("nullable", TajoDataTypes.Type.NULL_TYPE); + + testEval(schema, "table1", ",1,2,3,4.5,6.5,F6,abc,abc,t", "select col0 is null from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,,2,3,4.5,6.5,F6,abc,abc,t,", "select col1 is null from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,,3,4.5,6.5,F6,abc,abc,t,", "select col2 is null from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,,4.5,6.5,F6,abc,abc,t,", "select col3 is null from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,,6.5,F6,abc,abc,t,", "select col4 is null from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,,F6,abc,abc,t,", "select col5 is null from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5,,abc,abc,t,", "select col6 is null from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5,F6,,abc,t,", "select col7 is null from table1;", new String[]{"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5,F6,abc,,t,", "select col8 is null from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5,F6,abc,abc,,", "select col9 is null from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5,F6,abc,abc,t,", "select nullable is null from table1;", new String [] {"t"}); + + testEval(schema, "table1", ",1,2,3,4.5,6.5,F6,abc,abc,t", "select col0 is not null from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,,2,3,4.5,6.5,F6,abc,abc,t,", "select col1 is not null from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,,3,4.5,6.5,F6,abc,abc,t,", "select col2 is not null from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,,4.5,6.5,F6,abc,abc,t,", "select col3 is not null from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,,6.5,F6,abc,abc,t,", "select col4 is not null from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,,F6,abc,abc,t,", "select col5 is not null from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5,,abc,abc,t,", "select col6 is not null from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5,F6,,abc,t,", "select col7 is not null from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5,F6,abc,,t,", "select col8 is not null from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5,F6,abc,abc,,", "select col9 is not null from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5,F6,abc,abc,t,", "select nullable is not null from table1;", new String [] {"f"}); + } + + @Test + public void testComparison() throws TajoException { + Schema inetSchema = new Schema(); + inetSchema.addColumn("addr1", TajoDataTypes.Type.INET4); + inetSchema.addColumn("addr2", TajoDataTypes.Type.INET4); + + testSimpleEval("select (1 > null AND false)", new String[] {"f"}); // unknown - false -> false + testSimpleEval("select (1::int8 > null) is null", new String[] {"t"}); + + testSimpleEval("select 1 = null;", new String [] {""}); + testSimpleEval("select 1 <> null;", new String [] {""}); + testSimpleEval("select 1 > null;", new String [] {""}); + testSimpleEval("select 1 >= null;", new String [] {""}); + testSimpleEval("select 1 < null;", new String [] {""}); + testSimpleEval("select 1 <= null;", new String [] {""}); + + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 = col1 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 = col2 from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 = col3 from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 = col4 from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 = col5 from table1;", new String [] {"f"}); + + testEval(inetSchema, "table1", "192.168.0.1,192.168.0.1", "select addr1 = addr2 from table1;", new String[]{"t"}); + testEval(inetSchema, "table1", "192.168.0.1,192.168.0.2", "select addr1 = addr2 from table1;", new String[]{"f"}); + + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 <> col1 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 <> col2 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 <> col3 from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 <> col4 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 <> col5 from table1;", new String [] {"t"}); + + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 < col1 from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 < col2 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 < col3 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 < col4 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 1 < col5 from table1;", new String [] {"t"}); + + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 <= col1 from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 <= col2 from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 <= col3 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 <= col4 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 <= col5 from table1;", new String [] {"t"}); + + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 > col1 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 > col2 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 > col3 from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 > col4 from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 > col5 from table1;", new String [] {"f"}); + + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 >= col1 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 >= col2 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 >= col3 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 >= col4 from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 3 >= col5 from table1;", new String [] {"f"}); + } + + @Test + public void testBetweenAsymmetric() throws TajoException { + Schema schema = new Schema(); + schema.addColumn("col1", TajoDataTypes.Type.INT4); + schema.addColumn("col2", TajoDataTypes.Type.INT4); + testEval(schema, "table1", "0,", "select col1 between 1 and 3 from table1", new String[]{"f"}); + testEval(schema, "table1", "1,", "select col1 between 1 and 3 from table1", new String[]{"t"}); + testEval(schema, "table1", "2,", "select col1 between 1 and 3 from table1", new String[]{"t"}); + testEval(schema, "table1", "3,", "select col1 between 1 and 3 from table1", new String[]{"t"}); + testEval(schema, "table1", "4,", "select col1 between 1 and 3 from table1", new String[]{"f"}); + testEval(schema, "table1", "5,", "select (col2 between 1 and 3) is null from table1", new String[]{"t"}); + + testEval(schema, "table1", "0,", "select col1 between 3 and 1 from table1", new String[]{"f"}); + testEval(schema, "table1", "1,", "select col1 between 3 and 1 from table1", new String[]{"f"}); + testEval(schema, "table1", "2,", "select col1 between 3 and 1 from table1", new String[]{"f"}); + testEval(schema, "table1", "3,", "select col1 between 3 and 1 from table1", new String[]{"f"}); + testEval(schema, "table1", "4,", "select col1 between 3 and 1 from table1", new String[]{"f"}); + testEval(schema, "table1", "5,", "select (col2 between 3 and 1) is null from table1", new String[]{"t"}); + + testEval(schema, "table1", "0,", "select col1 not between 1 and 3 from table1", new String[]{"t"}); + testEval(schema, "table1", "1,", "select col1 not between 1 and 3 from table1", new String[]{"f"}); + testEval(schema, "table1", "2,", "select col1 not between 1 and 3 from table1", new String[]{"f"}); + testEval(schema, "table1", "3,", "select col1 not between 1 and 3 from table1", new String[]{"f"}); + testEval(schema, "table1", "4,", "select col1 not between 1 and 3 from table1", new String[]{"t"}); + testEval(schema, "table1", "5,", "select (col2 not between 1 and 3) is null from table1", new String[]{"t"}); + + testEval(schema, "table1", "0,", "select col1 not between 3 and 1 from table1", new String[]{"t"}); + testEval(schema, "table1", "1,", "select col1 not between 3 and 1 from table1", new String[]{"t"}); + testEval(schema, "table1", "2,", "select col1 not between 3 and 1 from table1", new String[]{"t"}); + testEval(schema, "table1", "3,", "select col1 not between 3 and 1 from table1", new String[]{"t"}); + testEval(schema, "table1", "4,", "select col1 not between 3 and 1 from table1", new String[]{"t"}); + testEval(schema, "table1", "5,", "select (col2 not between 3 and 1) is null from table1", new String[]{"t"}); + } + + @Test + public void testBetweenSymmetric() throws TajoException { + Schema schema = new Schema(); + schema.addColumn("col1", TajoDataTypes.Type.INT4); + schema.addColumn("col2", TajoDataTypes.Type.INT4); + testEval(schema, "table1", "0,", "select col1 between symmetric 1 and 3 from table1", new String[]{"f"}); + testEval(schema, "table1", "1,", "select col1 between symmetric 1 and 3 from table1", new String[]{"t"}); + testEval(schema, "table1", "2,", "select col1 between symmetric 1 and 3 from table1", new String[]{"t"}); + testEval(schema, "table1", "3,", "select col1 between symmetric 1 and 3 from table1", new String[]{"t"}); + testEval(schema, "table1", "4,", "select col1 between symmetric 1 and 3 from table1", new String[]{"f"}); + testEval(schema, "table1", "5,", "select (col2 between symmetric 1 and 3) is null from table1", new String[]{"t"}); + + testEval(schema, "table1", "0,", "select col1 not between symmetric 1 and 3 from table1", new String[]{"t"}); + testEval(schema, "table1", "1,", "select col1 not between symmetric 1 and 3 from table1", new String[]{"f"}); + testEval(schema, "table1", "2,", "select col1 not between symmetric 1 and 3 from table1", new String[]{"f"}); + testEval(schema, "table1", "3,", "select col1 not between symmetric 1 and 3 from table1", new String[]{"f"}); + testEval(schema, "table1", "4,", "select col1 not between symmetric 1 and 3 from table1", new String[]{"t"}); + testEval(schema, "table1", "5,", "select (col2 not between symmetric 1 and 3) is null from table1", new String[]{"t"}); + + testEval(schema, "table1", "0,", "select col1 between symmetric 3 and 1 from table1", new String[]{"f"}); + testEval(schema, "table1", "1,", "select col1 between symmetric 3 and 1 from table1", new String[]{"t"}); + testEval(schema, "table1", "2,", "select col1 between symmetric 3 and 1 from table1", new String[]{"t"}); + testEval(schema, "table1", "3,", "select col1 between symmetric 3 and 1 from table1", new String[]{"t"}); + testEval(schema, "table1", "4,", "select col1 between symmetric 3 and 1 from table1", new String[]{"f"}); + testEval(schema, "table1", "5,", "select (col2 between symmetric 3 and 1) is null from table1", new String[]{"t"}); + + testEval(schema, "table1", "0,", "select col1 not between symmetric 3 and 1 from table1", new String[]{"t"}); + testEval(schema, "table1", "1,", "select col1 not between symmetric 3 and 1 from table1", new String[]{"f"}); + testEval(schema, "table1", "2,", "select col1 not between symmetric 3 and 1 from table1", new String[]{"f"}); + testEval(schema, "table1", "3,", "select col1 not between symmetric 3 and 1 from table1", new String[]{"f"}); + testEval(schema, "table1", "4,", "select col1 not between symmetric 3 and 1 from table1", new String[]{"t"}); + testEval(schema, "table1", "5,", "select (col2 not between symmetric 3 and 1) is null from table1", + new String[]{"t"}); + } + + @Test + public void testUnary() throws TajoException { + schema = new Schema(); + schema.addColumn("col0", TajoDataTypes.Type.INT1); + schema.addColumn("col1", TajoDataTypes.Type.INT2); + schema.addColumn("col2", TajoDataTypes.Type.INT4); + schema.addColumn("col3", TajoDataTypes.Type.INT8); + schema.addColumn("col4", TajoDataTypes.Type.FLOAT4); + schema.addColumn("col5", TajoDataTypes.Type.FLOAT8); + schema.addColumn("col6", TajoDataTypes.Type.TEXT); + schema.addColumn("col7", CatalogUtil.newDataType(TajoDataTypes.Type.CHAR, "", 3)); + schema.addColumn("col8", TajoDataTypes.Type.BOOLEAN); + + + // sign test + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select +col1 from table1;", new String [] {"1"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select +col2 from table1;", new String [] {"2"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select +col3 from table1;", new String [] {"3"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select +col4 from table1;", new String [] {"4.1"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select +col5 from table1;", new String [] {"5.1"}); + + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select -col1 from table1;", new String [] {"-1"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select -col2 from table1;", new String [] {"-2"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select -col3 from table1;", new String [] {"-3"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select -col4 from table1;", new String [] {"-4.1"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select -col5 from table1;", new String [] {"-5.1"}); + + // not test + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select col8 from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select NOT (col8) from table1;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,t", "select NOT(NOT (col8)) from table1;", new String [] {"t"}); + + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,", "select col8 is null from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,", "select (NOT (col8)) is null from table1;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.1,5.1,6,7,", "select (NOT(NOT (col8))) is null from table1;", new String [] {"t"}); + } + + @Test + public void testAndOr() throws TajoException { + testSimpleEval("select true or (false or false) or false;", new String[] {"t"}); + + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select true and true;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select true and false;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select false and true;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select false and false;", new String [] {"f"}); + + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select true or true;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select true or false;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select false or true;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select false or false;", new String [] {"f"}); + + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select (true and true) and false;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select (true and false) and true;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select (false and true) and true;", new String [] {"f"}); + + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select (1 < 2) and true;", new String [] {"t"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select (1 < 2) and false;", new String [] {"f"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select (1 < 2) or false;", new String [] {"t"}); + } + + @Test + public void testFunction() throws TajoException { + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select upper('abc');", new String [] {"ABC"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select upper('bbc');", new String [] {"BBC"}); + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select upper('chs');", new String [] {"CHS"}); + + testSimpleEval("select ltrim('xxtrim', 'xx') ", new String[]{"trim"}); + } + + @Test + public void testStringConcat() throws TajoException { + testSimpleEval("select length('123456') as col1 ", new String[]{"6"}); + + testEval(schema, "table1", "0,1,2,3,4.5,6.5", "select 'abc' || 'bbc'", new String [] {"abcbbc"}); + Schema schema = new Schema(); + schema.addColumn("col1", TajoDataTypes.Type.TEXT); + schema.addColumn("col2", TajoDataTypes.Type.TEXT); + testEval(schema, "table1", " trim, abc", "select ltrim(col1) || ltrim(col2) from table1", + new String[]{"trimabc"}); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/a4106883/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestGeneratorAdapter.java ---------------------------------------------------------------------- diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestGeneratorAdapter.java b/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestGeneratorAdapter.java new file mode 100644 index 0000000..9976d39 --- /dev/null +++ b/tajo-core-tests/src/test/java/org/apache/tajo/engine/codegen/TestGeneratorAdapter.java @@ -0,0 +1,41 @@ +/** + * 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.codegen; + +import org.apache.tajo.catalog.Schema; +import org.apache.tajo.datum.Datum; +import org.apache.tajo.storage.Tuple; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + + +public class TestGeneratorAdapter { + @Test + public void testGetDescription() throws Exception { + assertEquals("I", TajoGeneratorAdapter.getDescription(int.class)); + assertEquals("Ljava/lang/String;", TajoGeneratorAdapter.getDescription(String.class)); + } + + @Test + public void getMethodDescription() throws Exception { + assertEquals("(Lorg/apache/tajo/catalog/Schema;Lorg/apache/tajo/storage/Tuple;)Lorg/apache/tajo/datum/Datum;", + TajoGeneratorAdapter.getMethodDescription(Datum.class, new Class[]{Schema.class, Tuple.class})); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/a4106883/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java ---------------------------------------------------------------------- diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java new file mode 100644 index 0000000..f2b6477 --- /dev/null +++ b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java @@ -0,0 +1,341 @@ +/** + * 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.eval; + +import org.apache.tajo.LocalTajoTestingUtility; +import org.apache.tajo.OverridableConf; +import org.apache.tajo.SessionVars; +import org.apache.tajo.TajoTestingCluster; +import org.apache.tajo.algebra.Expr; +import org.apache.tajo.catalog.*; +import org.apache.tajo.cli.tsql.InvalidStatementException; +import org.apache.tajo.cli.tsql.ParsedResult; +import org.apache.tajo.cli.tsql.SimpleParser; +import org.apache.tajo.common.TajoDataTypes.Type; +import org.apache.tajo.conf.TajoConf; +import org.apache.tajo.datum.*; +import org.apache.tajo.engine.codegen.EvalCodeGenerator; +import org.apache.tajo.engine.codegen.TajoClassLoader; +import org.apache.tajo.engine.function.FunctionLoader; +import org.apache.tajo.engine.json.CoreGsonHelper; +import org.apache.tajo.engine.parser.SQLAnalyzer; +import org.apache.tajo.engine.query.QueryContext; +import org.apache.tajo.exception.TajoException; +import org.apache.tajo.exception.TajoInternalError; +import org.apache.tajo.function.FunctionSignature; +import org.apache.tajo.master.exec.QueryExecutor; +import org.apache.tajo.plan.*; +import org.apache.tajo.plan.expr.EvalContext; +import org.apache.tajo.plan.expr.EvalNode; +import org.apache.tajo.plan.serder.EvalNodeDeserializer; +import org.apache.tajo.plan.serder.EvalNodeSerializer; +import org.apache.tajo.plan.serder.PlanProto; +import org.apache.tajo.plan.verifier.LogicalPlanVerifier; +import org.apache.tajo.plan.verifier.PreLogicalPlanVerifier; +import org.apache.tajo.plan.verifier.VerificationState; +import org.apache.tajo.storage.LazyTuple; +import org.apache.tajo.storage.TablespaceManager; +import org.apache.tajo.storage.Tuple; +import org.apache.tajo.storage.VTuple; +import org.apache.tajo.util.BytesUtils; +import org.apache.tajo.util.CommonTestingUtil; +import org.apache.tajo.util.KeyValueSet; +import org.apache.tajo.util.datetime.DateTimeUtil; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + +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 ExprTestBase { + private static TajoTestingCluster util; + private static TajoConf conf; + private static CatalogService cat; + private static SQLAnalyzer analyzer; + private static PreLogicalPlanVerifier preLogicalPlanVerifier; + private static LogicalPlanner planner; + private static LogicalOptimizer optimizer; + private static LogicalPlanVerifier annotatedPlanVerifier; + + public static String getUserTimeZoneDisplay(TimeZone tz) { + return DateTimeUtil.getTimeZoneDisplayTime(tz); + } + + public ExprTestBase() { + } + + @BeforeClass + public static void setUp() throws Exception { + util = new TajoTestingCluster(); + conf = util.getConfiguration(); + util.startCatalogCluster(); + cat = util.getMiniCatalogCluster().getCatalog(); + cat.createTablespace(DEFAULT_TABLESPACE_NAME, "hdfs://localhost:1234/warehouse"); + cat.createDatabase(DEFAULT_DATABASE_NAME, DEFAULT_TABLESPACE_NAME); + Map<FunctionSignature, FunctionDesc> map = FunctionLoader.load(); + map = FunctionLoader.loadUserDefinedFunctions(conf, map); + for (FunctionDesc funcDesc : map.values()) { + cat.createFunction(funcDesc); + } + + analyzer = new SQLAnalyzer(); + preLogicalPlanVerifier = new PreLogicalPlanVerifier(cat); + planner = new LogicalPlanner(cat, TablespaceManager.getInstance()); + optimizer = new LogicalOptimizer(util.getConfiguration(), cat); + annotatedPlanVerifier = new LogicalPlanVerifier(); + } + + @AfterClass + public static void tearDown() throws Exception { + util.shutdownCatalogCluster(); + } + + private static void assertJsonSerDer(EvalNode expr) { + String json = CoreGsonHelper.toJson(expr, EvalNode.class); + EvalNode fromJson = CoreGsonHelper.fromJson(json, EvalNode.class); + assertEquals(expr, fromJson); + } + + public TajoConf getConf() { + return new TajoConf(conf); + } + + /** + * verify query syntax and get raw targets. + * + * @param context QueryContext + * @param query a query for execution + * @param condition this parameter means whether it is for success case or is not for failure case. + * @return + * @throws PlanningException + */ + private static Target[] getRawTargets(QueryContext context, String query, boolean condition) + throws TajoException, InvalidStatementException { + + List<ParsedResult> parsedResults = SimpleParser.parseScript(query); + if (parsedResults.size() > 1) { + throw new RuntimeException("this query includes two or more statements."); + } + Expr expr = analyzer.parse(parsedResults.get(0).getHistoryStatement()); + VerificationState state = new VerificationState(); + preLogicalPlanVerifier.verify(context, state, expr); + if (state.getErrors().size() > 0) { + if (!condition && state.getErrors().size() > 0) { + throw new RuntimeException(state.getErrors().get(0)); + } + assertFalse(state.getErrors().get(0).getMessage(), true); + } + LogicalPlan plan = planner.createPlan(context, expr, true); + optimizer.optimize(context, plan); + annotatedPlanVerifier.verify(state, plan); + + if (state.getErrors().size() > 0) { + assertFalse(state.getErrors().get(0).getMessage(), true); + } + + Target [] targets = plan.getRootBlock().getRawTargets(); + if (targets == null) { + throw new RuntimeException("Wrong query statement or query plan: " + parsedResults.get(0).getHistoryStatement()); + } + + // Trying regression test for cloning, (de)serialization for json and protocol buffer + for (Target t : targets) { + try { + assertEquals(t.getEvalTree(), t.getEvalTree().clone()); + } catch (CloneNotSupportedException e) { + fail(e.getMessage()); + } + } + for (Target t : targets) { + assertJsonSerDer(t.getEvalTree()); + } + for (Target t : targets) { + assertEvalTreeProtoSerDer(context, t.getEvalTree()); + } + return targets; + } + + public void testSimpleEval(String query, String [] expected) throws TajoException { + testEval(null, null, null, query, expected); + } + + public void testSimpleEval(OverridableConf context, String query, String [] expected) throws TajoException { + testEval(context, null, null, null, query, expected); + } + + public void testSimpleEval(String query, String [] expected, boolean successOrFail) + throws TajoException, IOException { + + testEval(null, null, null, null, query, expected, ',', successOrFail); + } + + public void testSimpleEval(OverridableConf context, String query, String [] expected, boolean successOrFail) + throws TajoException, IOException { + testEval(context, null, null, null, query, expected, ',', successOrFail); + } + + public void testEval(Schema schema, String tableName, String csvTuple, String query, String [] expected) + throws TajoException { + testEval(null, schema, tableName != null ? CatalogUtil.normalizeIdentifier(tableName) : null, csvTuple, query, + expected, ',', true); + } + + public void testEval(OverridableConf context, Schema schema, String tableName, String csvTuple, String query, + String [] expected) + throws TajoException { + testEval(context, schema, tableName != null ? CatalogUtil.normalizeIdentifier(tableName) : null, csvTuple, + query, expected, ',', true); + } + + public void testEval(Schema schema, String tableName, String csvTuple, String query, + String [] expected, char delimiter, boolean condition) throws TajoException { + testEval(null, schema, tableName != null ? CatalogUtil.normalizeIdentifier(tableName) : null, csvTuple, + query, expected, delimiter, condition); + } + + public void testEval(OverridableConf context, Schema schema, String tableName, String csvTuple, String query, + String [] expected, char delimiter, boolean condition) throws TajoException { + QueryContext queryContext; + if (context == null) { + queryContext = LocalTajoTestingUtility.createDummyContext(conf); + } else { + queryContext = LocalTajoTestingUtility.createDummyContext(conf); + queryContext.putAll(context); + } + + String timezoneId = queryContext.get(SessionVars.TIMEZONE); + TimeZone timeZone = TimeZone.getTimeZone(timezoneId); + + LazyTuple lazyTuple; + VTuple vtuple = null; + String qualifiedTableName = + CatalogUtil.buildFQName(DEFAULT_DATABASE_NAME, + tableName != null ? CatalogUtil.normalizeIdentifier(tableName) : null); + Schema inputSchema = null; + if (schema != null) { + inputSchema = SchemaUtil.clone(schema); + inputSchema.setQualifier(qualifiedTableName); + + int targetIdx [] = new int[inputSchema.size()]; + for (int i = 0; i < targetIdx.length; i++) { + targetIdx[i] = i; + } + + byte[][] tokens = BytesUtils.splitPreserveAllTokens( + csvTuple.getBytes(), delimiter, targetIdx, inputSchema.size()); + lazyTuple = new LazyTuple(inputSchema, tokens,0); + vtuple = new VTuple(inputSchema.size()); + for (int i = 0; i < inputSchema.size(); i++) { + + // If null value occurs, null datum is manually inserted to an input tuple. + boolean nullDatum; + Datum datum = lazyTuple.get(i); + nullDatum = (datum instanceof TextDatum || datum instanceof CharDatum); + nullDatum = nullDatum && + datum.asChars().equals("") || datum.asChars().equals(queryContext.get(SessionVars.NULL_CHAR)); + nullDatum |= datum.isNull(); + + if (nullDatum) { + vtuple.put(i, NullDatum.get()); + } else { + vtuple.put(i, lazyTuple.get(i)); + } + } + try { + cat.createTable(new TableDesc(qualifiedTableName, inputSchema,"TEXT", + new KeyValueSet(), CommonTestingUtil.getTestDir().toUri())); + } catch (IOException e) { + throw new TajoInternalError(e); + } + } + + Target [] targets; + + TajoClassLoader classLoader = new TajoClassLoader(); + EvalContext evalContext = new EvalContext(); + + try { + targets = getRawTargets(queryContext, query, condition); + + EvalCodeGenerator codegen = null; + if (queryContext.getBool(SessionVars.CODEGEN)) { + codegen = new EvalCodeGenerator(classLoader); + } + + QueryExecutor.startScriptExecutors(queryContext, evalContext, targets); + Tuple outTuple = new VTuple(targets.length); + for (int i = 0; i < targets.length; i++) { + EvalNode eval = targets[i].getEvalTree(); + + if (queryContext.getBool(SessionVars.CODEGEN)) { + eval = codegen.compile(inputSchema, eval); + } + eval.bind(evalContext, inputSchema); + + outTuple.put(i, eval.eval(vtuple)); + } + + try { + classLoader.clean(); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + + for (int i = 0; i < expected.length; i++) { + String outTupleAsChars; + if (outTuple.type(i) == Type.TIMESTAMP) { + outTupleAsChars = TimestampDatum.asChars(outTuple.getTimeDate(i), timeZone, false); + } else if (outTuple.type(i) == Type.TIME) { + outTupleAsChars = TimeDatum.asChars(outTuple.getTimeDate(i), timeZone, false); + } else { + outTupleAsChars = outTuple.getText(i); + } + assertEquals(query, expected[i], outTupleAsChars); + } + } catch (IOException e) { + throw new TajoInternalError(e); + } catch (InvalidStatementException e) { + assertFalse(e.getMessage(), true); + } catch (TajoException e) { + // In failure test case, an exception must occur while executing query. + // So, we should check an error message, and return it. + if (!condition) { + assertEquals(expected[0], e.getMessage()); + } else { + throw e; + } + } finally { + if (schema != null) { + cat.dropTable(qualifiedTableName); + } + QueryExecutor.stopScriptExecutors(evalContext); + } + } + + public static void assertEvalTreeProtoSerDer(OverridableConf context, EvalNode evalNode) { + PlanProto.EvalNodeTree converted = EvalNodeSerializer.serialize(evalNode); + assertEquals(evalNode, EvalNodeDeserializer.deserialize(context, null, converted)); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/a4106883/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java ---------------------------------------------------------------------- diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java new file mode 100644 index 0000000..ea42783 --- /dev/null +++ b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java @@ -0,0 +1,424 @@ +/** + * 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.eval; + +import org.apache.tajo.catalog.CatalogUtil; +import org.apache.tajo.catalog.Column; +import org.apache.tajo.catalog.Schema; +import org.apache.tajo.common.TajoDataTypes; +import org.apache.tajo.common.TajoDataTypes.DataType; +import org.apache.tajo.datum.Datum; +import org.apache.tajo.datum.DatumFactory; +import org.apache.tajo.engine.json.CoreGsonHelper; +import org.apache.tajo.plan.expr.*; +import org.apache.tajo.storage.Tuple; +import org.apache.tajo.storage.VTuple; +import org.junit.Test; + +import static org.apache.tajo.common.TajoDataTypes.Type.*; +import static org.junit.Assert.*; +import static org.junit.Assert.fail; + +public class TestEvalTree extends ExprTestBase { + @Test + public void testTupleEval() throws CloneNotSupportedException { + ConstEval e1 = new ConstEval(DatumFactory.createInt4(1)); + assertCloneEqual(e1); + FieldEval e2 = new FieldEval("table1.score", CatalogUtil.newSimpleDataType(INT4)); // it indicates + assertCloneEqual(e2); + + Schema schema1 = new Schema(); + schema1.addColumn("table1.id", INT4); + schema1.addColumn("table1.score", INT4); + + BinaryEval expr = new BinaryEval(EvalType.PLUS, e1, e2); + expr.bind(null, schema1); + + assertCloneEqual(expr); + VTuple tuple = new VTuple(2); + tuple.put(0, DatumFactory.createInt4(1)); // put 0th field + tuple.put(1, DatumFactory.createInt4(99)); // put 1th field + + // the result of evaluation must be 100. + assertEquals(expr.eval(tuple).asInt4(), 100); + } + + public static class MockTrueEval extends EvalNode { + + public MockTrueEval() { + super(EvalType.CONST); + } + + @Override + public String getName() { + return this.getClass().getName(); + } + + @Override + public void preOrder(EvalNodeVisitor visitor) { + visitor.visit(this); + } + + @Override + public void postOrder(EvalNodeVisitor visitor) { + visitor.visit(this); + } + + @Override + public Datum eval(Tuple tuple) { + super.eval(tuple); + return DatumFactory.createBool(true); + } + + @Override + public boolean equals(Object obj) { + return true; + } + + @Override + public DataType getValueType() { + return CatalogUtil.newSimpleDataType(BOOLEAN); + } + + @Override + public int childNum() { + return 0; + } + + @Override + public EvalNode getChild(int idx) { + return null; + } + } + + public static class MockFalseExpr extends EvalNode { + + public MockFalseExpr() { + super(EvalType.CONST); + } + + @Override + public Datum eval(Tuple tuple) { + super.eval(tuple); + return DatumFactory.createBool(false); + } + + @Override + public boolean equals(Object obj) { + return true; + } + + @Override + public String getName() { + return this.getClass().getName(); + } + + @Override + public void preOrder(EvalNodeVisitor visitor) { + visitor.visit(this); + } + + @Override + public void postOrder(EvalNodeVisitor visitor) { + visitor.visit(this); + } + + @Override + public DataType getValueType() { + return CatalogUtil.newSimpleDataType(BOOLEAN); + } + + @Override + public int childNum() { + return 0; + } + + @Override + public EvalNode getChild(int idx) { + return null; + } + } + + @Test + public void testAndTest() { + MockTrueEval trueExpr = new MockTrueEval(); + MockFalseExpr falseExpr = new MockFalseExpr(); + + BinaryEval andExpr = new BinaryEval(EvalType.AND, trueExpr, trueExpr); + andExpr.bind(null, null); + assertTrue(andExpr.eval(null).asBool()); + + andExpr = new BinaryEval(EvalType.AND, falseExpr, trueExpr); + andExpr.bind(null, null); + assertFalse(andExpr.eval(null).asBool()); + + andExpr = new BinaryEval(EvalType.AND, trueExpr, falseExpr); + andExpr.bind(null, null); + assertFalse(andExpr.eval(null).asBool()); + + andExpr = new BinaryEval(EvalType.AND, falseExpr, falseExpr); + andExpr.bind(null, null); + assertFalse(andExpr.eval(null).asBool()); + } + + @Test + public void testOrTest() { + MockTrueEval trueExpr = new MockTrueEval(); + MockFalseExpr falseExpr = new MockFalseExpr(); + + BinaryEval orExpr = new BinaryEval(EvalType.OR, trueExpr, trueExpr); + orExpr.bind(null, null); + assertTrue(orExpr.eval(null).asBool()); + + orExpr = new BinaryEval(EvalType.OR, falseExpr, trueExpr); + orExpr.bind(null, null); + assertTrue(orExpr.eval(null).asBool()); + + orExpr = new BinaryEval(EvalType.OR, trueExpr, falseExpr); + orExpr.bind(null, null); + assertTrue(orExpr.eval(null).asBool()); + + orExpr = new BinaryEval(EvalType.OR, falseExpr, falseExpr); + orExpr.bind(null, null); + assertFalse(orExpr.eval(null).asBool()); + } + + @Test + public final void testCompOperator() { + ConstEval e1; + ConstEval e2; + BinaryEval expr; + + // Constant + e1 = new ConstEval(DatumFactory.createInt4(9)); + e2 = new ConstEval(DatumFactory.createInt4(34)); + expr = new BinaryEval(EvalType.LTH, e1, e2); + assertTrue(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.LEQ, e1, e2); + assertTrue(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.LTH, e2, e1); + assertFalse(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.LEQ, e2, e1); + assertFalse(expr.bind(null, null).eval(null).asBool()); + + expr = new BinaryEval(EvalType.GTH, e2, e1); + assertTrue(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.GEQ, e2, e1); + assertTrue(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.GTH, e1, e2); + assertFalse(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.GEQ, e1, e2); + assertFalse(expr.bind(null, null).eval(null).asBool()); + + BinaryEval plus = new BinaryEval(EvalType.PLUS, e1, e2); + expr = new BinaryEval(EvalType.LTH, e1, plus); + assertTrue(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.LEQ, e1, plus); + assertTrue(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.LTH, plus, e1); + assertFalse(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.LEQ, plus, e1); + assertFalse(expr.bind(null, null).eval(null).asBool()); + + expr = new BinaryEval(EvalType.GTH, plus, e1); + assertTrue(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.GEQ, plus, e1); + assertTrue(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.GTH, e1, plus); + assertFalse(expr.bind(null, null).eval(null).asBool()); + expr = new BinaryEval(EvalType.GEQ, e1, plus); + assertFalse(expr.bind(null, null).eval(null).asBool()); + } + + @Test + public final void testArithmaticsOperator() + throws CloneNotSupportedException { + ConstEval e1; + ConstEval e2; + + // PLUS + e1 = new ConstEval(DatumFactory.createInt4(9)); + e2 = new ConstEval(DatumFactory.createInt4(34)); + BinaryEval expr = new BinaryEval(EvalType.PLUS, e1, e2); + assertEquals(expr.bind(null, null).eval(null).asInt4(), 43); + assertCloneEqual(expr); + + // MINUS + e1 = new ConstEval(DatumFactory.createInt4(5)); + e2 = new ConstEval(DatumFactory.createInt4(2)); + expr = new BinaryEval(EvalType.MINUS, e1, e2); + assertEquals(expr.bind(null, null).eval(null).asInt4(), 3); + assertCloneEqual(expr); + + // MULTIPLY + e1 = new ConstEval(DatumFactory.createInt4(5)); + e2 = new ConstEval(DatumFactory.createInt4(2)); + expr = new BinaryEval(EvalType.MULTIPLY, e1, e2); + assertEquals(expr.bind(null, null).eval(null).asInt4(), 10); + assertCloneEqual(expr); + + // DIVIDE + e1 = new ConstEval(DatumFactory.createInt4(10)); + e2 = new ConstEval(DatumFactory.createInt4(5)); + expr = new BinaryEval(EvalType.DIVIDE, e1, e2); + assertEquals(expr.bind(null, null).eval(null).asInt4(), 2); + assertCloneEqual(expr); + } + + @Test + public final void testGetReturnType() { + ConstEval e1; + ConstEval e2; + + // PLUS + e1 = new ConstEval(DatumFactory.createInt4(9)); + e2 = new ConstEval(DatumFactory.createInt4(34)); + BinaryEval expr = new BinaryEval(EvalType.PLUS, e1, e2); + assertEquals(CatalogUtil.newSimpleDataType(INT4), expr.getValueType()); + + expr = new BinaryEval(EvalType.LTH, e1, e2); + assertTrue(expr.bind(null, null).eval(null).asBool()); + assertEquals(CatalogUtil.newSimpleDataType(BOOLEAN), expr.getValueType()); + + e1 = new ConstEval(DatumFactory.createFloat8(9.3)); + e2 = new ConstEval(DatumFactory.createFloat8(34.2)); + expr = new BinaryEval(EvalType.PLUS, e1, e2); + assertEquals(CatalogUtil.newSimpleDataType(FLOAT8), expr.getValueType()); + } + + @Test + public final void testEquals() throws CloneNotSupportedException { + ConstEval e1; + ConstEval e2; + + // PLUS + e1 = new ConstEval(DatumFactory.createInt4(34)); + e2 = new ConstEval(DatumFactory.createInt4(34)); + assertEquals(e1, e2); + + BinaryEval plus1 = new BinaryEval(EvalType.PLUS, e1, e2); + BinaryEval plus2 = new BinaryEval(EvalType.PLUS, e2, e1); + assertEquals(plus1, plus2); + + ConstEval e3 = new ConstEval(DatumFactory.createInt4(29)); + BinaryEval plus3 = new BinaryEval(EvalType.PLUS, e1, e3); + assertFalse(plus1.equals(plus3)); + + // LTH + ConstEval e4 = new ConstEval(DatumFactory.createInt4(9)); + ConstEval e5 = new ConstEval(DatumFactory.createInt4(34)); + BinaryEval compExpr1 = new BinaryEval(EvalType.LTH, e4, e5); + assertCloneEqual(compExpr1); + + ConstEval e6 = new ConstEval(DatumFactory.createInt4(9)); + ConstEval e7 = new ConstEval(DatumFactory.createInt4(34)); + BinaryEval compExpr2 = new BinaryEval(EvalType.LTH, e6, e7); + assertCloneEqual(compExpr2); + + assertTrue(compExpr1.equals(compExpr2)); + } + + @Test + public final void testJson() throws CloneNotSupportedException { + ConstEval e1; + ConstEval e2; + + // 29 > (34 + 5) + (5 + 34) + e1 = new ConstEval(DatumFactory.createInt4(34)); + e2 = new ConstEval(DatumFactory.createInt4(5)); + assertCloneEqual(e1); + + BinaryEval plus1 = new BinaryEval(EvalType.PLUS, e1, e2); + assertCloneEqual(plus1); + BinaryEval plus2 = new BinaryEval(EvalType.PLUS, e2, e1); + assertCloneEqual(plus2); + BinaryEval plus3 = new BinaryEval(EvalType.PLUS, plus2, plus1); + assertCloneEqual(plus3); + + ConstEval e3 = new ConstEval(DatumFactory.createInt4(29)); + BinaryEval gth = new BinaryEval(EvalType.GTH, e3, plus3); + assertCloneEqual(gth); + + String json = gth.toJson(); + BinaryEval eval = (BinaryEval) CoreGsonHelper.fromJson(json, EvalNode.class); + assertCloneEqual(eval); + + assertEquals(gth.getType(), eval.getType()); + assertEquals(e3.getType(), eval.getLeftExpr().getType()); + assertEquals(plus3.getType(), eval.getRightExpr().getType()); + assertEquals(plus3.getLeftExpr(), ((BinaryEval)eval.getRightExpr()).getLeftExpr()); + assertEquals(plus3.getRightExpr(), ((BinaryEval) eval.getRightExpr()).getRightExpr()); + assertEquals(plus2.getLeftExpr(), ((BinaryEval)((BinaryEval)eval.getRightExpr()).getLeftExpr()).getLeftExpr()); + assertEquals(plus2.getRightExpr(), ((BinaryEval)((BinaryEval)eval.getRightExpr()).getLeftExpr()).getRightExpr()); + assertEquals(plus1.getLeftExpr(), ((BinaryEval) ((BinaryEval) eval.getRightExpr()).getRightExpr()).getLeftExpr()); + assertEquals(plus1.getRightExpr(), ((BinaryEval) ((BinaryEval) eval.getRightExpr()).getRightExpr()).getRightExpr()); + } + + @Test + public final void testBindCheck() { + ConstEval e1; + ConstEval e2; + BinaryEval binEval; + + // Constant + e1 = new ConstEval(DatumFactory.createInt4(9)); + e2 = new ConstEval(DatumFactory.createInt4(34)); + binEval = new BinaryEval(EvalType.LTH, e1, e2); + try { + binEval.eval(null); + fail("EvalNode is not binded"); + } catch (IllegalStateException e) { + assertTrue(binEval.bind(null, null).eval(null).asBool()); + } + + CaseWhenEval caseWhenEval = new CaseWhenEval(); + caseWhenEval.addIfCond(new CaseWhenEval.IfThenEval(binEval, new ConstEval(DatumFactory.createInt4(1)))); + try { + caseWhenEval.eval(null); + fail("EvalNode is not binded"); + } catch (IllegalStateException e) { + assertEquals(caseWhenEval.bind(null, null).eval(null).asInt4(), 1); + } + + Schema schema = new Schema(new Column[]{new Column("test", TajoDataTypes.Type.INT4)}); + Tuple tuple = new VTuple(new Datum[]{DatumFactory.createText("aaa")}); + RegexPredicateEval regexEval = new RegexPredicateEval(false, new FieldEval("test", + CatalogUtil.newSimpleDataType(TajoDataTypes.Type.INT4)), new ConstEval(DatumFactory.createText("a*")), false); + try { + regexEval.eval(null); + fail("EvalNode is not binded"); + } catch (IllegalStateException e) { + assertEquals(regexEval.bind(null, schema).eval(tuple).asBool(), true); + } + + RowConstantEval rowConstantEval = new RowConstantEval(new Datum[]{}); + try { + rowConstantEval.eval(null); + fail("EvalNode is not binded"); + } catch (IllegalStateException e) { + assertEquals(rowConstantEval.bind(null, null).eval(null).isNull(), true); + } + } + + private void assertCloneEqual(EvalNode eval) throws CloneNotSupportedException { + EvalNode copy = (EvalNode) eval.clone(); + assertEquals(eval, copy); + assertFalse(eval == copy); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/a4106883/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestEvalTreeUtil.java ---------------------------------------------------------------------- diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestEvalTreeUtil.java b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestEvalTreeUtil.java new file mode 100644 index 0000000..8c31550 --- /dev/null +++ b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestEvalTreeUtil.java @@ -0,0 +1,374 @@ +/** + * 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.eval; + +import com.google.common.collect.Sets; +import org.apache.tajo.LocalTajoTestingUtility; +import org.apache.tajo.TajoConstants; +import org.apache.tajo.TajoTestingCluster; +import org.apache.tajo.algebra.Expr; +import org.apache.tajo.algebra.OpType; +import org.apache.tajo.algebra.Selection; +import org.apache.tajo.catalog.*; +import org.apache.tajo.catalog.proto.CatalogProtos.FunctionType; +import org.apache.tajo.common.TajoDataTypes; +import org.apache.tajo.datum.Datum; +import org.apache.tajo.datum.DatumFactory; +import org.apache.tajo.engine.function.FunctionLoader; +import org.apache.tajo.engine.parser.SQLAnalyzer; +import org.apache.tajo.engine.query.QueryContext; +import org.apache.tajo.exception.TajoException; +import org.apache.tajo.plan.LogicalPlan; +import org.apache.tajo.plan.LogicalPlanner; +import org.apache.tajo.plan.Target; +import org.apache.tajo.plan.expr.*; +import org.apache.tajo.plan.exprrewrite.EvalTreeOptimizer; +import org.apache.tajo.plan.function.GeneralFunction; +import org.apache.tajo.plan.logical.GroupbyNode; +import org.apache.tajo.plan.logical.NodeType; +import org.apache.tajo.plan.nameresolver.NameResolvingMode; +import org.apache.tajo.storage.TablespaceManager; +import org.apache.tajo.storage.Tuple; +import org.apache.tajo.util.CommonTestingUtil; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import static org.apache.tajo.TajoConstants.DEFAULT_TABLESPACE_NAME; +import static org.apache.tajo.common.TajoDataTypes.Type.INT4; +import static org.junit.Assert.*; + +public class TestEvalTreeUtil { + static TajoTestingCluster util; + static CatalogService catalog = null; + static EvalNode expr1; + static EvalNode expr2; + static EvalNode expr3; + static SQLAnalyzer analyzer; + static LogicalPlanner planner; + static QueryContext defaultContext; + + public static class TestSum extends GeneralFunction { + private Integer x; + private Integer y; + + public TestSum() { + super(new Column[] { new Column("arg1", INT4), + new Column("arg2", INT4) }); + } + + @Override + public Datum eval(Tuple params) { + x = params.getInt4(0); + y = params.getInt4(1); + return DatumFactory.createInt4(x + y); + } + } + + @BeforeClass + public static void setUp() throws Exception { + util = new TajoTestingCluster(); + util.startCatalogCluster(); + catalog = util.getMiniCatalogCluster().getCatalog(); + for (FunctionDesc funcDesc : FunctionLoader.findLegacyFunctions()) { + catalog.createFunction(funcDesc); + } + catalog.createTablespace(DEFAULT_TABLESPACE_NAME, "hdfs://localhost:1234/warehouse"); + catalog.createDatabase(TajoConstants.DEFAULT_DATABASE_NAME, DEFAULT_TABLESPACE_NAME); + + Schema schema = new Schema(); + schema.addColumn("name", TajoDataTypes.Type.TEXT); + schema.addColumn("score", TajoDataTypes.Type.INT4); + schema.addColumn("age", TajoDataTypes.Type.INT4); + + TableMeta meta = CatalogUtil.newTableMeta("TEXT"); + TableDesc desc = new TableDesc( + CatalogUtil.buildFQName(TajoConstants.DEFAULT_DATABASE_NAME, "people"), schema, meta, + CommonTestingUtil.getTestDir().toUri()); + catalog.createTable(desc); + + FunctionDesc funcMeta = new FunctionDesc("test_sum", TestSum.class, + FunctionType.GENERAL, + CatalogUtil.newSimpleDataType(TajoDataTypes.Type.INT4), + CatalogUtil.newSimpleDataTypeArray(TajoDataTypes.Type.INT4, TajoDataTypes.Type.INT4)); + catalog.createFunction(funcMeta); + + analyzer = new SQLAnalyzer(); + planner = new LogicalPlanner(catalog, TablespaceManager.getInstance()); + + String[] QUERIES = { + "select name, score, age from people where score > 30", // 0 + "select name, score, age from people where score * age", // 1 + "select name, score, age from people where test_sum(score * age, 50)", // 2 + }; + + defaultContext = LocalTajoTestingUtility.createDummyContext(util.getConfiguration()); + + expr1 = getRootSelection(QUERIES[0]); + expr2 = getRootSelection(QUERIES[1]); + expr3 = getRootSelection(QUERIES[2]); + } + + @AfterClass + public static void tearDown() throws Exception { + util.shutdownCatalogCluster(); + } + + public static Target [] getRawTargets(String query) { + Expr expr = analyzer.parse(query); + LogicalPlan plan = null; + try { + plan = planner.createPlan(defaultContext, expr); + } catch (TajoException e) { + throw new RuntimeException(e); + } + + return plan.getRootBlock().getRawTargets(); + } + + public static EvalNode getRootSelection(String query) throws TajoException { + Expr block = analyzer.parse(query); + LogicalPlan plan = planner.createPlan(defaultContext, block); + + LogicalPlanner.PlanContext context = new LogicalPlanner.PlanContext(defaultContext, plan, plan.getRootBlock(), + new EvalTreeOptimizer(), true); + + Selection selection = plan.getRootBlock().getSingletonExpr(OpType.Filter); + return planner.getExprAnnotator().createEvalNode(context, selection.getQual(), + NameResolvingMode.RELS_AND_SUBEXPRS); + } + + @Test + public final void testChangeColumnRef() throws CloneNotSupportedException { + EvalNode copy = (EvalNode)expr1.clone(); + EvalTreeUtil.changeColumnRef(copy, "default.people.score", "newscore"); + Set<Column> set = EvalTreeUtil.findUniqueColumns(copy); + assertEquals(1, set.size()); + assertTrue(set.contains(new Column("newscore", TajoDataTypes.Type.INT4))); + + copy = (EvalNode)expr2.clone(); + EvalTreeUtil.changeColumnRef(copy, "default.people.age", "sum_age"); + set = EvalTreeUtil.findUniqueColumns(copy); + assertEquals(2, set.size()); + assertTrue(set.contains(new Column("default.people.score", TajoDataTypes.Type.INT4))); + assertTrue(set.contains(new Column("sum_age", TajoDataTypes.Type.INT4))); + + copy = (EvalNode)expr3.clone(); + EvalTreeUtil.changeColumnRef(copy, "default.people.age", "sum_age"); + set = EvalTreeUtil.findUniqueColumns(copy); + assertEquals(2, set.size()); + assertTrue(set.contains(new Column("default.people.score", TajoDataTypes.Type.INT4))); + assertTrue(set.contains(new Column("sum_age", TajoDataTypes.Type.INT4))); + } + + @Test + public final void testFindAllRefColumns() { + Set<Column> set = EvalTreeUtil.findUniqueColumns(expr1); + assertEquals(1, set.size()); + assertTrue(set.contains(new Column("default.people.score", TajoDataTypes.Type.INT4))); + + set = EvalTreeUtil.findUniqueColumns(expr2); + assertEquals(2, set.size()); + assertTrue(set.contains(new Column("default.people.score", TajoDataTypes.Type.INT4))); + assertTrue(set.contains(new Column("default.people.age", TajoDataTypes.Type.INT4))); + + set = EvalTreeUtil.findUniqueColumns(expr3); + assertEquals(2, set.size()); + assertTrue(set.contains(new Column("default.people.score", TajoDataTypes.Type.INT4))); + assertTrue(set.contains(new Column("default.people.age", TajoDataTypes.Type.INT4))); + } + + public static final String [] QUERIES = { + "select 3 + 4 as plus, (3.5 * 2) as mul", // 0 + "select (score + 3) < 4, age > 5 from people", // 1 + "select score from people where score > 7", // 2 + "select score from people where (10 * 2) * (score + 2) > 20 + 30 + 10", // 3 + "select score from people where 10 * 2 > score * 10", // 4 + "select score from people where score < 10 and 4 < score", // 5 + "select score from people where score < 10 and 4 < score and age > 5", // 6 + "select score from people where (score > 1 and score < 3) or (7 < score and score < 10)", // 7 + }; + + @Test + public final void testGetSchemaFromTargets() { + Target [] targets = getRawTargets(QUERIES[0]); + Schema schema = EvalTreeUtil.getSchemaByTargets(null, targets); + Column col1 = schema.getColumn(0); + Column col2 = schema.getColumn(1); + assertEquals("plus", col1.getSimpleName()); + assertEquals(TajoDataTypes.Type.INT4, col1.getDataType().getType()); + assertEquals("mul", col2.getSimpleName()); + assertEquals(TajoDataTypes.Type.FLOAT8, col2.getDataType().getType()); + } + + @Test + public final void testGetContainExprs() throws CloneNotSupportedException, TajoException { + Expr expr = analyzer.parse(QUERIES[1]); + LogicalPlan plan = planner.createPlan(defaultContext, expr, true); + Target [] targets = plan.getRootBlock().getRawTargets(); + Column col1 = new Column("default.people.score", TajoDataTypes.Type.INT4); + Collection<EvalNode> exprs = + EvalTreeUtil.getContainExpr(targets[0].getEvalTree(), col1); + BinaryEval node = (BinaryEval) exprs.iterator().next(); + assertEquals(EvalType.LTH, node.getType()); + assertEquals(EvalType.PLUS, node.getLeftExpr().getType()); + assertEquals(new ConstEval(DatumFactory.createInt4(4)), node.getRightExpr()); + + Column col2 = new Column("default.people.age", TajoDataTypes.Type.INT4); + exprs = EvalTreeUtil.getContainExpr(targets[1].getEvalTree(), col2); + node = (BinaryEval) exprs.iterator().next(); + assertEquals(EvalType.GTH, node.getType()); + assertEquals("default.people.age", node.getLeftExpr().getName()); + assertEquals(new ConstEval(DatumFactory.createInt4(5)), node.getRightExpr()); + } + + @Test + public final void testGetCNF() throws TajoException { + // "select score from people where score < 10 and 4 < score " + EvalNode node = getRootSelection(QUERIES[5]); + EvalNode [] cnf = AlgebraicUtil.toConjunctiveNormalFormArray(node); + + Column col1 = new Column("default.people.score", TajoDataTypes.Type.INT4); + + assertEquals(2, cnf.length); + BinaryEval first = (BinaryEval) cnf[0]; + BinaryEval second = (BinaryEval) cnf[1]; + + FieldEval field = first.getLeftExpr(); + assertEquals(col1, field.getColumnRef()); + assertEquals(EvalType.LTH, first.getType()); + assertEquals(10, first.getRightExpr().bind(null, null).eval(null).asInt4()); + + field = second.getRightExpr(); + assertEquals(col1, field.getColumnRef()); + assertEquals(EvalType.LTH, second.getType()); + assertEquals(4, second.getLeftExpr().bind(null, null).eval(null).asInt4()); + } + + @Test + public final void testTransformCNF2Singleton() throws TajoException { + // "select score from people where score < 10 and 4 < score " + EvalNode node = getRootSelection(QUERIES[6]); + EvalNode [] cnf1 = AlgebraicUtil.toConjunctiveNormalFormArray(node); + assertEquals(3, cnf1.length); + + EvalNode conj = AlgebraicUtil.createSingletonExprFromCNF(cnf1); + EvalNode [] cnf2 = AlgebraicUtil.toConjunctiveNormalFormArray(conj); + + Set<EvalNode> set1 = Sets.newHashSet(cnf1); + Set<EvalNode> set2 = Sets.newHashSet(cnf2); + assertEquals(set1, set2); + } + + @Test + public final void testGetDNF() throws TajoException { + // "select score from people where score > 1 and score < 3 or score > 7 and score < 10", // 7 + EvalNode node = getRootSelection(QUERIES[7]); + EvalNode [] cnf = AlgebraicUtil.toDisjunctiveNormalFormArray(node); + assertEquals(2, cnf.length); + + assertEquals("default.people.score (INT4) > 1 AND default.people.score (INT4) < 3", cnf[0].toString()); + assertEquals("7 < default.people.score (INT4) AND default.people.score (INT4) < 10", cnf[1].toString()); + } + + @Test + public final void testSimplify() throws TajoException { + Target [] targets = getRawTargets(QUERIES[0]); + EvalNode node = AlgebraicUtil.eliminateConstantExprs(targets[0].getEvalTree()); + assertEquals(EvalType.CONST, node.getType()); + assertEquals(7, node.bind(null, null).eval(null).asInt4()); + node = AlgebraicUtil.eliminateConstantExprs(targets[1].getEvalTree()); + assertEquals(EvalType.CONST, node.getType()); + assertTrue(7.0d == node.bind(null, null).eval(null).asFloat8()); + + Expr expr = analyzer.parse(QUERIES[1]); + LogicalPlan plan = planner.createPlan(defaultContext, expr, true); + targets = plan.getRootBlock().getRawTargets(); + Column col1 = new Column("default.people.score", TajoDataTypes.Type.INT4); + Collection<EvalNode> exprs = + EvalTreeUtil.getContainExpr(targets[0].getEvalTree(), col1); + node = exprs.iterator().next(); + } + + @Test + public final void testConatainSingleVar() throws TajoException { + EvalNode node = getRootSelection(QUERIES[2]); + assertEquals(true, AlgebraicUtil.containSingleVar(node)); + node = getRootSelection(QUERIES[3]); + assertEquals(true, AlgebraicUtil.containSingleVar(node)); + } + + @Test + public final void testTranspose() throws TajoException { + Column col1 = new Column("default.people.score", TajoDataTypes.Type.INT4); + EvalNode node = getRootSelection(QUERIES[3]); + // we expect that score < 3 + BinaryEval transposed = (BinaryEval) AlgebraicUtil.transpose(node, col1); + assertEquals(EvalType.GTH, transposed.getType()); + FieldEval field = transposed.getLeftExpr(); + assertEquals(col1, field.getColumnRef()); + assertEquals(1, transposed.getRightExpr().bind(null, null).eval(null).asInt4()); + + node = getRootSelection(QUERIES[4]); + // we expect that score < 3 + transposed = (BinaryEval) AlgebraicUtil.transpose(node, col1); + assertEquals(EvalType.LTH, transposed.getType()); + field = transposed.getLeftExpr(); + assertEquals(col1, field.getColumnRef()); + assertEquals(2, transposed.getRightExpr().bind(null, null).eval(null).asInt4()); + } + + @Test + public final void testFindDistinctAggFunctions() throws TajoException { + String query = "select sum(score) + max(age) from people"; + Expr expr = analyzer.parse(query); + LogicalPlan plan = planner.createPlan(defaultContext, expr); + GroupbyNode groupByNode = plan.getRootBlock().getNode(NodeType.GROUP_BY); + EvalNode [] aggEvals = groupByNode.getAggFunctions(); + + List<AggregationFunctionCallEval> list = new ArrayList<AggregationFunctionCallEval>(); + for (int i = 0; i < aggEvals.length; i++) { + list.addAll(EvalTreeUtil.findDistinctAggFunction(aggEvals[i])); + } + assertEquals(2, list.size()); + + Set<String> result = Sets.newHashSet("max", "sum"); + for (AggregationFunctionCallEval eval : list) { + assertTrue(result.contains(eval.getName())); + } + } + + @Test + public final void testIsJoinQual() throws TajoException { + EvalNode evalNode = getRootSelection("select score from people where people.score > people.age"); + assertFalse(EvalTreeUtil.isJoinQual(evalNode, true)); + } + + @Test + public final void testIsJoinQual2() throws TajoException { + EvalNode evalNode = getRootSelection( + "select score from people where substr(people.score::text,1,1) > substr(people.age::text,1,1)"); + assertFalse(EvalTreeUtil.isJoinQual(evalNode, true)); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tajo/blob/a4106883/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestIntervalType.java ---------------------------------------------------------------------- diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestIntervalType.java b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestIntervalType.java new file mode 100644 index 0000000..9f9d294 --- /dev/null +++ b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/TestIntervalType.java @@ -0,0 +1,124 @@ +/** + * 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.eval; + +import org.apache.tajo.exception.InvalidOperationException; +import org.apache.tajo.exception.TajoException; +import org.junit.Test; + +import static org.junit.Assert.fail; + +public class TestIntervalType extends ExprTestBase { + @Test + public void testIntervalPostgresqlCase() throws TajoException { + + // http://www.postgresql.org/docs/8.2/static/functions-datetime.html + testSimpleEval("select date '2001-09-28' + 7", new String[]{"2001-10-05"}); + testSimpleEval("select date '2001-09-28' + interval '1 hour'", + new String[]{"2001-09-28 01:00:00"}); + + testSimpleEval("select date '2001-09-28' + time '03:00'", + new String[]{"2001-09-28 03:00:00"}); + testSimpleEval("select time '03:00' + date '2001-09-28'", + new String[]{"2001-09-28 03:00:00"}); + testSimpleEval("select interval '1 day' + interval '1 hour'", new String[]{"1 day 01:00:00"}); + + testSimpleEval("select timestamp '2001-09-28 01:00' + interval '23 hours'", + new String[]{"2001-09-29 00:00:00"}); + + testSimpleEval("select time '01:00' + interval '3 hours'", new String[]{"04:00:00"}); + + testSimpleEval("select date '2001-10-01' - date '2001-09-28'", new String[]{"3"}); + testSimpleEval("select date '2001-10-01' - 7", new String[]{"2001-09-24"}); + testSimpleEval("select date '2001-09-28' - interval '1 hour'", + new String[]{"2001-09-27 23:00:00"}); + + testSimpleEval("select time '05:00' - time '03:00'", new String[]{"02:00:00"}); + testSimpleEval("select time '05:00' - interval '2 hours'", new String[]{"03:00:00"}); + testSimpleEval("select timestamp '2001-09-28 23:00' - interval '23 hours'", + new String[]{"2001-09-28 00:00:00"}); + + testSimpleEval("select interval '1 day' - interval '1 hour'", new String[]{"23:00:00"}); + + testSimpleEval("select timestamp '2001-09-29 03:00' - timestamp '2001-09-27 12:00'", new String[]{"1 day 15:00:00"}); + testSimpleEval("select 900 * interval '1 second'", new String[]{"00:15:00"}); + testSimpleEval("select 21 * interval '1 day'", new String[]{"21 days"}); + testSimpleEval("select 3.5 * interval '1 hour'", new String[]{"03:30:00"}); + testSimpleEval("select interval '1 hour' / 1.5", new String[]{"00:40:00"}); + } + + @Test + public void testCaseByCase() throws Exception { + testSimpleEval("select date '2001-08-28' + interval '10 day 1 hour'", + new String[]{"2001-09-07 01:00:00"}); + testSimpleEval("select interval '10 day 01:00:00' + date '2001-08-28'", + new String[]{"2001-09-07 01:00:00"}); + testSimpleEval("select time '10:20:30' + interval '1 day 01:00:00'", + new String[]{"11:20:30"}); + testSimpleEval("select interval '1 day 01:00:00' + time '10:20:30'", + new String[]{"11:20:30"}); + testSimpleEval("select time '10:20:30' - interval '1 day 01:00:00'", + new String[]{"09:20:30"}); + + testSimpleEval("select (interval '1 month 20 day' + interval '50 day')", new String[]{"1 month 70 days"}); + testSimpleEval("select date '2013-01-01' + interval '1 month 70 day'", + new String[]{"2013-04-12 00:00:00"}); + testSimpleEval("select date '2013-01-01' + (interval '1 month 20 day' + interval '50 day')", + new String[]{"2013-04-12 00:00:00"}); + testSimpleEval("select interval '1 month 70 day' + date '2013-01-01'", + new String[]{"2013-04-12 00:00:00"}); + testSimpleEval("select date '2013-01-01' - interval '1 month 70 day'", + new String[]{"2012-09-22 00:00:00"}); + + testSimpleEval("select timestamp '2001-09-28 23:00' - interval '1 month 2 day 10:20:30'", + new String[]{"2001-08-26 12:39:30"}); + testSimpleEval("select timestamp '2001-09-28 23:00' + interval '1 month 2 day 10:20:30'", + new String[]{"2001-10-31 09:20:30"}); + testSimpleEval("select interval '1 month 2 day 10:20:30' + timestamp '2001-09-28 23:00'", + new String[]{"2001-10-31 09:20:30"}); + + + testSimpleEval("select interval '5 month' / 3", new String[]{"1 month 20 days"}); + + // Notice: Different from postgresql result(13 days 01:02:36.4992) because of double type precision. + testSimpleEval("select interval '1 month' / 2.3", new String[]{"13 days 01:02:36.522"}); + + testSimpleEval("select interval '1 month' * 2.3", new String[]{"2 months 9 days"}); + testSimpleEval("select interval '3 year 5 month 1 hour' / 1.5", new String[]{"2 years 3 months 10 days 00:40:00"}); + + testSimpleEval("select date '2001-09-28' - time '03:00'", + new String[]{"2001-09-27 21:00:00"}); + + testSimpleEval("select date '2014-03-20' + interval '1 day'", + new String[]{"2014-03-21 00:00:00"}); + + testSimpleEval("select date '2014-03-20' - interval '1 day'", + new String[]{"2014-03-19 00:00:00"}); + } + + @Test + public void testWrongFormatLiteral() throws Exception { + try { + testSimpleEval("select interval '1 month 2 day 23 hours 10:20:30'", new String[]{"DUMMY"}); + fail("hour and time format can not be used at the same time in interval."); + } catch (InvalidOperationException e) { + //success + } + } +}
