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 2014/10/25 20:17:56 UTC

[07/28] TAJO-1125: Separate logical plan and optimizer into a maven module.

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/EvalType.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/EvalType.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/EvalType.java
new file mode 100644
index 0000000..c1df658
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/EvalType.java
@@ -0,0 +1,172 @@
+/**
+ * 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.plan.expr;
+
+public enum EvalType {
+  // Unary expression
+  NOT(NotEval.class, "!"),
+
+  // Binary expression
+  AND(BinaryEval.class),
+  OR(BinaryEval.class),
+  EQUAL(BinaryEval.class, "="),
+  IS_NULL(IsNullEval.class),
+  NOT_EQUAL(BinaryEval.class, "<>"),
+  LTH(BinaryEval.class, "<"),
+  LEQ(BinaryEval.class, "<="),
+  GTH(BinaryEval.class, ">"),
+  GEQ(BinaryEval.class, ">="),
+  PLUS(BinaryEval.class, "+"),
+  MINUS(BinaryEval.class, "-"),
+  MODULAR(BinaryEval.class, "%"),
+  MULTIPLY(BinaryEval.class, "*"),
+  DIVIDE(BinaryEval.class, "/"),
+
+  // Binary Bitwise expressions
+  BIT_AND(BinaryEval.class, "&"),
+  BIT_OR(BinaryEval.class, "|"),
+  BIT_XOR(BinaryEval.class, "|"),
+
+  // Function
+  WINDOW_FUNCTION(WindowFunctionEval.class),
+  AGG_FUNCTION(AggregationFunctionCallEval.class),
+  FUNCTION(GeneralFunctionEval.class),
+
+  // String operator or pattern matching predicates
+  LIKE(LikePredicateEval.class),
+  SIMILAR_TO(SimilarToPredicateEval.class),
+  REGEX(RegexPredicateEval.class),
+  CONCATENATE(BinaryEval.class, "||"),
+
+  // Other predicates
+  BETWEEN(BetweenPredicateEval.class),
+  CASE(CaseWhenEval.class),
+  IF_THEN(CaseWhenEval.IfThenEval.class),
+  IN(InEval.class),
+
+  // Value or Reference
+  SIGNED(SignedEval.class),
+  CAST(CastEval.class),
+  ROW_CONSTANT(RowConstantEval.class),
+  FIELD(FieldEval.class),
+  CONST(ConstEval.class);
+
+  private Class<? extends EvalNode> baseClass;
+  private String operatorName;
+
+  EvalType(Class<? extends EvalNode> type) {
+    this.baseClass = type;
+  }
+
+  EvalType(Class<? extends EvalNode> type, String text) {
+    this(type);
+    this.operatorName = text;
+  }
+
+  public static boolean isUnaryOperator(EvalType type) {
+    boolean match = false;
+
+    match |= type == CAST;
+    match |= type == IS_NULL;
+    match |= type == NOT;
+    match |= type == SIGNED;
+
+    return match;
+  }
+
+  public static boolean isBinaryOperator(EvalType type) {
+    boolean match = false;
+
+    match |= isArithmeticOperator(type);
+    match |= isLogicalOperator(type) && type != NOT;
+    match |= isComparisonOperator(type) && type != BETWEEN;
+
+    match |= type == CONCATENATE;
+    match |= type == IN;
+    match |= type == LIKE;
+    match |= type == REGEX;
+    match |= type == SIMILAR_TO;
+
+    return match;
+  }
+
+  public static boolean isLogicalOperator(EvalType type) {
+    boolean match = false;
+
+    match |= type == AND;
+    match |= type == OR;
+    match |= type == NOT;
+
+    return match;
+  }
+
+  public static boolean isComparisonOperator(EvalType type) {
+    boolean match = false;
+
+    match |= type == EQUAL;
+    match |= type == NOT_EQUAL;
+    match |= type == LTH;
+    match |= type == LEQ;
+    match |= type == GTH;
+    match |= type == GEQ;
+    match |= type == BETWEEN;
+
+    return match;
+  }
+
+  public static boolean isArithmeticOperator(EvalType type) {
+    boolean match = false;
+
+    match |= type == PLUS;
+    match |= type == MINUS;
+    match |= type == MULTIPLY;
+    match |= type == DIVIDE;
+    match |= type == MODULAR;
+
+    return match;
+  }
+
+  public static boolean isFunction(EvalType type) {
+    boolean match = false;
+
+    match |= type == FUNCTION;
+    match |= type == AGG_FUNCTION;
+    match |= type == WINDOW_FUNCTION;
+
+    return match;
+  }
+
+  public static boolean isStringPatternMatchOperator(EvalType type) {
+    boolean match = false;
+
+    match |= type == LIKE;
+    match |= type == SIMILAR_TO;
+    match |= type == REGEX;
+
+    return match;
+  }
+
+  public String getOperatorName() {
+    return operatorName != null ? operatorName : name();
+  }
+
+  public Class<? extends EvalNode> getBaseClass() {
+    return this.baseClass;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/FieldEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/FieldEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/FieldEval.java
new file mode 100644
index 0000000..c42768d
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/FieldEval.java
@@ -0,0 +1,129 @@
+/**
+ * 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.plan.expr;
+
+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.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(EvalType.FIELD);
+		this.column = new Column(columnName, domain);
+	}
+	
+	public FieldEval(Column column) {
+	  super(EvalType.FIELD);
+	  this.column = column;
+	}
+
+	@Override
+	public Datum eval(Schema schema, Tuple tuple) {
+	  if (fieldId == -1) {
+      // TODO - column namespace should be improved to simplify name handling and resolving.
+      if (column.hasQualifier()) {
+        fieldId = schema.getColumnId(column.getQualifiedName());
+      } else {
+        fieldId = schema.getColumnIdByName(column.getSimpleName());
+      }
+      if (fieldId == -1) {
+        throw new IllegalStateException("No Such Column Reference: " + column + ", schema: " + schema);
+      }
+	  }
+	  return tuple.get(fieldId);
+  }
+
+  @Override
+	public DataType getValueType() {
+		return column.getDataType();
+	}
+
+  @Override
+  public int childNum() {
+    return 0;
+  }
+
+  @Override
+  public EvalNode getChild(int idx) {
+    return null;
+  }
+
+  public Column getColumnRef() {
+    return column;
+  }
+	
+	public String getQualifier() {
+	  return column.getQualifier();
+	}
+	
+	public String getColumnName() {
+	  return column.getSimpleName();
+	}
+	
+	public void replaceColumnRef(String columnName) {
+	  this.column = new Column(columnName, this.column.getDataType());
+	}
+
+	@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 = this.column;
+    eval.fieldId = fieldId;
+    
+    return eval;
+  }
+
+  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/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/FunctionEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/FunctionEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/FunctionEval.java
new file mode 100644
index 0000000..ec8d7da
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/FunctionEval.java
@@ -0,0 +1,175 @@
+/**
+ * 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.plan.expr;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.FunctionDesc;
+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.storage.Tuple;
+import org.apache.tajo.util.TUtil;
+
+import static org.apache.tajo.catalog.proto.CatalogProtos.FunctionType.DISTINCT_AGGREGATION;
+import static org.apache.tajo.catalog.proto.CatalogProtos.FunctionType.DISTINCT_UDA;
+
+public abstract class FunctionEval extends EvalNode implements Cloneable {
+  public static enum ParamType {
+    CONSTANT, VARIABLE, NULL
+  }
+
+  @Expose protected FunctionDesc funcDesc;
+	@Expose protected EvalNode [] argEvals;
+
+	public FunctionEval(EvalType type, FunctionDesc funcDesc, EvalNode[] argEvals) {
+		super(type);
+		this.funcDesc = funcDesc;
+    Preconditions.checkArgument(argEvals != null, "argEvals cannot be null");
+    this.argEvals = argEvals;
+	}
+
+  public FunctionDesc getFuncDesc() {
+    return funcDesc;
+  }
+
+  public ParamType [] getParamType() {
+    ParamType [] paramTypes = new ParamType[argEvals.length];
+    for (int i = 0; i < argEvals.length; i++) {
+      if (argEvals[i].getType() == EvalType.CONST) {
+        if (argEvals[i].getValueType().getType() == TajoDataTypes.Type.NULL_TYPE) {
+          paramTypes[i] = ParamType.NULL;
+        } else {
+          paramTypes[i] = ParamType.CONSTANT;
+        }
+      } else {
+        paramTypes[i] = ParamType.VARIABLE;
+      }
+    }
+    return paramTypes;
+  }
+
+  public boolean isDistinct() {
+    return funcDesc.getFuncType() == DISTINCT_AGGREGATION || funcDesc.getFuncType() == DISTINCT_UDA;
+  }
+
+	public EvalNode [] getArgs() {
+	  return this.argEvals;
+	}
+
+  public void setArg(int idx, EvalNode arg) {
+    this.argEvals[idx] = arg;
+  }
+
+  public void setArgs(EvalNode [] args) {
+    this.argEvals = args;
+  }
+
+  @Override
+  public int childNum() {
+    if (argEvals != null) {
+      return argEvals.length;
+    } else {
+      return 0;
+    }
+  }
+
+  @Override
+  public EvalNode getChild(int idx) {
+    return argEvals[idx];
+  }
+
+
+	public DataType getValueType() {
+		return this.funcDesc.getReturnType();
+	}
+
+	@Override
+	public abstract Datum eval(Schema schema, Tuple tuple);
+
+	@Override
+	public String getName() {
+		return funcDesc.getFunctionName();
+	}
+
+  @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.getFunctionName() + "(" + (isDistinct() ? " distinct " : "") + sb+")";
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+	  if (obj instanceof FunctionEval) {
+      FunctionEval other = (FunctionEval) 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 {
+    FunctionEval eval = (FunctionEval) super.clone();
+    eval.funcDesc = (FunctionDesc) funcDesc.clone();
+    if (argEvals != null) {
+      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) {
+    if (argEvals != null) {
+      for (EvalNode eval : argEvals) {
+        eval.postOrder(visitor);
+      }
+    }
+    visitor.visit(this);
+  }
+	
+	@Override
+	public void postOrder(EvalNodeVisitor visitor) {
+    if (argEvals != null) {
+      for (EvalNode eval : argEvals) {
+        eval.postOrder(visitor);
+      }
+    }
+	  visitor.visit(this);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/GeneralFunctionEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/GeneralFunctionEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/GeneralFunctionEval.java
new file mode 100644
index 0000000..e28e5f3
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/GeneralFunctionEval.java
@@ -0,0 +1,81 @@
+/**
+ * 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.plan.expr;
+
+import com.google.common.base.Objects;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.FunctionDesc;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.plan.function.GeneralFunction;
+import org.apache.tajo.storage.Tuple;
+import org.apache.tajo.storage.VTuple;
+import org.apache.tajo.util.TUtil;
+
+public class GeneralFunctionEval extends FunctionEval {
+  @Expose protected GeneralFunction instance;
+  private Tuple params = null;
+
+	public GeneralFunctionEval(FunctionDesc desc, GeneralFunction instance, EvalNode[] givenArgs) {
+		super(EvalType.FUNCTION, desc, givenArgs);
+		this.instance = instance;
+    this.instance.init(getParamType());
+  }
+
+  /* (non-Javadoc)
+    * @see nta.query.executor.eval.Expr#evalVal(Tuple)
+    */
+	@Override
+	public Datum eval(Schema schema, Tuple tuple) {
+    if (this.params == null) {
+      params = new VTuple(argEvals.length);
+    }
+    if(argEvals != null) {
+      params.clear();
+      for(int i=0;i < argEvals.length; i++) {
+        params.put(i, argEvals[i].eval(schema, tuple));
+      }
+    }
+
+    return instance.eval(params);
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+	  if (obj instanceof GeneralFunctionEval) {
+      GeneralFunctionEval other = (GeneralFunctionEval) 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 {
+    GeneralFunctionEval eval = (GeneralFunctionEval) super.clone();
+    eval.instance = (GeneralFunction) instance.clone();
+    return eval;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/InEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/InEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/InEval.java
new file mode 100644
index 0000000..4dcc7bf
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/InEval.java
@@ -0,0 +1,86 @@
+/**
+ * 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.plan.expr;
+
+
+import com.google.common.collect.Sets;
+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.datum.Datum;
+import org.apache.tajo.datum.DatumFactory;
+import org.apache.tajo.datum.NullDatum;
+import org.apache.tajo.storage.Tuple;
+
+import java.util.Set;
+
+public class InEval extends BinaryEval {
+  private static final TajoDataTypes.DataType RES_TYPE = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.BOOLEAN);
+
+  @Expose private boolean not;
+  Set<Datum> values;
+
+  public InEval(EvalNode lhs, RowConstantEval valueList, boolean not) {
+    super(EvalType.IN, lhs, valueList);
+    this.not = not;
+  }
+
+  public boolean isNot() {
+    return this.not;
+  }
+
+  @Override
+  public TajoDataTypes.DataType getValueType() {
+    return RES_TYPE;
+  }
+
+  @Override
+  public String getName() {
+    return "?";
+  }
+
+  @Override
+  public Datum eval(Schema schema, Tuple tuple) {
+    if (values == null) {
+      values = Sets.newHashSet(((RowConstantEval)rightExpr).getValues());
+    }
+
+    Datum leftValue = leftExpr.eval(schema, tuple);
+
+    if (leftValue.isNull()) {
+      return NullDatum.get();
+    }
+
+    return DatumFactory.createBool(not ^ values.contains(leftValue));
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof InEval) {
+      InEval other = (InEval) obj;
+      return super.equals(obj) && not == other.not;
+    }
+    return false;
+  }
+
+  public String toString() {
+    return leftExpr + " IN (" + rightExpr + ")";
+  }
+}

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

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/IsNullEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/IsNullEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/IsNullEval.java
new file mode 100644
index 0000000..6a17bf8
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/IsNullEval.java
@@ -0,0 +1,84 @@
+/**
+ * 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.plan.expr;
+
+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;
+
+public class IsNullEval extends UnaryEval {
+  // it's just a hack to emulate a binary expression
+  private final static ConstEval DUMMY_EVAL = new ConstEval(DatumFactory.createBool(true));
+  private static final DataType RES_TYPE = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.BOOLEAN);
+
+  // persistent variables
+  @Expose private boolean isNot;
+
+  public IsNullEval(boolean not, EvalNode predicand) {
+    super(EvalType.IS_NULL, predicand);
+    this.isNot = not;
+  }
+
+  @Override
+  public DataType getValueType() {
+    return RES_TYPE;
+  }
+
+  @Override
+  public String getName() {
+    return "?";
+  }
+
+  @Override
+  public String toString() {
+    return child + " IS " + (isNot ? "NOT NULL" : "NULL");
+  }
+
+  @Override
+  public Datum eval(Schema schema, Tuple tuple) {
+    boolean isNull = child.eval(schema, tuple).isNull();
+    return DatumFactory.createBool(isNot ^ isNull);
+  }
+
+  public boolean isNot() {
+    return isNot;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof IsNullEval) {
+      IsNullEval other = (IsNullEval) obj;
+      return super.equals(other) && isNot == other.isNot();
+    } else {
+      return false;
+    }
+  }
+
+  public Object clone() throws CloneNotSupportedException {
+    IsNullEval isNullEval = (IsNullEval) super.clone();
+    isNullEval.isNot = isNot;
+
+    return isNullEval;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/LikePredicateEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/LikePredicateEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/LikePredicateEval.java
new file mode 100644
index 0000000..73f4f3a
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/LikePredicateEval.java
@@ -0,0 +1,54 @@
+/**
+ * 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.plan.expr;
+
+import org.apache.tajo.util.StringUtils;
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+public class LikePredicateEval extends PatternMatchPredicateEval {
+
+  public LikePredicateEval(boolean not, EvalNode field, ConstEval pattern) {
+    super(EvalType.LIKE, not, field, pattern, false);
+  }
+
+  public LikePredicateEval(boolean not, EvalNode field, ConstEval pattern, boolean caseSensitive) {
+    super(EvalType.LIKE, not, field, pattern, caseSensitive);
+  }
+
+  protected void compile(String pattern) throws PatternSyntaxException {
+    String escaped = StringUtils.escapeRegexp(pattern);
+    String regex = escaped.replace("_", ".").replace("%", ".*");
+    int flags = Pattern.DOTALL;
+    if (caseInsensitive) {
+      flags |= Pattern.CASE_INSENSITIVE;
+    }
+    this.compiled = Pattern.compile(regex, flags);
+  }
+
+  public boolean isLeadingWildCard() {
+    return pattern.indexOf(".*") == 0;
+  }
+
+  @Override
+  public String toString() {
+    return leftExpr.toString() + (caseInsensitive ? "ILIKE" : "LIKE") + "'" + pattern +"'";
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/NotEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/NotEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/NotEval.java
new file mode 100644
index 0000000..916c1f7
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/NotEval.java
@@ -0,0 +1,56 @@
+/**
+ * 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.plan.expr;
+
+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;
+
+public class NotEval extends UnaryEval implements Cloneable {
+  private static final DataType RES_TYPE = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.BOOLEAN);
+
+  public NotEval(EvalNode child) {
+    super(EvalType.NOT, child);
+  }
+
+  @Override
+  public DataType getValueType() {
+    return RES_TYPE;
+  }
+
+  @Override
+  public String getName() {
+    return "?";
+  }
+
+  @Override
+  public Datum eval(Schema schema, Tuple tuple) {
+    Datum datum = child.eval(schema, tuple);
+    return !datum.isNull() ? DatumFactory.createBool(!datum.asBool()) : datum;
+  }
+
+  @Override
+  public String toString() {
+    return "NOT " + child.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/PartialBinaryExpr.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/PartialBinaryExpr.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/PartialBinaryExpr.java
new file mode 100644
index 0000000..3aded7b
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/PartialBinaryExpr.java
@@ -0,0 +1,73 @@
+/**
+ * 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.plan.expr;
+
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.exception.InvalidOperationException;
+import org.apache.tajo.storage.Tuple;
+
+public class PartialBinaryExpr extends BinaryEval {
+  
+  public PartialBinaryExpr(EvalType type) {
+    super(type);
+  }
+
+  public PartialBinaryExpr(EvalType type, EvalNode left, EvalNode right) {
+    super(type);
+    this.leftExpr = left;
+    this.rightExpr = right;
+    // skip to determine the result type
+  }
+
+  @Override
+  public DataType getValueType() {
+    return null;
+  }
+
+  @Override
+  public String getName() {
+    return "nonamed";
+  }
+
+  @Override
+  public Datum eval(Schema schema, Tuple tuple) {
+    throw new InvalidOperationException("ERROR: the partial binary expression cannot be evluated: "
+            + this.toString());
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof PartialBinaryExpr) {
+      PartialBinaryExpr other = (PartialBinaryExpr) obj;
+      return type.equals(other.type) &&
+          leftExpr.equals(other.leftExpr) &&
+          rightExpr.equals(other.rightExpr);
+    }
+    return false;
+  }
+
+  public String toString() {
+    return 
+        (leftExpr != null ? leftExpr.toString() : "[EMPTY]") 
+        + " " + type + " " 
+        + (rightExpr != null ? rightExpr.toString() : "[EMPTY]");
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/PatternMatchPredicateEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/PatternMatchPredicateEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/PatternMatchPredicateEval.java
new file mode 100644
index 0000000..1d83d60
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/PatternMatchPredicateEval.java
@@ -0,0 +1,90 @@
+/**
+ * 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.plan.expr;
+
+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.datum.NullDatum;
+import org.apache.tajo.storage.Tuple;
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+public abstract class PatternMatchPredicateEval extends BinaryEval {
+  private static final DataType RES_TYPE = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.BOOLEAN);
+
+  @Expose protected boolean not;
+  @Expose protected String pattern;
+  @Expose protected boolean caseInsensitive;
+
+  // transient variables
+  protected Pattern compiled;
+
+  public PatternMatchPredicateEval(EvalType evalType, boolean not, EvalNode predicand, ConstEval pattern,
+                                   boolean caseInsensitive) {
+    super(evalType, predicand, pattern);
+    this.not = not;
+    this.pattern = pattern.getValue().asChars();
+    this.caseInsensitive = caseInsensitive;
+  }
+
+  public PatternMatchPredicateEval(EvalType evalType, boolean not, EvalNode field, ConstEval pattern) {
+    this(evalType, not, field, pattern, false);
+  }
+
+  abstract void compile(String pattern) throws PatternSyntaxException;
+
+  public boolean isNot() {
+    return not;
+  }
+
+  public boolean isCaseInsensitive() {
+    return caseInsensitive;
+  }
+
+  @Override
+  public DataType getValueType() {
+    return RES_TYPE;
+  }
+
+  @Override
+  public String getName() {
+    return "?";
+  }
+
+  @Override
+  public Datum eval(Schema schema, Tuple tuple) {
+    if (this.compiled == null) {
+      compile(this.pattern);
+    }
+
+    Datum predicand = leftExpr.eval(schema, tuple);
+    if (predicand.isNull()) {
+      return NullDatum.get();
+    }
+
+    boolean matched = compiled.matcher(predicand.asChars()).matches();
+    return DatumFactory.createBool(matched ^ not);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/RegexPredicateEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/RegexPredicateEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/RegexPredicateEval.java
new file mode 100644
index 0000000..7519e2d
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/RegexPredicateEval.java
@@ -0,0 +1,53 @@
+/**
+ * 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.plan.expr;
+
+import com.google.gson.annotations.Expose;
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+public class RegexPredicateEval extends PatternMatchPredicateEval {
+  @Expose private String operator;
+  public RegexPredicateEval(boolean not, EvalNode field, ConstEval pattern, boolean caseInsensitive) {
+    super(EvalType.REGEX, not, field, pattern, caseInsensitive);
+    StringBuilder sb = new StringBuilder();
+    if (not) {
+      sb.append("!");
+    }
+    sb.append("~");
+    if (caseInsensitive) {
+      sb.append("*");
+    }
+    this.operator = sb.toString();
+  }
+  
+  protected void compile(String regex) throws PatternSyntaxException {
+    int flags = Pattern.DOTALL;
+    if (caseInsensitive) {
+      flags |= Pattern.CASE_INSENSITIVE;
+    }
+    this.compiled = Pattern.compile(regex, flags);
+  }
+
+  @Override
+  public String toString() {
+    return leftExpr.toString() + operator + "'" + pattern +"'";
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/RowConstantEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/RowConstantEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/RowConstantEval.java
new file mode 100644
index 0000000..4a97e67
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/RowConstantEval.java
@@ -0,0 +1,99 @@
+/**
+ * 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.plan.expr;
+
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.CatalogUtil;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.datum.NullDatum;
+import org.apache.tajo.storage.Tuple;
+import org.apache.tajo.util.TUtil;
+
+import static org.apache.tajo.common.TajoDataTypes.DataType;
+
+public class RowConstantEval extends EvalNode {
+  @Expose Datum [] values;
+
+  public RowConstantEval(Datum [] values) {
+    super(EvalType.ROW_CONSTANT);
+    this.values = values;
+  }
+
+  @Override
+  public DataType getValueType() {
+    return CatalogUtil.newSimpleDataType(values[0].type());
+  }
+
+  @Override
+  public int childNum() {
+    return 0;
+  }
+
+  @Override
+  public EvalNode getChild(int idx) {
+    return null;
+  }
+
+  @Override
+  public String getName() {
+    return "ROW";
+  }
+
+  @Override
+  public Datum eval(Schema schema, Tuple tuple) {
+    return NullDatum.get();
+  }
+
+  public Datum [] getValues() {
+    return values;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof RowConstantEval) {
+      RowConstantEval other = (RowConstantEval) obj;
+      return TUtil.checkEquals(values, other.values);
+    }
+
+    return false;
+  }
+
+  public String toString() {
+    return TUtil.arrayToString(values);
+  }
+
+  public void preOrder(EvalNodeVisitor visitor) {
+    visitor.visit(this);
+  }
+
+  public void postOrder(EvalNodeVisitor visitor) {
+    visitor.visit(this);
+  }
+
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    RowConstantEval rowConstantEval = (RowConstantEval) super.clone();
+    if (values != null) {
+      rowConstantEval.values = new Datum[values.length];
+      System.arraycopy(values, 0, rowConstantEval.values, 0, values.length);
+    }
+    return rowConstantEval;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SignedEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SignedEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SignedEval.java
new file mode 100644
index 0000000..36f7e2f
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SignedEval.java
@@ -0,0 +1,86 @@
+/**
+ * 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.plan.expr;
+
+import com.google.common.base.Objects;
+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.datum.NumericDatum;
+import org.apache.tajo.storage.Tuple;
+
+public class SignedEval extends UnaryEval implements Cloneable {
+  @Expose private boolean negative;
+
+  public SignedEval(boolean negative, EvalNode childEval) {
+    super(EvalType.SIGNED, childEval);
+    this.negative = negative;
+  }
+
+  public boolean isNegative() {
+    return negative;
+  }
+
+  @Override
+  public DataType getValueType() {
+    return child.getValueType();
+  }
+
+  @Override
+  public String getName() {
+    return "?";
+  }
+
+  @Override
+  public Datum eval(Schema schema, Tuple tuple) {
+    NumericDatum result = child.eval(schema, tuple);
+    if (negative) {
+      return result.inverseSign();
+    }
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return (negative ? "-" : "+") + child.toString();
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof SignedEval) {
+      SignedEval other = (SignedEval) obj;
+      return super.equals(other) && negative == other.negative;
+    } else {
+      return false;
+    }
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(type, negative, child);
+  }
+
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    SignedEval signedEval = (SignedEval) super.clone();
+    signedEval.negative = negative;
+    return signedEval;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SimilarToPredicateEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SimilarToPredicateEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SimilarToPredicateEval.java
new file mode 100644
index 0000000..ed5e123
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SimilarToPredicateEval.java
@@ -0,0 +1,48 @@
+/**
+ * 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.plan.expr;
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+public class SimilarToPredicateEval extends PatternMatchPredicateEval {
+  private static final String SIMILARTO_ESCAPE_SPATIAL_CHARACTERS = "([.])";
+
+  public SimilarToPredicateEval(boolean not, EvalNode field, ConstEval pattern,
+                                @SuppressWarnings("unused") boolean isCaseSensitive) {
+    super(EvalType.SIMILAR_TO, not, field, pattern, false);
+  }
+
+  public SimilarToPredicateEval(boolean not, EvalNode field, ConstEval pattern) {
+    super(EvalType.SIMILAR_TO, not, field, pattern);
+  }
+
+  @Override
+  protected void compile(String pattern) throws PatternSyntaxException {
+    String regex = pattern.replaceAll(SIMILARTO_ESCAPE_SPATIAL_CHARACTERS, "\\\\$1");
+    regex = regex.replace("_", ".").replace("%", ".*"); // transform some special characters to be 'like'.
+
+    this.compiled = Pattern.compile(regex, Pattern.DOTALL);
+  }
+  
+  @Override
+  public String toString() {
+    return leftExpr.toString() + " SIMILAR TO '" + pattern + "'";
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SimpleEvalNodeVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SimpleEvalNodeVisitor.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SimpleEvalNodeVisitor.java
new file mode 100644
index 0000000..e706391
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/SimpleEvalNodeVisitor.java
@@ -0,0 +1,172 @@
+/**
+ * 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.plan.expr;
+
+import com.google.common.base.Preconditions;
+import org.apache.tajo.exception.UnsupportedException;
+
+import java.util.Stack;
+
+/**
+ * It provides simple visitor methods for an expression tree. Since <code>SimpleEvalNodeVisitor</code> provides
+ * fewer visitor methods, it allows users to write a simple rewriter for expression trees.
+ */
+public abstract class SimpleEvalNodeVisitor<CONTEXT> {
+
+  public EvalNode visit(CONTEXT context, EvalNode evalNode, Stack<EvalNode> stack) {
+    Preconditions.checkNotNull(evalNode);
+
+    EvalNode result;
+
+    if (evalNode instanceof UnaryEval) {
+      result = visitUnaryEval(context, stack, (UnaryEval) evalNode);
+    } else if (evalNode instanceof BinaryEval) {
+      result = visitBinaryEval(context, stack, (BinaryEval) evalNode);
+    } else {
+
+      switch (evalNode.getType()) {
+      // Column and Value reference expressions
+      case CONST:
+        result = visitConst(context, (ConstEval) evalNode, stack);
+        break;
+      case ROW_CONSTANT:
+        result = visitRowConstant(context, (RowConstantEval) evalNode, stack);
+        break;
+      case FIELD:
+        result = visitField(context, stack, (FieldEval) evalNode);
+        break;
+
+
+      // SQL standard predicates
+      case BETWEEN:
+        result = visitBetween(context, (BetweenPredicateEval) evalNode, stack);
+        break;
+      case CASE:
+        result = visitCaseWhen(context, (CaseWhenEval) evalNode, stack);
+        break;
+      case IF_THEN:
+        result = visitIfThen(context, (CaseWhenEval.IfThenEval) evalNode, stack);
+        break;
+
+      // Functions
+      case FUNCTION:
+        result = visitFuncCall(context, (FunctionEval) evalNode, stack);
+        break;
+      case AGG_FUNCTION:
+        result = visitFuncCall(context, (FunctionEval) evalNode, stack);
+        break;
+      case WINDOW_FUNCTION:
+        result = visitFuncCall(context, (FunctionEval) evalNode, stack);
+        break;
+
+      default:
+        throw new UnsupportedException("Unknown EvalType: " + evalNode);
+      }
+    }
+
+    return result;
+  }
+
+  protected EvalNode visitUnaryEval(CONTEXT context, Stack<EvalNode> stack, UnaryEval unaryEval) {
+    stack.push(unaryEval);
+    visit(context, unaryEval.getChild(), stack);
+    stack.pop();
+    return unaryEval;
+  }
+
+  protected EvalNode visitBinaryEval(CONTEXT context, Stack<EvalNode> stack, BinaryEval binaryEval) {
+    stack.push(binaryEval);
+    visit(context, binaryEval.getLeftExpr(), stack);
+    visit(context, binaryEval.getRightExpr(), stack);
+    stack.pop();
+    return binaryEval;
+  }
+
+  protected EvalNode visitDefaultFunctionEval(CONTEXT context, Stack<EvalNode> stack, FunctionEval functionEval) {
+    stack.push(functionEval);
+    if (functionEval.getArgs() != null) {
+      for (EvalNode arg : functionEval.getArgs()) {
+        visit(context, arg, stack);
+      }
+    }
+    stack.pop();
+    return functionEval;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////
+  // Value and Literal
+  ///////////////////////////////////////////////////////////////////////////////////////////////
+
+  protected EvalNode visitConst(CONTEXT context, ConstEval evalNode, Stack<EvalNode> stack) {
+    return evalNode;
+  }
+
+  protected EvalNode visitRowConstant(CONTEXT context, RowConstantEval evalNode, Stack<EvalNode> stack) {
+    return evalNode;
+  }
+
+  protected EvalNode visitField(CONTEXT context, Stack<EvalNode> stack, FieldEval evalNode) {
+    return evalNode;
+  }
+
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////
+  // SQL standard predicates
+  ///////////////////////////////////////////////////////////////////////////////////////////////
+
+  protected EvalNode visitBetween(CONTEXT context, BetweenPredicateEval evalNode, Stack<EvalNode> stack) {
+    stack.push(evalNode);
+    visit(context, evalNode.getPredicand(), stack);
+    visit(context, evalNode.getBegin(), stack);
+    visit(context, evalNode.getEnd(), stack);
+    return evalNode;
+  }
+
+  protected EvalNode visitCaseWhen(CONTEXT context, CaseWhenEval evalNode, Stack<EvalNode> stack) {
+    stack.push(evalNode);
+    for (CaseWhenEval.IfThenEval ifThenEval : evalNode.getIfThenEvals()) {
+      visitIfThen(context, ifThenEval, stack);
+    }
+    if (evalNode.hasElse()) {
+      visit(context, evalNode.getElse(), stack);
+    }
+    stack.pop();
+    return evalNode;
+  }
+
+  protected EvalNode visitIfThen(CONTEXT context, CaseWhenEval.IfThenEval evalNode, Stack<EvalNode> stack) {
+    stack.push(evalNode);
+    visit(context, evalNode.getCondition(), stack);
+    visit(context, evalNode.getResult(), stack);
+    stack.pop();
+    return evalNode;
+  }
+
+  protected EvalNode visitInPredicate(CONTEXT context, InEval evalNode, Stack<EvalNode> stack) {
+    return visitBinaryEval(context, stack, evalNode);
+  }
+
+  ///////////////////////////////////////////////////////////////////////////////////////////////
+  // Functions
+  ///////////////////////////////////////////////////////////////////////////////////////////////
+
+  protected EvalNode visitFuncCall(CONTEXT context, FunctionEval evalNode, Stack<EvalNode> stack) {
+    return visitDefaultFunctionEval(context, stack, evalNode);
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/UnaryEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/UnaryEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/UnaryEval.java
new file mode 100644
index 0000000..7d45776
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/UnaryEval.java
@@ -0,0 +1,107 @@
+/**
+ * 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.plan.expr;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.common.TajoDataTypes;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.storage.Tuple;
+
+public abstract class UnaryEval extends EvalNode implements Cloneable {
+  @Expose protected EvalNode child;
+
+  public UnaryEval(EvalType type) {
+    super(type);
+  }
+
+  public UnaryEval(EvalType type, EvalNode child) {
+    super(type);
+    this.child = child;
+  }
+
+  @Override
+  public int childNum() {
+    return 1;
+  }
+
+  public EvalNode getChild(int idx) {
+    Preconditions.checkArgument(idx == 0, "UnaryEval always has one child.");
+    return child;
+  }
+
+  public void setChild(EvalNode child) {
+    this.child = child;
+  }
+
+  public EvalNode getChild() {
+    return child;
+  }
+
+  @Override
+  public TajoDataTypes.DataType getValueType() {
+    return null;
+  }
+
+  @Override
+  public String getName() {
+    return null;
+  }
+
+  @Override
+  public <T extends Datum> T eval(Schema schema, Tuple tuple) {
+    return null;
+  }
+
+  @Override
+  public void preOrder(EvalNodeVisitor visitor) {
+    visitor.visit(this);
+    child.preOrder(visitor);
+  }
+
+  @Override
+  public void postOrder(EvalNodeVisitor visitor) {
+    child.postOrder(visitor);
+    visitor.visit(this);
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof UnaryEval) {
+      UnaryEval another = (UnaryEval) obj;
+      return type == another.type && child.equals(another.child);
+    } else {
+      return false;
+    }
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(type, child);
+  }
+
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    UnaryEval unaryEval = (UnaryEval) super.clone();
+    unaryEval.child = (EvalNode) this.child.clone();
+    return unaryEval;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/expr/WindowFunctionEval.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/WindowFunctionEval.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/WindowFunctionEval.java
new file mode 100644
index 0000000..84b4a45
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/WindowFunctionEval.java
@@ -0,0 +1,117 @@
+/**
+ * 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.plan.expr;
+
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.FunctionDesc;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.catalog.SortSpec;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.plan.function.AggFunction;
+import org.apache.tajo.plan.function.FunctionContext;
+import org.apache.tajo.plan.logical.WindowSpec;
+import org.apache.tajo.storage.Tuple;
+import org.apache.tajo.storage.VTuple;
+import org.apache.tajo.util.TUtil;
+
+public class WindowFunctionEval extends AggregationFunctionCallEval implements Cloneable {
+  @Expose private SortSpec [] sortSpecs;
+  @Expose WindowSpec.WindowFrame windowFrame;
+  private Tuple params;
+
+  public WindowFunctionEval(FunctionDesc desc, AggFunction instance, EvalNode[] givenArgs,
+                            WindowSpec.WindowFrame windowFrame) {
+    super(EvalType.WINDOW_FUNCTION, desc, instance, givenArgs);
+    this.windowFrame = windowFrame;
+  }
+
+  public boolean hasSortSpecs() {
+    return sortSpecs != null;
+  }
+
+  public void setSortSpecs(SortSpec [] sortSpecs) {
+    this.sortSpecs = sortSpecs;
+  }
+
+  public SortSpec [] getSortSpecs() {
+    return sortSpecs;
+  }
+
+  public WindowSpec.WindowFrame getWindowFrame() {
+    return windowFrame;
+  }
+
+  @Override
+  public Datum eval(Schema schema, Tuple tuple) {
+    throw new UnsupportedOperationException("Cannot execute eval() of aggregation function");
+  }
+
+  public void merge(FunctionContext context, Schema schema, Tuple tuple) {
+    if (params == null) {
+      this.params = new VTuple(argEvals.length);
+    }
+
+    if (argEvals != null) {
+      for (int i = 0; i < argEvals.length; i++) {
+        params.put(i, argEvals[i].eval(schema, tuple));
+      }
+    }
+
+    instance.eval(context, params);
+  }
+
+  public Datum terminate(FunctionContext context) {
+    return instance.terminate(context);
+  }
+
+  @Override
+  public DataType getValueType() {
+    return funcDesc.getReturnType();
+  }
+
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    WindowFunctionEval windowFunctionEval = (WindowFunctionEval) super.clone();
+    if (sortSpecs != null) {
+      windowFunctionEval.sortSpecs = new SortSpec[sortSpecs.length];
+      for (int i = 0; i < sortSpecs.length; i++) {
+        windowFunctionEval.sortSpecs[i] = (SortSpec) sortSpecs[i].clone();
+      }
+    }
+    return windowFunctionEval;
+  }
+
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    if (argEvals != null) {
+      for(int i=0; i < argEvals.length; i++) {
+        sb.append(argEvals[i]);
+        if(i+1 < argEvals.length)
+          sb.append(",");
+      }
+    }
+    sb.append(funcDesc.getFunctionName()).append("(").append(isDistinct() ? " distinct" : "").append(sb)
+        .append(")");
+    if (hasSortSpecs()) {
+      sb.append("ORDER BY ").append(TUtil.arrayToString(sortSpecs));
+    }
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/EvalTreeOptimizationRule.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/EvalTreeOptimizationRule.java b/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/EvalTreeOptimizationRule.java
new file mode 100644
index 0000000..7e03224
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/EvalTreeOptimizationRule.java
@@ -0,0 +1,28 @@
+/**
+ * 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.plan.exprrewrite;
+
+import org.apache.tajo.plan.LogicalPlanner;
+import org.apache.tajo.plan.annotator.Prioritized;
+import org.apache.tajo.plan.expr.EvalNode;
+
+@Prioritized
+public interface EvalTreeOptimizationRule {
+  public EvalNode optimize(LogicalPlanner.PlanContext context, EvalNode tree);
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/EvalTreeOptimizer.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/EvalTreeOptimizer.java b/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/EvalTreeOptimizer.java
new file mode 100644
index 0000000..3bea6a4
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/EvalTreeOptimizer.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.plan.exprrewrite;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tajo.plan.LogicalPlanner;
+import org.apache.tajo.plan.annotator.Prioritized;
+import org.apache.tajo.plan.expr.EvalNode;
+import org.apache.tajo.util.ClassUtil;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+
+public class EvalTreeOptimizer {
+  private static final Log LOG = LogFactory.getLog(EvalTreeOptimizer.class);
+
+  private List<EvalTreeOptimizationRule> rules = Lists.newArrayList();
+
+  public EvalTreeOptimizer() {
+    Set<Class> functionClasses = ClassUtil.findClasses(EvalTreeOptimizationRule.class,
+        EvalTreeOptimizationRule.class.getPackage().getName() + ".rules");
+
+    for (Class eachRule : functionClasses) {
+      if (!EvalTreeOptimizationRule.class.isAssignableFrom(eachRule)) {
+        continue;
+      }
+
+      EvalTreeOptimizationRule rule = null;
+      try {
+        rule = (EvalTreeOptimizationRule)eachRule.newInstance();
+      } catch (Exception e) {
+        LOG.warn(eachRule + " cannot instantiate EvalTreeOptimizerRule class because of " + e.getMessage());
+        continue;
+      }
+      rules.add(rule);
+    }
+
+    Collections.sort(rules, new Comparator<EvalTreeOptimizationRule>() {
+      @Override
+      public int compare(EvalTreeOptimizationRule o1, EvalTreeOptimizationRule o2) {
+        int priority1 = o1.getClass().getAnnotation(Prioritized.class).priority();
+        int priority2 = o2.getClass().getAnnotation(Prioritized.class).priority();
+        return priority1 - priority2;
+      }
+    });
+  }
+
+  public EvalNode optimize(LogicalPlanner.PlanContext context, EvalNode node) {
+    Preconditions.checkNotNull(node);
+
+    EvalNode optimized = node;
+    for (EvalTreeOptimizationRule rule : rules) {
+      optimized = rule.optimize(context, optimized);
+    }
+
+    return optimized;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/rules/ConstantFolding.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/rules/ConstantFolding.java b/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/rules/ConstantFolding.java
new file mode 100644
index 0000000..0e115e2
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/rules/ConstantFolding.java
@@ -0,0 +1,92 @@
+/*
+ * 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.plan.exprrewrite.rules;
+
+import org.apache.tajo.plan.expr.*;
+import org.apache.tajo.plan.exprrewrite.EvalTreeOptimizationRule;
+import org.apache.tajo.plan.annotator.Prioritized;
+import org.apache.tajo.plan.LogicalPlanner;
+
+import java.util.Stack;
+
+@Prioritized(priority = 10)
+public class ConstantFolding extends SimpleEvalNodeVisitor<LogicalPlanner.PlanContext>
+    implements EvalTreeOptimizationRule {
+
+  @Override
+  public EvalNode optimize(LogicalPlanner.PlanContext context, EvalNode evalNode) {
+    return visit(context, evalNode, new Stack<EvalNode>());
+  }
+
+  @Override
+  public EvalNode visitBinaryEval(LogicalPlanner.PlanContext context, Stack<EvalNode> stack, BinaryEval binaryEval) {
+    stack.push(binaryEval);
+    EvalNode lhs = visit(context, binaryEval.getLeftExpr(), stack);
+    EvalNode rhs = visit(context, binaryEval.getRightExpr(), stack);
+    stack.pop();
+
+    if (!binaryEval.getLeftExpr().equals(lhs)) {
+      binaryEval.setLeftExpr(lhs);
+    }
+    if (!binaryEval.getRightExpr().equals(rhs)) {
+      binaryEval.setRightExpr(rhs);
+    }
+
+    if (lhs.getType() == EvalType.CONST && rhs.getType() == EvalType.CONST) {
+      return new ConstEval(binaryEval.eval(null, null));
+    }
+
+    return binaryEval;
+  }
+
+  @Override
+  public EvalNode visitUnaryEval(LogicalPlanner.PlanContext context, Stack<EvalNode> stack, UnaryEval unaryEval) {
+    stack.push(unaryEval);
+    EvalNode child = visit(context, unaryEval.getChild(), stack);
+    stack.pop();
+
+    if (child.getType() == EvalType.CONST) {
+      return new ConstEval(unaryEval.eval(null, null));
+    }
+
+    return unaryEval;
+  }
+
+  @Override
+  public EvalNode visitFuncCall(LogicalPlanner.PlanContext context, FunctionEval evalNode, Stack<EvalNode> stack) {
+    boolean constantOfAllDescendents = true;
+
+    if ("sleep".equals(evalNode.getFuncDesc().getFunctionName())) {
+      constantOfAllDescendents = false;
+    } else {
+      if (evalNode.getArgs() != null) {
+        for (EvalNode arg : evalNode.getArgs()) {
+          arg = visit(context, arg, stack);
+          constantOfAllDescendents &= (arg.getType() == EvalType.CONST);
+        }
+      }
+    }
+
+    if (constantOfAllDescendents && evalNode.getType() == EvalType.FUNCTION) {
+      return new ConstEval(evalNode.eval(null, null));
+    } else {
+      return evalNode;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/rules/ConstantPropagation.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/rules/ConstantPropagation.java b/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/rules/ConstantPropagation.java
new file mode 100644
index 0000000..6fe3b3e
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/exprrewrite/rules/ConstantPropagation.java
@@ -0,0 +1,112 @@
+/**
+ * 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.plan.exprrewrite.rules;
+
+import org.apache.tajo.plan.LogicalPlanner;
+import org.apache.tajo.plan.expr.*;
+import org.apache.tajo.plan.exprrewrite.EvalTreeOptimizationRule;
+import org.apache.tajo.plan.annotator.Prioritized;
+
+import java.util.Stack;
+
+/**
+ * It replaces all field references which actually point to constant values by constant values.
+ * In order to maximize the effectiveness of constant folding, ConstantPropagation should be performed after
+ * constant folding.
+ */
+@Prioritized(priority = 15)
+public class ConstantPropagation extends SimpleEvalNodeVisitor<LogicalPlanner.PlanContext>
+    implements EvalTreeOptimizationRule {
+
+  @Override
+  public EvalNode optimize(LogicalPlanner.PlanContext context, EvalNode evalNode) {
+    if (evalNode.getType() == EvalType.FIELD) {
+      FieldEval fieldEval = (FieldEval) evalNode;
+
+      // if a reference points to a const value
+      if (context.getQueryBlock().isConstReference(fieldEval.getName())) {
+        return context.getQueryBlock().getConstByReference(fieldEval.getName());
+      } else {
+        return evalNode; // otherwise, it just returns.
+      }
+    } else {
+      return visit(context, evalNode, new Stack<EvalNode>());
+    }
+  }
+
+  @Override
+  public EvalNode visitBinaryEval(LogicalPlanner.PlanContext context, Stack<EvalNode> stack, BinaryEval binaryEval) {
+    stack.push(binaryEval);
+
+    for (int i = 0; i < 2; i++) {
+      if (binaryEval.getChild(i).getType() == EvalType.FIELD) {
+        FieldEval fieldEval = (FieldEval) binaryEval.getChild(i);
+        if (context.getQueryBlock().isConstReference(fieldEval.getName())) {
+          binaryEval.setChild(i, context.getQueryBlock().getConstByReference(fieldEval.getName()));
+          continue;
+        }
+      }
+
+      visit(context, binaryEval.getChild(i), stack);
+    }
+
+    stack.pop();
+
+    return binaryEval;
+  }
+
+  @Override
+  public EvalNode visitUnaryEval(LogicalPlanner.PlanContext context, Stack<EvalNode> stack, UnaryEval unaryEval) {
+    stack.push(unaryEval);
+
+    if (unaryEval.getChild().getType() == EvalType.FIELD) {
+      FieldEval fieldEval = (FieldEval) unaryEval.getChild();
+      if (context.getQueryBlock().isConstReference(fieldEval.getName())) {
+        unaryEval.setChild(context.getQueryBlock().getConstByReference(fieldEval.getName()));
+        stack.pop();
+        return unaryEval;
+      }
+    }
+    visit(context, unaryEval.getChild(), stack);
+    stack.pop();
+
+    return unaryEval;
+  }
+
+  @Override
+  public EvalNode visitFuncCall(LogicalPlanner.PlanContext context, FunctionEval function, Stack<EvalNode> stack) {
+    stack.push(function);
+
+    for (int i = 0; i < function.getArgs().length; i++) {
+      if (function.getArgs()[i].getType() == EvalType.FIELD) {
+        FieldEval fieldEval = (FieldEval) function.getArgs()[i];
+        if (context.getQueryBlock().isConstReference(fieldEval.getName())) {
+          function.setArg(i, context.getQueryBlock().getConstByReference(fieldEval.getName()));
+          continue;
+        }
+      }
+
+      visit(context, function.getArgs()[i], stack);
+    }
+
+    stack.pop();
+
+    return function;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/function/AggFunction.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/function/AggFunction.java b/tajo-plan/src/main/java/org/apache/tajo/plan/function/AggFunction.java
new file mode 100644
index 0000000..08ea6a7
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/function/AggFunction.java
@@ -0,0 +1,59 @@
+/**
+ * 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.plan.function;
+
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.function.Function;
+import org.apache.tajo.catalog.json.CatalogGsonHelper;
+import org.apache.tajo.catalog.proto.CatalogProtos;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.storage.Tuple;
+
+@Deprecated
+public abstract class AggFunction<T extends Datum> extends Function<T> {
+
+  public AggFunction(Column[] definedArgs) {
+    super(definedArgs);
+  }
+
+  public abstract FunctionContext newContext();
+
+  public abstract void eval(FunctionContext ctx, Tuple params);
+
+  public void merge(FunctionContext ctx, Tuple part) {
+    eval(ctx, part);
+  }
+
+  public abstract Datum getPartialResult(FunctionContext ctx);
+
+  public abstract DataType getPartialResultType();
+
+  public abstract T terminate(FunctionContext ctx);
+
+  @Override
+  public String toJson() {
+    return CatalogGsonHelper.toJson(this, AggFunction.class);
+  }
+
+  @Override
+  public CatalogProtos.FunctionType getFunctionType() {
+    return CatalogProtos.FunctionType.AGGREGATION;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/function/FunctionContext.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/function/FunctionContext.java b/tajo-plan/src/main/java/org/apache/tajo/plan/function/FunctionContext.java
new file mode 100644
index 0000000..9844bbc
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/function/FunctionContext.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.plan.function;
+
+public interface FunctionContext {
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/function/GeneralFunction.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/function/GeneralFunction.java b/tajo-plan/src/main/java/org/apache/tajo/plan/function/GeneralFunction.java
new file mode 100644
index 0000000..006449f
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/function/GeneralFunction.java
@@ -0,0 +1,57 @@
+/**
+ * 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.plan.function;
+
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.json.CatalogGsonHelper;
+import org.apache.tajo.catalog.proto.CatalogProtos;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.function.Function;
+import org.apache.tajo.json.GsonObject;
+import org.apache.tajo.plan.expr.FunctionEval;
+import org.apache.tajo.storage.Tuple;
+
+@Deprecated
+public abstract class GeneralFunction extends Function implements GsonObject {
+  public GeneralFunction(Column[] definedArgs) {
+    super(definedArgs);
+  }
+
+  /**
+   * This method gives hints to an actual function instance.
+   */
+  public void init(FunctionEval.ParamType [] paramTypes) {}
+
+  public abstract Datum eval(Tuple params);
+
+	public enum Type {
+	  AGG,
+	  GENERAL
+	}
+
+  @Override
+  public String toJson() {
+    return CatalogGsonHelper.toJson(this, GeneralFunction.class);
+  }
+
+  @Override
+  public CatalogProtos.FunctionType getFunctionType() {
+    return CatalogProtos.FunctionType.GENERAL;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/function/WindowAggFunc.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/function/WindowAggFunc.java b/tajo-plan/src/main/java/org/apache/tajo/plan/function/WindowAggFunc.java
new file mode 100644
index 0000000..82f7257
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/function/WindowAggFunc.java
@@ -0,0 +1,62 @@
+/**
+ * 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.plan.function;
+
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.json.CatalogGsonHelper;
+import org.apache.tajo.catalog.proto.CatalogProtos;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.exception.InvalidOperationException;
+import org.apache.tajo.storage.Tuple;
+
+public abstract class WindowAggFunc<T extends Datum> extends AggFunction<T> {
+
+  public WindowAggFunc(Column[] definedArgs) {
+    super(definedArgs);
+  }
+
+  public abstract FunctionContext newContext();
+
+  public abstract void eval(FunctionContext ctx, Tuple params);
+
+  public void merge(FunctionContext ctx, Tuple part) {
+    throw new InvalidOperationException("Window function does not support getPartialResult()");
+  }
+
+  public Datum getPartialResult(FunctionContext ctx) {
+    throw new InvalidOperationException("Window function does not support getPartialResult()");
+  }
+
+  public DataType getPartialResultType() {
+    throw new InvalidOperationException("Window function does not support getPartialResultType()");
+  }
+
+  public abstract T terminate(FunctionContext ctx);
+
+  @Override
+  public String toJson() {
+    return CatalogGsonHelper.toJson(this, WindowAggFunc.class);
+  }
+
+  @Override
+  public CatalogProtos.FunctionType getFunctionType() {
+    return CatalogProtos.FunctionType.WINDOW;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/joinorder/Edge.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/joinorder/Edge.java b/tajo-plan/src/main/java/org/apache/tajo/plan/joinorder/Edge.java
new file mode 100644
index 0000000..0ff305f
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/joinorder/Edge.java
@@ -0,0 +1,50 @@
+/**
+ * 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.plan.joinorder;
+
+import org.apache.tajo.plan.expr.EvalNode;
+
+public class Edge {
+  private String src;
+  private String target;
+  private EvalNode joinQual;
+
+  public Edge(String src, String target, EvalNode joinQual) {
+    this.src = src;
+    this.target = target;
+    this.joinQual = joinQual;
+  }
+
+  public String getSrc() {
+    return this.src;
+  }
+
+  public String getTarget() {
+    return this.target;
+  }
+
+  public EvalNode getJoinQual() {
+    return this.joinQual;
+  }
+
+  @Override
+  public String toString() {
+    return "(" + src + "=> " + target + ", " + joinQual + ")";
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-plan/src/main/java/org/apache/tajo/plan/joinorder/FoundJoinOrder.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/joinorder/FoundJoinOrder.java b/tajo-plan/src/main/java/org/apache/tajo/plan/joinorder/FoundJoinOrder.java
new file mode 100644
index 0000000..57fdb7b
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/joinorder/FoundJoinOrder.java
@@ -0,0 +1,47 @@
+/**
+ * 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.plan.joinorder;
+
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.tajo.plan.logical.JoinNode;
+
+/**
+ * It contains the result of join enumeration.
+ */
+@InterfaceStability.Evolving
+public class FoundJoinOrder {
+  private JoinNode joinNode;
+  private double cost;
+
+  public FoundJoinOrder(JoinNode joinNode, double cost) {
+    this.joinNode = joinNode;
+    this.cost = cost;
+  }
+
+  /**
+   * @return a ordered join operators
+   */
+  public JoinNode getOrderedJoin() {
+    return this.joinNode;
+  }
+
+  public double getCost() {
+    return cost;
+  }
+}