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
+    }
+  }
+}