tajo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hyun...@apache.org
Subject [34/51] [partial] TAJO-22: The package prefix should be org.apache.tajo. (DaeMyung Kang via hyunsik)
Date Tue, 02 Jul 2013 14:16:28 GMT
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/QueryStatus.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/QueryStatus.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/QueryStatus.java
new file mode 100644
index 0000000..cdde9de
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/QueryStatus.java
@@ -0,0 +1,79 @@
+/**
+ * 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;
+
+import org.apache.tajo.QueryId;
+import org.apache.tajo.TajoProtos.QueryState;
+import org.apache.tajo.client.ClientProtocol.GetQueryStatusResponse;
+
+public class QueryStatus {
+  private QueryId queryId;
+  private QueryState state;
+  private float progress;
+  private long submitTime;
+  private long initTime;
+  private long finishTime;
+  private boolean hasResult;
+  private String errorText;
+
+  public QueryStatus(GetQueryStatusResponse proto) {
+    queryId = new QueryId(proto.getQueryId());
+    state = proto.getState();
+    progress = proto.getProgress();
+    submitTime = proto.getSubmitTime();
+    initTime = proto.getInitTime();
+    finishTime = proto.getFinishTime();
+    hasResult = proto.getHasResult();
+    if (proto.hasErrorMessage()) {
+      errorText = proto.getErrorMessage();
+    }
+  }
+
+  public QueryId getQueryId() {
+    return this.queryId;
+  }
+
+  public QueryState getState() {
+    return this.state;
+  }
+
+  public float getProgress() {
+    return progress;
+  }
+
+  public long getSubmitTime() {
+    return this.submitTime;
+  }
+
+  public long getInitTime() {
+    return this.initTime;
+  }
+
+  public long getFinishTime() {
+    return this.finishTime;
+  }
+
+  public boolean hasResult() {
+    return this.hasResult;
+  }
+
+  public String getErrorMessage() {
+    return errorText;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/ResultSetUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/ResultSetUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/ResultSetUtil.java
new file mode 100644
index 0000000..7644e97
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/ResultSetUtil.java
@@ -0,0 +1,49 @@
+/**
+ * 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;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+
+public class ResultSetUtil {
+  public static String prettyFormat(ResultSet res) throws SQLException {
+    StringBuilder sb = new StringBuilder();
+    ResultSetMetaData rsmd = res.getMetaData();
+    int numOfColumns = rsmd.getColumnCount();
+
+    for (int i = 1; i <= numOfColumns; i++) {
+      if (i > 1) sb.append(",  ");
+      String columnName = rsmd.getColumnName(i);
+      sb.append(columnName);
+    }
+    sb.append("\n-------------------------------\n");
+
+    while (res.next()) {
+      for (int i = 1; i <= numOfColumns; i++) {
+        if (i > 1) sb.append(",  ");
+        String columnValue = res.getObject(i).toString();
+        sb.append(columnValue);
+      }
+      sb.append("\n");
+    }
+
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/TajoClient.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/TajoClient.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/TajoClient.java
new file mode 100644
index 0000000..6b5832c
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/client/TajoClient.java
@@ -0,0 +1,297 @@
+/**
+ * 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;
+
+import com.google.protobuf.ServiceException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.net.NetUtils;
+import org.apache.tajo.QueryId;
+import org.apache.tajo.TajoProtos.QueryState;
+import org.apache.tajo.catalog.CatalogUtil;
+import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.catalog.TableMeta;
+import org.apache.tajo.client.ClientProtocol.*;
+import org.apache.tajo.conf.TajoConf;
+import org.apache.tajo.conf.TajoConf.ConfVars;
+import org.apache.tajo.engine.query.ResultSetImpl;
+import org.apache.tajo.rpc.ProtoBlockingRpcClient;
+import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos.StringProto;
+import org.apache.tajo.util.TajoIdUtils;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.sql.ResultSet;
+import java.util.List;
+
+public class TajoClient {
+  private final Log LOG = LogFactory.getLog(TajoClient.class);
+
+  private final TajoConf conf;
+  private ProtoBlockingRpcClient client;
+  private ClientProtocolService.BlockingInterface service;
+
+  public TajoClient(TajoConf conf) throws IOException {
+    this.conf = conf;
+    String masterAddr = this.conf.getVar(ConfVars.CLIENT_SERVICE_ADDRESS);
+    InetSocketAddress addr = NetUtils.createSocketAddr(masterAddr);
+    connect(addr);
+  }
+
+  public TajoClient(InetSocketAddress addr) throws IOException {
+    this.conf = new TajoConf();
+    connect(addr);
+  }
+
+  public TajoClient(String hostname, int port) throws IOException {
+    this.conf = new TajoConf();
+    connect(NetUtils.createSocketAddr(hostname, port));
+  }
+
+  private void connect(InetSocketAddress addr) throws IOException {
+    try {
+      client = new ProtoBlockingRpcClient(ClientProtocol.class, addr);
+      service = client.getStub();
+    } catch (Exception e) {
+      throw new IOException(e);
+    }
+
+    LOG.info("connected to tajo cluster (" +
+        org.apache.tajo.util.NetUtils.getIpPortString(addr) + ")");
+  }
+
+  public void close() {
+    client.close();
+  }
+
+  public boolean isConnected() {
+    return client.isConnected();
+  }
+
+  /**
+   * It submits a query statement and get a response immediately.
+   * The response only contains a query id, and submission status.
+   * In order to get the result, you should use {@link #getQueryResult(org.apache.tajo.QueryId)}
+   * or {@link #getQueryResultAndWait(org.apache.tajo.QueryId)}.
+   */
+  public SubmitQueryRespose executeQuery(String tql) throws ServiceException {
+    QueryRequest.Builder builder = QueryRequest.newBuilder();
+    builder.setQuery(tql);
+
+    return service.submitQuery(null, builder.build());
+  }
+
+  /**
+   * It submits a query statement and get a response.
+   * The main difference from {@link #executeQuery(String)}
+   * is a blocking method. So, this method is wait for
+   * the finish of the submitted query.
+   *
+   * @return If failed, return null.
+   */
+  public ResultSet executeQueryAndGetResult(String tql)
+      throws ServiceException, IOException {
+    QueryRequest.Builder builder = QueryRequest.newBuilder();
+    builder.setQuery(tql);
+    SubmitQueryRespose response = service.submitQuery(null, builder.build());
+    QueryId queryId = new QueryId(response.getQueryId());
+    if (queryId.equals(TajoIdUtils.NullQueryId)) {
+      return null;
+    }
+
+    return getQueryResultAndWait(queryId);
+  }
+
+  public QueryStatus getQueryStatus(QueryId queryId) throws ServiceException {
+    GetQueryStatusRequest.Builder builder
+        = GetQueryStatusRequest.newBuilder();
+    builder.setQueryId(queryId.getProto());
+
+    GetQueryStatusResponse res = service.getQueryStatus(null,
+        builder.build());
+
+    return new QueryStatus(res);
+  }
+
+  private static boolean isQueryRunnning(QueryState state) {
+    return state == QueryState.QUERY_NEW ||
+        state == QueryState.QUERY_INIT ||
+        state == QueryState.QUERY_RUNNING;
+  }
+
+  public ResultSet getQueryResult(QueryId queryId)
+      throws ServiceException, IOException {
+    if (queryId.equals(TajoIdUtils.NullQueryId)) {
+      return null;
+    }
+
+    TableDesc tableDesc = getResultDesc(queryId);
+    return new ResultSetImpl(conf, tableDesc.getPath());
+  }
+
+  public ResultSet getQueryResultAndWait(QueryId queryId)
+      throws ServiceException, IOException {
+    if (queryId.equals(TajoIdUtils.NullQueryId)) {
+      return null;
+    }
+    QueryStatus status = getQueryStatus(queryId);
+
+    while(status != null && isQueryRunnning(status.getState())) {
+      try {
+        Thread.sleep(500);
+      } catch (InterruptedException e) {
+        e.printStackTrace();
+      }
+
+      status = getQueryStatus(queryId);
+    }
+
+    if (status.getState() == QueryState.QUERY_SUCCEEDED) {
+      if (status.hasResult()) {
+        return getQueryResult(queryId);
+      } else {
+        return null;
+      }
+
+    } else {
+      LOG.error(status.getErrorMessage());
+
+      return null;
+    }
+  }
+
+  public TableDesc getResultDesc(QueryId queryId) throws ServiceException {
+    if (queryId.equals(TajoIdUtils.NullQueryId)) {
+      return null;
+    }
+
+    GetQueryResultRequest.Builder builder = GetQueryResultRequest.newBuilder();
+    builder.setQueryId(queryId.getProto());
+    GetQueryResultResponse response = service.getQueryResult(null,
+        builder.build());
+
+    return CatalogUtil.newTableDesc(response.getTableDesc());
+  }
+
+  public boolean updateQuery(String tql) throws ServiceException {
+    QueryRequest.Builder builder = QueryRequest.newBuilder();
+    builder.setQuery(tql);
+
+    ResultCode resultCode =
+        service.updateQuery(null, builder.build()).getResultCode();
+    return resultCode == ResultCode.OK;
+  }
+
+  public boolean existTable(String name) throws ServiceException {
+    StringProto.Builder builder = StringProto.newBuilder();
+    builder.setValue(name);
+    return service.existTable(null, builder.build()).getValue();
+  }
+
+  public TableDesc attachTable(String name, String path)
+      throws ServiceException {
+    AttachTableRequest.Builder builder = AttachTableRequest.newBuilder();
+    builder.setName(name);
+    builder.setPath(path);
+    TableResponse res = service.attachTable(null, builder.build());
+    return CatalogUtil.newTableDesc(res.getTableDesc());
+  }
+
+  public TableDesc attachTable(String name, Path path)
+      throws ServiceException {
+    return attachTable(name, path.toString());
+  }
+
+  public boolean detachTable(String name) throws ServiceException {
+    StringProto.Builder builder = StringProto.newBuilder();
+    builder.setValue(name);
+    return service.detachTable(null, builder.build()).getValue();
+  }
+
+  public TableDesc createTable(String name, Path path, TableMeta meta)
+      throws ServiceException {
+    CreateTableRequest.Builder builder = CreateTableRequest.newBuilder();
+    builder.setName(name);
+    builder.setPath(path.toString());
+    builder.setMeta(meta.getProto());
+    TableResponse res = service.createTable(null, builder.build());
+    return CatalogUtil.newTableDesc(res.getTableDesc());
+  }
+
+  public boolean dropTable(String name) throws ServiceException {
+    StringProto.Builder builder = StringProto.newBuilder();
+    builder.setValue(name);
+    return service.dropTable(null, builder.build()).getValue();
+  }
+
+  public List<String> getClusterInfo() {
+    return null;
+  }
+
+  /**
+   * Get a list of table names. All table and column names are
+   * represented as lower-case letters.
+   */
+  public List<String> getTableList() throws ServiceException {
+    GetTableListRequest.Builder builder = GetTableListRequest.newBuilder();
+    GetTableListResponse res = service.getTableList(null, builder.build());
+    return res.getTablesList();
+  }
+
+  public TableDesc getTableDesc(String tableName) throws ServiceException {
+    GetTableDescRequest.Builder build = GetTableDescRequest.newBuilder();
+    build.setTableName(tableName);
+    TableResponse res = service.getTableDesc(null, build.build());
+    if (res == null) {
+      return null;
+    } else {
+      return CatalogUtil.newTableDesc(res.getTableDesc());
+    }
+  }
+
+  public boolean killQuery(QueryId queryId)
+      throws ServiceException, IOException {
+
+    QueryStatus status = getQueryStatus(queryId);
+
+    try {
+      /* send a kill to the TM */
+      service.killQuery(null, queryId.getProto());
+      long currentTimeMillis = System.currentTimeMillis();
+      long timeKillIssued = currentTimeMillis;
+      while ((currentTimeMillis < timeKillIssued + 10000L) && (status.getState()
+          != QueryState.QUERY_KILLED)) {
+        try {
+          Thread.sleep(1000L);
+        } catch(InterruptedException ie) {
+          /** interrupted, just break */
+          break;
+        }
+        currentTimeMillis = System.currentTimeMillis();
+        status = getQueryStatus(queryId);
+      }
+    } catch(ServiceException io) {
+      LOG.debug("Error when checking for application status", io);
+      return false;
+    }
+
+    return true;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AggFuncCallEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AggFuncCallEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AggFuncCallEval.java
new file mode 100644
index 0000000..0e46c32
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AggFuncCallEval.java
@@ -0,0 +1,111 @@
+/**
+ * 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.gson.annotations.Expose;
+import org.apache.tajo.catalog.FunctionDesc;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.catalog.function.AggFunction;
+import org.apache.tajo.catalog.function.FunctionContext;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.engine.json.GsonCreator;
+import org.apache.tajo.storage.Tuple;
+import org.apache.tajo.storage.VTuple;
+
+public class AggFuncCallEval extends FuncEval implements Cloneable {
+  @Expose protected AggFunction instance;
+  @Expose boolean firstPhase = false;
+  private Tuple params;
+
+  public AggFuncCallEval(FunctionDesc desc, AggFunction instance, EvalNode[] givenArgs) {
+    super(Type.AGG_FUNCTION, desc, givenArgs);
+    this.instance = instance;
+  }
+
+  @Override
+  public EvalContext newContext() {
+    AggFunctionCtx newCtx = new AggFunctionCtx(argEvals, instance.newContext());
+
+    return newCtx;
+  }
+
+  @Override
+  public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
+    AggFunctionCtx localCtx = (AggFunctionCtx) ctx;
+    if (params == null) {
+      this.params = new VTuple(argEvals.length);
+    }
+
+    if (argEvals != null) {
+      params.clear();
+
+      for (int i = 0; i < argEvals.length; i++) {
+        argEvals[i].eval(localCtx.argCtxs[i], schema, tuple);
+        params.put(i, argEvals[i].terminate(localCtx.argCtxs[i]));
+      }
+    }
+
+    if (firstPhase) {
+      instance.eval(localCtx.funcCtx, params);
+    } else {
+      instance.merge(localCtx.funcCtx, params);
+    }
+  }
+
+  @Override
+  public Datum terminate(EvalContext ctx) {
+    if (firstPhase) {
+      return instance.getPartialResult(((AggFunctionCtx)ctx).funcCtx);
+    } else {
+      return instance.terminate(((AggFunctionCtx)ctx).funcCtx);
+    }
+  }
+
+  @Override
+  public DataType[] getValueType() {
+    if (firstPhase) {
+      return instance.getPartialResultType();
+    } else {
+      return funcDesc.getReturnType();
+    }
+  }
+
+  public String toJSON() {
+	  return GsonCreator.getInstance().toJson(this, EvalNode.class);
+  }
+
+  public Object clone() throws CloneNotSupportedException {
+    AggFuncCallEval agg = (AggFuncCallEval) super.clone();
+    return agg;
+  }
+
+  public void setFirstPhase() {
+    this.firstPhase = true;
+  }
+
+  protected class AggFunctionCtx extends FuncCallCtx {
+    FunctionContext funcCtx;
+
+    AggFunctionCtx(EvalNode [] argEvals, FunctionContext funcCtx) {
+      super(argEvals);
+      this.funcCtx = funcCtx;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicException.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicException.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicException.java
new file mode 100644
index 0000000..9dba6df
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicException.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.eval;
+
+public class AlgebraicException extends RuntimeException {
+  private static final long serialVersionUID = -1813125460274622006L;
+  
+  public AlgebraicException() {
+  }
+
+  public AlgebraicException(String message) {
+    super(message);
+  }
+
+  public AlgebraicException(Throwable cause) {
+    super(cause);
+  }
+
+  public AlgebraicException(String message, Throwable cause) {
+    super(message, cause);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java
new file mode 100644
index 0000000..46a3cdb
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java
@@ -0,0 +1,289 @@
+/**
+ * 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.Column;
+
+import java.util.Map;
+
+public class AlgebraicUtil {
+  
+  /**
+   * Transpose a given comparison expression into the expression 
+   * where the variable corresponding to the target is placed 
+   * on the left-hand side.
+   * 
+   * @param expr
+   * @param target
+   * @return Transposed expression
+   */
+  public static EvalNode transpose(EvalNode expr, Column target) {
+    EvalNode commutated = null;
+    // If the variable is in the right term, inverse the expr.
+    if (!EvalTreeUtil.containColumnRef(expr.getLeftExpr(), target)) {
+      // the commutate method works with a copy of the expr
+      commutated = commutate(expr);
+    } else {
+      try {
+        commutated = (EvalNode) expr.clone();
+      } catch (CloneNotSupportedException e) {
+        throw new AlgebraicException(e);
+      }
+    }
+
+    return _transpose(commutated, target);
+  }
+  
+  private static EvalNode _transpose(EvalNode _expr, Column target) {
+     EvalNode expr = simplify(_expr);
+     
+     if (isSingleVar(expr.getLeftExpr())) {
+       return expr;
+     }
+     
+     EvalNode left = expr.getLeftExpr();     
+     EvalNode lTerm = null;
+     EvalNode rTerm = null;
+     
+    if (left.getType() == EvalNode.Type.PLUS
+        || left.getType() == EvalNode.Type.MINUS
+        || left.getType() == EvalNode.Type.MULTIPLY
+        || left.getType() == EvalNode.Type.DIVIDE) {
+      
+      // If the left-left term is a variable, the left-right term is transposed.
+      if(EvalTreeUtil.containColumnRef(left.getLeftExpr(), target)) {
+        PartialBinaryExpr tmpTerm = splitRightTerm(left);
+        tmpTerm.type = inverseOperator(tmpTerm.type);
+        tmpTerm.setLeftExpr(expr.getRightExpr());
+        lTerm = left.getLeftExpr();
+        rTerm = new BinaryEval(tmpTerm);
+      } else { 
+        // Otherwise, the left-right term is transposed into the left-left term.
+        PartialBinaryExpr tmpTerm = splitLeftTerm(left);
+        tmpTerm.type = inverseOperator(tmpTerm.type);
+        tmpTerm.setLeftExpr(expr.getRightExpr());        
+        lTerm = left.getRightExpr();
+        rTerm = new BinaryEval(tmpTerm);    
+      }
+    }
+    
+    return _transpose(new BinaryEval(expr.getType(), lTerm, rTerm), target);
+  }
+  
+  /**
+   * Inverse a given operator (+, -, *, /)
+   * 
+   * @param type
+   * @return inversed operator type
+   */
+  public static EvalNode.Type inverseOperator(EvalNode.Type type) {
+    switch (type) {
+    case PLUS:
+      return EvalNode.Type.MINUS;
+    case MINUS:
+      return EvalNode.Type.PLUS;
+    case MULTIPLY:
+      return EvalNode.Type.DIVIDE;
+    case DIVIDE:
+      return EvalNode.Type.MULTIPLY;
+    default : throw new AlgebraicException("ERROR: cannot inverse the operator: " 
+      + type);
+    }
+  }
+  
+  /**
+   * Examine if a given expr is a variable.
+   * 
+   * @param node
+   * @return true if a given expr is a variable.
+   */
+  private static boolean isSingleVar(EvalNode node) {
+    if (node.getType() == EvalNode.Type.FIELD) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+  
+  /**
+   * Simplify the given expr. That is, all subexprs consisting of only constants
+   * are calculated immediately.
+   * 
+   * @param expr to be simplified
+   * @return the simplified expr
+   */
+  public static EvalNode simplify(EvalNode expr) {
+    EvalNode left = expr.getLeftExpr();
+    EvalNode right = expr.getRightExpr();
+    
+    switch (expr.getType()) {
+    case AND:
+    case OR:
+    case EQUAL:
+    case LTH:
+    case LEQ:
+    case GTH:
+    case GEQ:
+      left = simplify(left);
+      right = simplify(right);      
+      return new BinaryEval(expr.getType(), left, right);    
+    
+    case PLUS:
+    case MINUS:
+    case MULTIPLY:
+    case DIVIDE:
+      left = simplify(left);
+      right = simplify(right);
+      
+      // If both are constants, they can be evaluated immediately.
+      if (left.getType() == EvalNode.Type.CONST
+          && right.getType() == EvalNode.Type.CONST) {
+        EvalContext exprCtx = expr.newContext();
+        expr.eval(exprCtx, null, null);
+        return new ConstEval(expr.terminate(exprCtx));
+      } else {
+        return new BinaryEval(expr.getType(), left, right);            
+      }
+      
+    case CONST:
+      return expr;
+      
+    default: new AlgebraicException("Wrong expression: " + expr);
+    }
+    return expr;
+  }
+  
+  /** 
+   * @param expr to be evaluated if the expr includes one variable
+   * @return true if expr has only one field
+   */
+  public static boolean containSingleVar(EvalNode expr) {
+    Map<EvalNode.Type, Integer> counter = EvalTreeUtil.getExprCounters(expr);
+    
+    int sum = 0;
+    for (Integer cnt : counter.values()) {      
+      sum += cnt;
+    }
+    
+    if (sum == 1 && counter.get(EvalNode.Type.FIELD) == 1) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+  
+  /**
+   * Split the left term and transform it into the right deep expression.
+   * 
+   * @param expr - notice the left term of this expr will be eliminated 
+   * after done.
+   * @return the separated expression changed into the right deep expression.  
+   * For example, the expr 'x * y' is transformed into '* x'.  
+   *
+   */
+  public static PartialBinaryExpr splitLeftTerm(EvalNode expr) {
+    
+    if (!(expr.getType() == EvalNode.Type.PLUS
+        || expr.getType() == EvalNode.Type.MINUS
+        || expr.getType() == EvalNode.Type.MULTIPLY
+        || expr.getType() == EvalNode.Type.DIVIDE)) {
+      throw new AlgebraicException("Invalid algebraic operation: " + expr);
+    }
+    
+    if (expr.getLeftExpr().getType() != EvalNode.Type.CONST) {
+      return splitLeftTerm(expr.getLeftExpr());
+    }
+    
+    PartialBinaryExpr splitted = 
+        new PartialBinaryExpr(expr.getType(), null, expr.getLeftExpr());
+    expr.setLeftExpr(null);
+    return splitted;
+  }
+  
+  /**
+   * Split the left term and transform it into the right deep expression.
+   * 
+   * @param expr - to be splited
+   * @return the separated expression changed into the right deep expression.
+   * For example, the expr 'x * y' is transformed into '* y'. 
+   *
+   * @throws CloneNotSupportedException
+   */
+  public static PartialBinaryExpr splitRightTerm(EvalNode expr) {
+    
+    if (!(expr.getType() == EvalNode.Type.PLUS
+        || expr.getType() == EvalNode.Type.MINUS
+        || expr.getType() == EvalNode.Type.MULTIPLY
+        || expr.getType() == EvalNode.Type.DIVIDE)) {
+      throw new AlgebraicException("Invalid algebraic operation: " + expr);
+    }
+    
+    if (expr.getRightExpr().getType() != EvalNode.Type.CONST) {
+      return splitRightTerm(expr.getRightExpr());
+    }
+    
+    PartialBinaryExpr splitted = 
+        new PartialBinaryExpr(expr.getType(), null, expr.getRightExpr());
+    expr.setRightExpr(null);
+    return splitted;
+  }
+  
+  /**
+   * Commutate two terms which are added, subtracted and multiplied.
+   * 
+   * @param inputExpr
+   * @return
+   */
+  public static EvalNode commutate(EvalNode inputExpr) {
+    EvalNode expr;
+    switch (inputExpr.getType()) {
+    case AND:
+    case OR:
+    case EQUAL:
+    case PLUS:
+    case MINUS:
+    case MULTIPLY: // these types can be commutated w/o any change
+      expr = EvalTreeFactory.create(inputExpr.getType(),
+          inputExpr.getRightExpr(), inputExpr.getLeftExpr());
+      break;
+      
+    case GTH:
+      expr = EvalTreeFactory.create(EvalNode.Type.LTH,
+          inputExpr.getRightExpr(), inputExpr.getLeftExpr());
+      break;
+    case GEQ:
+      expr = EvalTreeFactory.create(EvalNode.Type.LEQ,
+          inputExpr.getRightExpr(), inputExpr.getLeftExpr());
+      break;
+    case LTH:
+      expr = EvalTreeFactory.create(EvalNode.Type.GTH,
+          inputExpr.getRightExpr(), inputExpr.getLeftExpr());
+      break;
+    case LEQ:
+      expr = EvalTreeFactory.create(EvalNode.Type.GEQ,
+          inputExpr.getRightExpr(), inputExpr.getLeftExpr());
+      break;
+      
+    default :
+      throw new AlgebraicException("Cannot commutate the expr: " + inputExpr);
+    }
+    
+    return expr;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
new file mode 100644
index 0000000..a30e77c
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
@@ -0,0 +1,234 @@
+/**
+ * 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.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.gson.Gson;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.CatalogUtil;
+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.GsonCreator;
+import org.apache.tajo.engine.utils.SchemaUtil;
+import org.apache.tajo.storage.Tuple;
+
+public class BinaryEval extends EvalNode implements Cloneable {
+	@Expose private DataType[] returnType = null;
+
+  private class BinaryEvalCtx implements EvalContext {
+    EvalContext left;
+    EvalContext right;
+  }
+
+	/**
+	 * @param type
+	 */
+	public BinaryEval(Type type, EvalNode left, EvalNode right) {
+		super(type, left, right);		
+		Preconditions.checkNotNull(type);
+		Preconditions.checkNotNull(left);
+		Preconditions.checkNotNull(right);
+		
+		if(
+			type == Type.AND ||
+			type == Type.OR ||
+			type == Type.EQUAL ||
+			type == Type.LTH ||
+			type == Type.GTH ||
+			type == Type.LEQ ||
+			type == Type.GEQ
+		) {
+			this.returnType = CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.BOOLEAN);
+		} else if (
+			type == Type.PLUS ||
+			type == Type.MINUS ||
+			type == Type.MULTIPLY ||
+			type == Type.DIVIDE ||
+      type == Type.MODULAR
+		) {
+			this.returnType = SchemaUtil.newNoNameSchema(determineType(left.getValueType()[0],
+				right.getValueType()[0]));
+		}
+	}
+
+  public BinaryEval(PartialBinaryExpr expr) {
+	  this(expr.type, expr.leftExpr, expr.rightExpr);
+	}
+
+  @Override
+  public EvalContext newContext() {
+    BinaryEvalCtx newCtx =  new BinaryEvalCtx();
+    newCtx.left = leftExpr.newContext();
+    newCtx.right = rightExpr.newContext();
+
+    return newCtx;
+  }
+
+  private DataType determineType(DataType left, DataType right) {
+    switch (left.getType()) {
+      case INT4: {
+        switch(right.getType()) {
+          case INT2:
+          case INT4: return CatalogUtil.newDataTypeWithoutLen(TajoDataTypes.Type.INT4);
+          case INT8: return CatalogUtil.newDataTypeWithoutLen(TajoDataTypes.Type.INT8);
+          case FLOAT4: return CatalogUtil.newDataTypeWithoutLen(TajoDataTypes.Type.FLOAT4);
+          case FLOAT8: return CatalogUtil.newDataTypeWithoutLen(TajoDataTypes.Type.FLOAT8);
+          default: throw new InvalidEvalException();
+        }
+      }
+
+      case INT8: {
+        switch(right.getType()) {
+          case INT2:
+          case INT4:
+          case INT8: return CatalogUtil.newDataTypeWithoutLen(TajoDataTypes.Type.INT8);
+          case FLOAT4:
+          case FLOAT8: return CatalogUtil.newDataTypeWithoutLen(TajoDataTypes.Type.FLOAT8);
+          default: throw new InvalidEvalException();
+        }
+      }
+
+      case FLOAT4: {
+        switch(right.getType()) {
+          case INT2:
+          case INT4:
+          case INT8:
+          case FLOAT4:
+          case FLOAT8: return CatalogUtil.newDataTypeWithoutLen(TajoDataTypes.Type.FLOAT8);
+          default: throw new InvalidEvalException();
+        }
+      }
+
+      case FLOAT8: {
+        switch(right.getType()) {
+          case INT2:
+          case INT4:
+          case INT8:
+          case FLOAT4:
+          case FLOAT8: return CatalogUtil.newDataTypeWithoutLen(TajoDataTypes.Type.FLOAT8);
+          default: throw new InvalidEvalException();
+        }
+      }
+
+      default: return left;
+    }
+  }
+
+	/* (non-Javadoc)
+	 * @see nta.query.executor.eval.Expr#evalBool(Tuple)
+	 */
+	@Override
+	public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
+    BinaryEvalCtx binCtx = (BinaryEvalCtx) ctx;
+	  leftExpr.eval(binCtx == null ? null : binCtx.left, schema, tuple);
+    rightExpr.eval(binCtx == null ? null : binCtx.right, schema, tuple);
+	}
+
+  @Override
+  public Datum terminate(EvalContext ctx) {
+    BinaryEvalCtx binCtx = (BinaryEvalCtx) ctx;
+
+    switch(type) {
+      case AND:
+        return DatumFactory.createBool(leftExpr.terminate(binCtx.left).asBool()
+            && rightExpr.terminate(binCtx.right).asBool());
+      case OR:
+        return DatumFactory.createBool(leftExpr.terminate(binCtx.left).asBool()
+            || rightExpr.terminate(binCtx.right).asBool());
+
+      case EQUAL:
+        return leftExpr.terminate(binCtx.left).equalsTo(rightExpr.terminate(binCtx.right));
+      case NOT_EQUAL:
+        return DatumFactory.createBool(!leftExpr.terminate(binCtx.left).equalsTo(rightExpr.terminate(binCtx.right)).
+            asBool());
+      case LTH:
+        return leftExpr.terminate(binCtx.left).lessThan(rightExpr.terminate(binCtx.right));
+      case LEQ:
+        return leftExpr.terminate(binCtx.left).lessThanEqual(rightExpr.terminate(binCtx.right));
+      case GTH:
+        return leftExpr.terminate(binCtx.left).greaterThan(rightExpr.terminate(binCtx.right));
+      case GEQ:
+        return leftExpr.terminate(binCtx.left).greaterThanEqual(rightExpr.terminate(binCtx.right));
+
+      case PLUS:
+        return leftExpr.terminate(binCtx.left).plus(rightExpr.terminate(binCtx.right));
+      case MINUS:
+        return leftExpr.terminate(binCtx.left).minus(rightExpr.terminate(binCtx.right));
+      case MULTIPLY:
+        return leftExpr.terminate(binCtx.left).multiply(rightExpr.terminate(binCtx.right));
+      case DIVIDE:
+        return leftExpr.terminate(binCtx.left).divide(rightExpr.terminate(binCtx.right));
+      case MODULAR:
+        return leftExpr.terminate(binCtx.left).modular(rightExpr.terminate(binCtx.right));
+      default:
+        throw new InvalidEvalException("We does not support " + type + " expression yet");
+    }
+  }
+
+  @Override
+	public String getName() {
+		return "?";
+	}
+	
+	@Override
+	public DataType [] getValueType() {
+		if (returnType == null) {
+		  
+		}
+	  return returnType;
+	}
+	
+	public String toString() {
+		return leftExpr +" "+type+" "+rightExpr;
+	}
+	
+	public String toJSON() {
+	  Gson gson = GsonCreator.getInstance();
+	  return gson.toJson(this, EvalNode.class);
+	}
+	
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof BinaryEval) {
+      BinaryEval other = (BinaryEval) obj;
+
+      boolean b1 = this.type == other.type;
+      boolean b2 = leftExpr.equals(other.leftExpr);
+      boolean b3 = rightExpr.equals(other.rightExpr);
+      return b1 && b2 && b3;      
+    }
+    return false;
+  }
+  
+  public int hashCode() {
+    return Objects.hashCode(this.type, leftExpr, rightExpr);
+  }
+  
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    BinaryEval eval = (BinaryEval) super.clone();
+    eval.returnType = returnType;
+    
+    return eval;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
new file mode 100644
index 0000000..4f385b0
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
@@ -0,0 +1,238 @@
+/**
+ * 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.Lists;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.CatalogUtil;
+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.storage.Tuple;
+
+import java.util.List;
+
+public class CaseWhenEval extends EvalNode {
+  @Expose private List<WhenEval> whens = Lists.newArrayList();
+  @Expose private EvalNode elseResult;
+
+  public CaseWhenEval() {
+    super(Type.CASE);
+  }
+
+  public void addWhen(EvalNode condition, EvalNode result) {
+    whens.add(new WhenEval(condition, result));
+  }
+
+  public void setElseResult(EvalNode elseResult) {
+    this.elseResult = elseResult;
+  }
+
+  @Override
+  public EvalContext newContext() {
+    return new CaseContext(whens, elseResult != null ? elseResult.newContext() : null);
+  }
+
+  @Override
+  public DataType [] getValueType() {
+    return whens.get(0).getResultExpr().getValueType();
+  }
+
+  @Override
+  public String getName() {
+    return "?";
+  }
+
+  public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
+    CaseContext caseCtx = (CaseContext) ctx;
+    for (int i = 0; i < whens.size(); i++) {
+      whens.get(i).eval(caseCtx.contexts[i], schema, tuple);
+    }
+
+    if (elseResult != null) { // without else clause
+      elseResult.eval(caseCtx.elseCtx, schema, tuple);
+    }
+  }
+
+  @Override
+  public Datum terminate(EvalContext ctx) {
+    CaseContext caseCtx = (CaseContext) ctx;
+    for (int i = 0; i < whens.size(); i++) {
+      if (whens.get(i).terminate(caseCtx.contexts[i]).asBool()) {
+        return whens.get(i).getThenResult(caseCtx.contexts[i]);
+      }
+    }
+    if (elseResult != null) { // without else clause
+      return elseResult.terminate(caseCtx.elseCtx);
+    } else {
+      return DatumFactory.createNullDatum();
+    }
+  }
+
+  public String toString() {
+    StringBuilder sb = new StringBuilder("CASE\n");
+    for (WhenEval when : whens) {
+     sb.append(when).append("\n");
+    }
+
+    sb.append("ELSE ").append(elseResult).append(" END\n");
+
+    return sb.toString();
+  }
+
+  @Override
+  public void preOrder(EvalNodeVisitor visitor) {
+    visitor.visit(this);
+    for (WhenEval when : whens) {
+      when.preOrder(visitor);
+    }
+    if (elseResult != null) { // without else clause
+      elseResult.preOrder(visitor);
+    }
+  }
+
+  @Override
+  public void postOrder(EvalNodeVisitor visitor) {
+    for (WhenEval when : whens) {
+      when.postOrder(visitor);
+    }
+    if (elseResult != null) { // without else clause
+      elseResult.postOrder(visitor);
+    }
+    visitor.visit(this);
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof CaseWhenEval) {
+      CaseWhenEval other = (CaseWhenEval) obj;
+
+      for (int i = 0; i < other.whens.size(); i++) {
+        if (!whens.get(i).equals(other.whens.get(i))) {
+          return false;
+        }
+      }
+      return elseResult.equals(other.elseResult);
+    } else {
+      return false;
+    }
+  }
+
+  public static class WhenEval extends EvalNode {
+    @Expose private EvalNode condition;
+    @Expose private EvalNode result;
+
+    public WhenEval(EvalNode condition, EvalNode result) {
+      super(Type.WHEN);
+      this.condition = condition;
+      this.result = result;
+    }
+
+    @Override
+    public EvalContext newContext() {
+      return new WhenContext(condition.newContext(), result.newContext());
+    }
+
+    @Override
+    public DataType [] getValueType() {
+      return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.BOOLEAN);
+    }
+
+    @Override
+    public String getName() {
+      return "when?";
+    }
+
+    public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
+      condition.eval(((WhenContext) ctx).condCtx, schema, tuple);
+      result.eval(((WhenContext) ctx).resultCtx, schema, tuple);
+    }
+
+    @Override
+    public Datum terminate(EvalContext ctx) {
+      return condition.terminate(((WhenContext) ctx).condCtx);
+    }
+
+    public EvalNode getConditionExpr() {
+      return this.condition;
+    }
+
+    public EvalNode getResultExpr() {
+      return this.result;
+    }
+
+    public String toString() {
+      return "WHEN " + condition + " THEN " + result;
+    }
+
+    private class WhenContext implements EvalContext {
+      EvalContext condCtx;
+      EvalContext resultCtx;
+
+      public WhenContext(EvalContext condCtx, EvalContext resultCtx) {
+        this.condCtx = condCtx;
+        this.resultCtx = resultCtx;
+      }
+    }
+
+    public Datum getThenResult(EvalContext ctx) {
+      return result.terminate(((WhenContext) ctx).resultCtx);
+    }
+
+    @Override
+    public void preOrder(EvalNodeVisitor visitor) {
+      visitor.visit(this);
+      condition.preOrder(visitor);
+      result.preOrder(visitor);
+    }
+
+    @Override
+    public void postOrder(EvalNodeVisitor visitor) {
+      condition.postOrder(visitor);
+      result.postOrder(visitor);
+      visitor.visit(this);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (obj instanceof WhenEval) {
+       WhenEval other = (WhenEval) obj;
+        return this.condition == other.condition
+            && this.result == other.result;
+      } else {
+        return false;
+      }
+    }
+  }
+
+  private class CaseContext implements EvalContext {
+    EvalContext [] contexts;
+    EvalContext elseCtx;
+
+    CaseContext(List<WhenEval> whens, EvalContext elseCtx) {
+      contexts = new EvalContext[whens.size()];
+      for (int i = 0; i < whens.size(); i++) {
+        contexts[i] = whens.get(i).newContext();
+      }
+      this.elseCtx = elseCtx;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/ConstEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/ConstEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/ConstEval.java
new file mode 100644
index 0000000..7ab019f
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/ConstEval.java
@@ -0,0 +1,125 @@
+/**
+ * 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.base.Objects;
+import com.google.gson.Gson;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.CatalogUtil;
+import org.apache.tajo.common.TajoDataTypes;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.engine.json.GsonCreator;
+
+public class ConstEval extends EvalNode implements Comparable<ConstEval>, Cloneable {
+	@Expose Datum datum = null;
+	
+	public ConstEval(Datum datum) {
+		super(Type.CONST);
+		this.datum = datum;
+	}
+
+  @Override
+  public EvalContext newContext() {
+    return null;
+  }
+
+  @Override
+  public Datum terminate(EvalContext ctx) {
+    return this.datum;
+  }
+
+
+  public Datum getValue() {
+    return this.datum;
+  }
+	
+	public String toString() {
+		return datum.toString();
+	}
+	
+	public String toJSON() {
+		Gson gson = GsonCreator.getInstance();
+		return gson.toJson(this, EvalNode.class);
+	}
+
+  @Override
+	public DataType [] getValueType() {
+		switch(this.datum.type()) {
+      case BOOLEAN: return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.BOOLEAN);
+      case BIT: return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.BIT);
+      case CHAR: return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.CHAR);
+      case INT1: return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.INT1);
+      case INT2: return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.INT2);
+      case INT4: return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.INT4);
+      case INT8: return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.INT8);
+      case FLOAT4: return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.FLOAT4);
+      case FLOAT8 : return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.FLOAT8);
+      case BLOB : return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.BLOB);
+      case TEXT: return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.TEXT);
+      case INET4: return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.INET4);
+      default: return CatalogUtil.newDataTypesWithoutLen(TajoDataTypes.Type.ANY);
+		}
+	}
+
+	@Override
+	public String getName() {
+		return this.datum.toString();
+	}
+	
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof ConstEval) {
+      ConstEval other = (ConstEval) obj;
+
+      if (this.type == other.type && this.datum.equals(other.datum)) {
+        return true;
+      }
+    }
+    return false;
+  }
+  
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(type, datum.type(), datum);
+  }
+  
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    ConstEval eval = (ConstEval) super.clone();
+    eval.datum = datum;
+    
+    return eval;
+  }
+
+  @Override
+  public int compareTo(ConstEval other) {    
+    return datum.compareTo(other.datum);
+  }
+  
+  @Override
+  public void preOrder(EvalNodeVisitor visitor) {
+    visitor.visit(this);
+  }
+  
+  @Override
+  public void postOrder(EvalNodeVisitor visitor) {
+    visitor.visit(this);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalContext.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalContext.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalContext.java
new file mode 100644
index 0000000..00007ce
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalContext.java
@@ -0,0 +1,22 @@
+/**
+ * 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;
+
+public interface EvalContext {
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
new file mode 100644
index 0000000..b6c7276
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
@@ -0,0 +1,155 @@
+/**
+ * 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.gson.Gson;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.engine.json.GsonCreator;
+import org.apache.tajo.storage.Tuple;
+
+public abstract class EvalNode implements Cloneable {
+	@Expose
+	protected Type type;
+	@Expose
+	protected EvalNode leftExpr;
+	@Expose
+	protected EvalNode rightExpr;
+	
+	public EvalNode(Type type) {
+		this.type = type;
+	}
+	
+	public EvalNode(Type type, EvalNode left, EvalNode right) {
+		this(type);
+		this.leftExpr = left;
+		this.rightExpr = right;
+	}
+
+  public abstract EvalContext newContext();
+	
+	public Type getType() {
+		return this.type;
+	}
+	
+	public void setLeftExpr(EvalNode expr) {
+		this.leftExpr = expr;
+	}
+	
+	public EvalNode getLeftExpr() {
+		return this.leftExpr;
+	}
+	
+	public void setRightExpr(EvalNode expr) {
+		this.rightExpr = expr;
+	}
+	
+	public EvalNode getRightExpr() {
+		return this.rightExpr;
+	}
+
+  public EvalNode getExpr(int id) {
+    if (id == 0) {
+      return this.leftExpr;
+    } else if (id == 1) {
+      return this.rightExpr;
+    } else {
+      throw new ArrayIndexOutOfBoundsException("only 0 or 1 is available (" + id + " is not available)");
+    }
+  }
+	
+	public abstract DataType [] getValueType();
+	
+	public abstract String getName();
+	
+	public String toString() {
+		return "("+this.type+"("+leftExpr.toString()+" "+rightExpr.toString()+"))";
+	}
+	
+	public String toJSON() {
+	  Gson gson = GsonCreator.getInstance();
+    return gson.toJson(this, EvalNode.class);
+	}
+	
+	public void eval(EvalContext ctx, Schema schema, Tuple tuple) {}
+
+  public abstract Datum terminate(EvalContext ctx);
+
+	public void preOrder(EvalNodeVisitor visitor) {
+	  visitor.visit(this);
+	  leftExpr.preOrder(visitor);
+	  rightExpr.preOrder(visitor);
+	}
+	
+	public void postOrder(EvalNodeVisitor visitor) {
+	  leftExpr.postOrder(visitor);
+	  rightExpr.postOrder(visitor);	  	  
+	  visitor.visit(this);
+	}
+	
+	public static enum Type {
+    AGG_FUNCTION,
+    AND,
+	  OR,
+	  EQUAL("="),
+    IS,
+	  NOT_EQUAL("<>"),
+	  LTH("<"),
+	  LEQ("<="),
+	  GTH(">"),
+	  GEQ(">="),
+	  NOT("!"),
+	  PLUS("+"),
+    MINUS("-"),
+    MODULAR("%"),
+    MULTIPLY("*"),
+    DIVIDE("/"),
+	  FIELD,
+    FUNCTION,
+    LIKE,
+    CONST,
+    CASE,
+    WHEN;
+
+    private String represent;
+    Type() {
+    }
+    Type(String represent) {
+      this.represent = represent;
+    }
+
+    public String toString() {
+      return represent == null ? this.name() : represent;
+    }
+	}
+
+  public abstract boolean equals(Object obj);
+	
+	@Override
+	public Object clone() throws CloneNotSupportedException {
+	  EvalNode node = (EvalNode) super.clone();
+	  node.type = type;
+	  node.leftExpr = leftExpr != null ? (EvalNode) leftExpr.clone() : null;
+	  node.rightExpr = rightExpr != null ? (EvalNode) rightExpr.clone() : null;
+	  
+	  return node;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java
new file mode 100644
index 0000000..2cac5da
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java
@@ -0,0 +1,23 @@
+/**
+ * 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;
+
+public interface EvalNodeVisitor {
+  public void visit(EvalNode node);
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeFactory.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeFactory.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeFactory.java
new file mode 100644
index 0000000..5d5a9be
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeFactory.java
@@ -0,0 +1,32 @@
+/**
+ * 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.datum.Datum;
+
+public class EvalTreeFactory {
+	public static ConstEval newConst(Datum datum) {
+		return new ConstEval(datum);
+	}
+	
+	public static BinaryEval create(EvalNode.Type type, EvalNode e1, 
+	    EvalNode e2) {
+		return new BinaryEval(type, e1, e2);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
new file mode 100644
index 0000000..4686dc1
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
@@ -0,0 +1,353 @@
+/**
+ * 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.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.engine.eval.EvalNode.Type;
+import org.apache.tajo.engine.parser.QueryBlock.Target;
+import org.apache.tajo.engine.utils.SchemaUtil;
+import org.apache.tajo.exception.InternalException;
+
+import java.util.*;
+
+public class EvalTreeUtil {
+  public static void changeColumnRef(EvalNode node, Column oldName, 
+      Column newName) {
+    node.postOrder(new ChangeColumnRefVisitor(oldName.getQualifiedName(), 
+        newName.getQualifiedName()));
+  }
+  
+  public static void changeColumnRef(EvalNode node, String oldName, 
+      String newName) {
+    node.postOrder(new ChangeColumnRefVisitor(oldName, newName));
+  }
+  
+  public static Set<Column> findDistinctRefColumns(EvalNode node) {
+    DistinctColumnRefFinder finder = new DistinctColumnRefFinder();
+    node.postOrder(finder);
+    return finder.getColumnRefs();
+  }
+  
+  public static List<Column> findAllColumnRefs(EvalNode node) {
+    AllColumnRefFinder finder = new AllColumnRefFinder();
+    node.postOrder(finder);
+    return finder.getColumnRefs();
+  }
+  
+  /**
+   * Convert a list of conjunctive normal forms into a singleton expression.
+   *  
+   * @param evalNode
+   * @return
+   */
+  public static EvalNode transformCNF2Singleton(EvalNode...evalNode) {    
+    if (evalNode.length == 1) {
+      return evalNode[0];
+    }
+    
+    return transformCNF2Singleton_(evalNode, 0);
+  }
+  
+  private static EvalNode transformCNF2Singleton_(EvalNode [] evalNode, int idx) {
+    if (idx == evalNode.length - 2) {
+      return new BinaryEval(Type.AND, evalNode[idx], evalNode[idx + 1]);
+    } else {
+      return new BinaryEval(Type.AND, evalNode[idx], 
+          transformCNF2Singleton_(evalNode, idx + 1));
+    }
+  }
+  
+  /**
+   * Get a list of exprs similar to CNF
+   * 
+   * @param node
+   * @return
+   */
+  public static EvalNode [] getConjNormalForm(EvalNode node) {
+    List<EvalNode> list = new ArrayList<EvalNode>();    
+    getConjNormalForm(node, list);    
+    return list.toArray(new EvalNode[list.size()]);
+  }
+  
+  private static void getConjNormalForm(EvalNode node, List<EvalNode> found) {
+    if (node.getType() == Type.AND) {
+      getConjNormalForm(node.getLeftExpr(), found);
+      getConjNormalForm(node.getRightExpr(), found);
+    } else {
+      found.add(node);
+    }
+  }
+  
+  /**
+   * Compute a schema from a list of exprs.
+   * 
+   * @param inputSchema
+   * @param evalNodes
+   * @return
+   * @throws InternalException
+   */
+  public static Schema getSchemaByExprs(Schema inputSchema, EvalNode [] evalNodes) 
+      throws InternalException {
+    Schema schema = new Schema();
+    for (EvalNode expr : evalNodes) {
+      schema.addColumn(
+          expr.getName(),
+          getDomainByExpr(inputSchema, expr)[0]);
+    }
+    
+    return schema;
+  }
+  
+  public static Schema getSchemaByTargets(Schema inputSchema, Target [] targets) 
+      throws InternalException {
+    Schema schema = new Schema();
+    for (Target target : targets) {
+      schema.addColumn(
+          target.hasAlias() ? target.getAlias() : target.getEvalTree().getName(),
+          getDomainByExpr(inputSchema, target.getEvalTree())[0]);
+    }
+    
+    return schema;
+  }
+  
+  public static DataType[] getDomainByExpr(Schema inputSchema, EvalNode expr)
+      throws InternalException {
+    switch (expr.getType()) {
+    case AND:      
+    case OR:
+    case EQUAL:
+    case NOT_EQUAL:
+    case LTH:
+    case LEQ:
+    case GTH:
+    case GEQ:
+    case PLUS:
+    case MINUS:
+    case MULTIPLY:
+    case DIVIDE:
+    case CONST:
+    case FUNCTION:
+        return expr.getValueType();
+
+    case FIELD:
+      FieldEval fieldEval = (FieldEval) expr;
+      return SchemaUtil.newNoNameSchema(inputSchema.getColumn(fieldEval.getName()).getDataType());
+
+      
+    default:
+      throw new InternalException("Unknown expr type: " 
+          + expr.getType().toString());
+    }
+  }
+  
+  /**
+   * Return all exprs to refer columns corresponding to the target.
+   * 
+   * @param expr 
+   * @param target to be found
+   * @return a list of exprs
+   */
+  public static Collection<EvalNode> getContainExpr(EvalNode expr, Column target) {
+    Set<EvalNode> exprSet = Sets.newHashSet();    
+    getContainExpr(expr, target, exprSet);
+    return exprSet;
+  }
+  
+  /**
+   * Return the counter to count the number of expression types individually.
+   *  
+   * @param expr
+   * @return
+   */
+  public static Map<Type, Integer> getExprCounters(EvalNode expr) {
+    VariableCounter counter = new VariableCounter();
+    expr.postOrder(counter);
+    return counter.getCounter();
+  }
+  
+  private static void getContainExpr(EvalNode expr, Column target, Set<EvalNode> exprSet) {
+    switch (expr.getType()) {
+    case EQUAL:
+    case LTH:
+    case LEQ:
+    case GTH:
+    case GEQ:
+    case NOT_EQUAL:
+      if (containColumnRef(expr, target)) {          
+        exprSet.add(expr);
+      }
+    }    
+  }
+  
+  /**
+   * Examine if the expr contains the column reference corresponding 
+   * to the target column
+   * 
+   * @param expr
+   * @param target
+   * @return
+   */
+  public static boolean containColumnRef(EvalNode expr, Column target) {
+    Set<EvalNode> exprSet = Sets.newHashSet();
+    _containColumnRef(expr, target, exprSet);
+    
+    return exprSet.size() > 0;
+  }
+  
+  private static void _containColumnRef(EvalNode expr, Column target, 
+      Set<EvalNode> exprSet) {
+    switch (expr.getType()) {
+    case FIELD:
+      FieldEval field = (FieldEval) expr;
+      if (field.getColumnName().equals(target.getColumnName())) {
+        exprSet.add(field);
+      }
+      break;
+    case CONST:
+      return;
+    default: 
+      _containColumnRef(expr.getLeftExpr(), target, exprSet);
+      _containColumnRef(expr.getRightExpr(), target, exprSet);
+    }    
+  }
+
+  public static boolean isComparisonOperator(EvalNode expr) {
+    return expr.getType() == Type.EQUAL ||
+        expr.getType() == Type.LEQ ||
+        expr.getType() == Type.LTH ||
+        expr.getType() == Type.GEQ ||
+        expr.getType() == Type.GTH;
+  }
+
+  public static boolean isJoinQual(EvalNode expr) {
+    return isComparisonOperator(expr) &&
+        expr.getLeftExpr().getType() == Type.FIELD &&
+        expr.getRightExpr().getType() == Type.FIELD;
+  }
+
+  public static boolean isLogicalOperator(EvalNode expr) {
+    return expr.getType() == Type.AND || expr.getType() == Type.OR;
+  }
+  
+  public static class ChangeColumnRefVisitor implements EvalNodeVisitor {    
+    private final String findColumn;
+    private final String toBeChanged;
+    
+    public ChangeColumnRefVisitor(String oldName, String newName) {
+      this.findColumn = oldName;
+      this.toBeChanged = newName;
+    }
+    
+    @Override
+    public void visit(EvalNode node) {
+      if (node.type == Type.FIELD) {
+        FieldEval field = (FieldEval) node;
+        if (field.getColumnName().equals(findColumn)
+            || field.getName().equals(findColumn)) {
+          field.replaceColumnRef(toBeChanged);
+        }
+      }
+    }    
+  }
+  
+  public static class AllColumnRefFinder implements EvalNodeVisitor {
+    private List<Column> colList = new ArrayList<Column>();
+    private FieldEval field = null;
+    
+    @Override
+    public void visit(EvalNode node) {
+      if (node.getType() == Type.FIELD) {
+        field = (FieldEval) node;
+        colList.add(field.getColumnRef());
+      } 
+    }
+    
+    public List<Column> getColumnRefs() {
+      return this.colList;
+    }
+  }
+  
+  public static class DistinctColumnRefFinder implements EvalNodeVisitor {
+    private Set<Column> colList = new HashSet<Column>(); 
+    private FieldEval field = null;
+    
+    @Override
+    public void visit(EvalNode node) {
+      if (node.getType() == Type.FIELD) {
+        field = (FieldEval) node;
+        colList.add(field.getColumnRef());
+      }
+    }
+    
+    public Set<Column> getColumnRefs() {
+      return this.colList;
+    }
+  }
+  
+  public static class VariableCounter implements EvalNodeVisitor {
+    private final Map<EvalNode.Type, Integer> counter;
+    
+    public VariableCounter() {
+      counter = Maps.newHashMap();
+      counter.put(Type.FUNCTION, 0);
+      counter.put(Type.FIELD, 0);      
+    }
+    
+    @Override
+    public void visit(EvalNode node) {
+      if (counter.containsKey(node.getType())) {
+        int val = counter.get(node.getType());
+        val++;
+        counter.put(node.getType(), val);
+      }
+    }
+    
+    public Map<EvalNode.Type, Integer> getCounter() {
+      return counter;
+    }
+  }
+
+  public static List<AggFuncCallEval> findDistinctAggFunction(EvalNode expr) {
+    AllAggFunctionFinder finder = new AllAggFunctionFinder();
+    expr.postOrder(finder);
+    return Lists.newArrayList(finder.getAggregationFunction());
+  }
+
+  public static class AllAggFunctionFinder implements EvalNodeVisitor {
+    private Set<AggFuncCallEval> aggFucntions = Sets.newHashSet();
+    private AggFuncCallEval field = null;
+
+    @Override
+    public void visit(EvalNode node) {
+      if (node.getType() == Type.AGG_FUNCTION) {
+        field = (AggFuncCallEval) node;
+        aggFucntions.add(field);
+      }
+    }
+
+    public Set<AggFuncCallEval> getAggregationFunction() {
+      return this.aggFucntions;
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
new file mode 100644
index 0000000..75a6eb7
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
@@ -0,0 +1,147 @@
+/**
+ * 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.gson.Gson;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.engine.json.GsonCreator;
+import org.apache.tajo.engine.utils.SchemaUtil;
+import org.apache.tajo.storage.Tuple;
+
+public class FieldEval extends EvalNode implements Cloneable {
+	@Expose private Column column;
+	@Expose	private int fieldId = -1;
+	
+	public FieldEval(String columnName, DataType domain) {
+		super(Type.FIELD);
+		this.column = new Column(columnName, domain);
+	}
+	
+	public FieldEval(Column column) {
+	  super(Type.FIELD);
+	  this.column = column;
+	}
+
+	@Override
+	public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
+	  if (fieldId == -1) {
+	    if(schema.contains(column.getQualifiedName())) {
+	     fieldId = schema.getColumnId(column.getQualifiedName());
+	    } else {
+	      if(schema.getColumnNum() != 0) {
+	        String schemaColQualName = schema.getColumn(0).getTableName() + 
+	            "." +  column.getColumnName();
+	        fieldId = schema.getColumnId(schemaColQualName);
+	      } else {
+	        fieldId = schema.getColumnId(column.getQualifiedName());
+	      }
+	    }
+	  }
+    FieldEvalContext fieldCtx = (FieldEvalContext) ctx;
+	  fieldCtx.datum = tuple.get(fieldId);
+	}
+
+  @Override
+  public Datum terminate(EvalContext ctx) {
+    return ((FieldEvalContext)ctx).datum;
+  }
+
+  @Override
+  public EvalContext newContext() {
+    return new FieldEvalContext();
+  }
+
+  private static class FieldEvalContext implements EvalContext {
+    private Datum datum;
+
+    public FieldEvalContext() {
+    }
+  }
+
+  @Override
+	public DataType[] getValueType() {
+		return SchemaUtil.newNoNameSchema(column.getDataType());
+	}
+	
+  public Column getColumnRef() {
+    return column;
+  }
+	
+	public String getTableId() {	  
+	  return column.getTableName();
+	}
+	
+	public String getColumnName() {
+	  return column.getColumnName();
+	}
+	
+	public void replaceColumnRef(String columnName) {
+	  this.column.setName(columnName);
+	}
+
+	@Override
+	public String getName() {
+		return this.column.getQualifiedName();
+	}
+	
+	public String toString() {
+	  return this.column.toString();
+	}
+	
+  public boolean equals(Object obj) {
+    if (obj instanceof FieldEval) {
+      FieldEval other = (FieldEval) obj;
+      
+      return column.equals(other.column);      
+    }
+    return false;
+  }
+  
+  @Override
+  public int hashCode() {
+    return column.hashCode();
+  }
+  
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    FieldEval eval = (FieldEval) super.clone();
+    eval.column = (Column) this.column.clone();
+    eval.fieldId = fieldId;
+    
+    return eval;
+  }
+  
+  public String toJSON() {
+    Gson gson = GsonCreator.getInstance();
+    return gson.toJson(this, EvalNode.class);
+  }
+
+  public void preOrder(EvalNodeVisitor visitor) {
+    visitor.visit(this);
+  }
+  
+  @Override
+  public void postOrder(EvalNodeVisitor visitor) {
+    visitor.visit(this);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FuncCallEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FuncCallEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FuncCallEval.java
new file mode 100644
index 0000000..9787805
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FuncCallEval.java
@@ -0,0 +1,98 @@
+/**
+ * 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.base.Objects;
+import com.google.gson.Gson;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.FunctionDesc;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.catalog.function.GeneralFunction;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.engine.json.GsonCreator;
+import org.apache.tajo.storage.Tuple;
+import org.apache.tajo.storage.VTuple;
+import org.apache.tajo.util.TUtil;
+
+public class FuncCallEval extends FuncEval {
+	@Expose protected GeneralFunction instance;
+  private Tuple tuple;
+  private Tuple params = null;
+  private Schema schema;
+
+	public FuncCallEval(FunctionDesc desc, GeneralFunction instance, EvalNode [] givenArgs) {
+		super(Type.FUNCTION, desc, givenArgs);
+		this.instance = instance;
+  }
+
+  /* (non-Javadoc)
+    * @see nta.query.executor.eval.Expr#evalVal(Tuple)
+    */
+	@Override
+	public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
+    this.schema = schema;
+    this.tuple = tuple;
+	}
+
+  @Override
+  public Datum terminate(EvalContext ctx) {
+    FuncCallCtx localCtx = (FuncCallCtx) ctx;
+    if (this.params == null) {
+      params = new VTuple(argEvals.length);
+    }
+
+    if(argEvals != null) {
+      params.clear();
+      for(int i=0;i < argEvals.length; i++) {
+        argEvals[i].eval(localCtx.argCtxs[i], schema, tuple);
+        params.put(i, argEvals[i].terminate(localCtx.argCtxs[i]));
+      }
+    }
+    return instance.eval(params);
+  }
+
+  @Override
+	public String toJSON() {
+	  Gson gson = GsonCreator.getInstance();
+    return gson.toJson(this, EvalNode.class);
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+	  if (obj instanceof FuncCallEval) {
+      FuncCallEval other = (FuncCallEval) obj;
+      return super.equals(other) &&
+          TUtil.checkEquals(instance, other.instance);
+	  }
+	  
+	  return false;
+	}
+	
+	@Override
+	public int hashCode() {
+	  return Objects.hashCode(funcDesc, instance);
+	}
+	
+	@Override
+  public Object clone() throws CloneNotSupportedException {
+    FuncCallEval eval = (FuncCallEval) super.clone();
+    eval.instance = (GeneralFunction) instance.clone();
+    return eval;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FuncEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FuncEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FuncEval.java
new file mode 100644
index 0000000..350b761
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FuncEval.java
@@ -0,0 +1,142 @@
+/**
+ * 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.base.Objects;
+import com.google.gson.Gson;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.FunctionDesc;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.engine.json.GsonCreator;
+import org.apache.tajo.storage.Tuple;
+import org.apache.tajo.util.TUtil;
+
+public abstract class FuncEval extends EvalNode implements Cloneable {
+	@Expose protected FunctionDesc funcDesc;
+	@Expose protected EvalNode [] argEvals;
+
+	public FuncEval(Type type, FunctionDesc funcDesc, EvalNode[] argEvals) {
+		super(type);
+		this.funcDesc = funcDesc;
+		this.argEvals = argEvals;
+	}
+
+  @Override
+  public EvalContext newContext() {
+    FuncCallCtx newCtx = new FuncCallCtx(argEvals);
+    return newCtx;
+  }
+	
+	public EvalNode [] getArgs() {
+	  return this.argEvals;
+	}
+
+  public void setArgs(EvalNode [] args) {
+    this.argEvals = args;
+  }
+	
+	public DataType [] getValueType() {
+		return this.funcDesc.getReturnType();
+	}
+
+	@Override
+	public abstract void eval(EvalContext ctx, Schema schema, Tuple tuple);
+
+  public abstract Datum terminate(EvalContext ctx);
+
+	@Override
+	public String getName() {
+		return funcDesc.getSignature();
+	}
+
+  @Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		for(int i=0; i < argEvals.length; i++) {
+			sb.append(argEvals[i]);
+			if(i+1 < argEvals.length)
+				sb.append(",");
+		}
+		return funcDesc.getSignature()+"("+sb+")";
+	}
+
+  @Override
+	public String toJSON() {
+	  Gson gson = GsonCreator.getInstance();
+    return gson.toJson(this, EvalNode.class);
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+	  if (obj instanceof FuncEval) {
+      FuncEval other = (FuncEval) obj;
+
+      boolean b1 = this.type == other.type;
+      boolean b2 = TUtil.checkEquals(funcDesc, other.funcDesc);
+      boolean b3 = TUtil.checkEquals(argEvals, other.argEvals);
+      return b1 && b2 && b3;
+	  }
+	  
+	  return false;
+	}
+	
+	@Override
+	public int hashCode() {
+	  return Objects.hashCode(funcDesc, argEvals);
+	}
+	
+	@Override
+  public Object clone() throws CloneNotSupportedException {
+    FuncEval eval = (FuncEval) super.clone();
+    eval.funcDesc = (FunctionDesc) funcDesc.clone();
+    eval.argEvals = new EvalNode[argEvals.length];
+    for (int i = 0; i < argEvals.length; i++) {
+      eval.argEvals[i] = (EvalNode) argEvals[i].clone();
+    }    
+    return eval;
+  }
+	
+	@Override
+  public void preOrder(EvalNodeVisitor visitor) {
+    for (EvalNode eval : argEvals) {
+      eval.postOrder(visitor);
+    }
+    visitor.visit(this);
+  }
+	
+	@Override
+	public void postOrder(EvalNodeVisitor visitor) {
+	  for (EvalNode eval : argEvals) {
+	    eval.postOrder(visitor);
+	  }
+	  visitor.visit(this);
+	}
+
+  protected class FuncCallCtx implements EvalContext {
+    EvalContext [] argCtxs;
+    FuncCallCtx(EvalNode [] argEvals) {
+      argCtxs = new EvalContext[argEvals.length];
+      for (int i = 0; i < argEvals.length; i++) {
+        argCtxs[i] = argEvals[i].newContext();
+      }
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InvalidCastException.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InvalidCastException.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InvalidCastException.java
new file mode 100644
index 0000000..b907f06
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InvalidCastException.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.engine.eval;
+
+public class InvalidCastException extends RuntimeException {
+	private static final long serialVersionUID = -5090530469575858320L;
+
+	public InvalidCastException() {
+	}
+
+	/**
+	 * @param message
+	 */
+	public InvalidCastException(String message) {
+		super(message);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/bc6359b8/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InvalidEvalException.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InvalidEvalException.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InvalidEvalException.java
new file mode 100644
index 0000000..96eda91
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InvalidEvalException.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.engine.eval;
+
+public class InvalidEvalException extends RuntimeException {
+	private static final long serialVersionUID = -2897003028483298256L;
+
+	public InvalidEvalException() {
+	}
+
+	/**
+	 * @param message
+	 */
+	public InvalidEvalException(String message) {
+		super(message);
+	}
+}


Mime
View raw message