You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hy...@apache.org on 2015/08/14 16:30:26 UTC
[47/51] [partial] tajo git commit: TAJO-1761: Separate an integration
unit test kit into an independent module.
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
+ }
+ }
+}