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/04/18 11:20:09 UTC
[47/51] [partial] TAJO-752: Escalate sub modules in tajo-core into
the top-level modules. (hyunsik)
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
new file mode 100644
index 0000000..d362927
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
@@ -0,0 +1,205 @@
+/**
+ * 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.annotations.Expose;
+import org.apache.tajo.catalog.CatalogUtil;
+import org.apache.tajo.catalog.Schema;
+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 static org.apache.tajo.common.TajoDataTypes.Type;
+
+public class BinaryEval extends EvalNode implements Cloneable {
+ @Expose private DataType returnType = null;
+
+ /**
+ * @param type
+ */
+ public BinaryEval(EvalType type, EvalNode left, EvalNode right) {
+ super(type, left, right);
+ Preconditions.checkNotNull(type);
+ Preconditions.checkNotNull(left);
+ Preconditions.checkNotNull(right);
+
+ if(
+ type == EvalType.AND ||
+ type == EvalType.OR ||
+ type == EvalType.EQUAL ||
+ type == EvalType.NOT_EQUAL ||
+ type == EvalType.LTH ||
+ type == EvalType.GTH ||
+ type == EvalType.LEQ ||
+ type == EvalType.GEQ ) {
+ this.returnType = CatalogUtil.newSimpleDataType(Type.BOOLEAN);
+ } else if (
+ type == EvalType.PLUS ||
+ type == EvalType.MINUS ||
+ type == EvalType.MULTIPLY ||
+ type == EvalType.DIVIDE ||
+ type == EvalType.MODULAR ) {
+ this.returnType = determineType(left.getValueType(), right.getValueType());
+
+ } else if (type == EvalType.CONCATENATE) {
+ this.returnType = CatalogUtil.newSimpleDataType(Type.TEXT);
+ }
+ }
+
+ public BinaryEval(PartialBinaryExpr expr) {
+ this(expr.type, expr.leftExpr, expr.rightExpr);
+ }
+
+ /**
+ * This is verified by ExprsVerifier.checkArithmeticOperand().
+ */
+ private DataType determineType(DataType left, DataType right) throws InvalidEvalException {
+ switch (left.getType()) {
+ case INT4: {
+ switch(right.getType()) {
+ case INT2:
+ case INT4: return CatalogUtil.newSimpleDataType(Type.INT4);
+ case INT8: return CatalogUtil.newSimpleDataType(Type.INT8);
+ case FLOAT4: return CatalogUtil.newSimpleDataType(Type.FLOAT4);
+ case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8);
+ }
+ }
+
+ case INT8: {
+ switch(right.getType()) {
+ case INT2:
+ case INT4:
+ case INT8: return CatalogUtil.newSimpleDataType(Type.INT8);
+ case FLOAT4:
+ case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8);
+ }
+ }
+
+ case FLOAT4: {
+ switch(right.getType()) {
+ case INT2:
+ case INT4:
+ case INT8:
+ case FLOAT4:
+ case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8);
+ }
+ }
+
+ case FLOAT8: {
+ switch(right.getType()) {
+ case INT2:
+ case INT4:
+ case INT8:
+ case FLOAT4:
+ case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8);
+ }
+ }
+
+ default: return left;
+ }
+ }
+
+ @Override
+ public Datum eval(Schema schema, Tuple tuple) {
+ Datum lhs = leftExpr.eval(schema, tuple);
+ Datum rhs = rightExpr.eval(schema, tuple);
+
+ switch(type) {
+ case AND:
+ return lhs.and(rhs);
+ case OR:
+ return lhs.or(rhs);
+
+ case EQUAL:
+ return lhs.equalsTo(rhs);
+ case NOT_EQUAL:
+ return lhs.notEqualsTo(rhs);
+ case LTH:
+ return lhs.lessThan(rhs);
+ case LEQ:
+ return lhs.lessThanEqual(rhs);
+ case GTH:
+ return lhs.greaterThan(rhs);
+ case GEQ:
+ return lhs.greaterThanEqual(rhs);
+
+ case PLUS:
+ return lhs.plus(rhs);
+ case MINUS:
+ return lhs.minus(rhs);
+ case MULTIPLY:
+ return lhs.multiply(rhs);
+ case DIVIDE:
+ return lhs.divide(rhs);
+ case MODULAR:
+ return lhs.modular(rhs);
+
+ case CONCATENATE:
+ if (lhs.type() == Type.NULL_TYPE || rhs.type() == Type.NULL_TYPE) {
+ return NullDatum.get();
+ }
+ return DatumFactory.createText(lhs.asChars() + rhs.asChars());
+ default:
+ throw new InvalidEvalException("We does not support " + type + " expression yet");
+ }
+ }
+
+ @Override
+ public String getName() {
+ return type.name();
+ }
+
+ @Override
+ public DataType getValueType() {
+ return returnType;
+ }
+
+ public String toString() {
+ return leftExpr +" " + type.getOperatorName() + " "+rightExpr;
+ }
+
+ @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/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
new file mode 100644
index 0000000..d08bfd3
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
@@ -0,0 +1,208 @@
+/**
+ * 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.NullDatum;
+import org.apache.tajo.engine.json.CoreGsonHelper;
+import org.apache.tajo.json.GsonObject;
+import org.apache.tajo.storage.Tuple;
+import org.apache.tajo.util.TUtil;
+
+import java.util.List;
+
+public class CaseWhenEval extends EvalNode implements GsonObject {
+ @Expose private List<IfThenEval> whens = Lists.newArrayList();
+ @Expose private EvalNode elseResult;
+
+ public CaseWhenEval() {
+ super(EvalType.CASE);
+ }
+
+ public void addWhen(EvalNode condition, EvalNode result) {
+ whens.add(new IfThenEval(condition, result));
+ }
+
+ public List<IfThenEval> getIfThenEvals() {
+ return whens;
+ }
+
+ public boolean hasElse() {
+ return this.elseResult != null;
+ }
+
+ public EvalNode getElse() {
+ return elseResult;
+ }
+
+ public void setElseResult(EvalNode elseResult) {
+ this.elseResult = elseResult;
+ }
+
+ @Override
+ public DataType getValueType() {
+ return whens.get(0).getResultExpr().getValueType();
+ }
+
+ @Override
+ public String getName() {
+ return "?";
+ }
+
+ public Datum eval(Schema schema, Tuple tuple) {
+ for (int i = 0; i < whens.size(); i++) {
+ if (whens.get(i).checkIfCondition(schema, tuple)) {
+ return whens.get(i).eval(schema, tuple);
+ }
+ }
+
+ if (elseResult != null) { // without else clause
+ return elseResult.eval(schema, tuple);
+ }
+
+ return NullDatum.get();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("CASE ");
+ for (IfThenEval when : whens) {
+ sb.append(when).append(" ");
+ }
+
+ sb.append("ELSE ").append(elseResult).append(" END");
+
+ return sb.toString();
+ }
+
+ @Override
+ public void preOrder(EvalNodeVisitor visitor) {
+ visitor.visit(this);
+ for (IfThenEval when : whens) {
+ when.preOrder(visitor);
+ }
+ if (elseResult != null) { // without else clause
+ elseResult.preOrder(visitor);
+ }
+ }
+
+ @Override
+ public void postOrder(EvalNodeVisitor visitor) {
+ for (IfThenEval 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 TUtil.checkEquals(elseResult, other.elseResult);
+ } else {
+ return false;
+ }
+ }
+
+ public static class IfThenEval extends EvalNode implements GsonObject {
+ @Expose private EvalNode condition;
+ @Expose private EvalNode result;
+
+ public IfThenEval(EvalNode condition, EvalNode result) {
+ super(EvalType.IF_THEN);
+ this.condition = condition;
+ this.result = result;
+ }
+
+ @Override
+ public DataType getValueType() {
+ return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.BOOLEAN);
+ }
+
+ @Override
+ public String getName() {
+ return "when?";
+ }
+
+ public boolean checkIfCondition(Schema schema, Tuple tuple) {
+ return condition.eval(schema, tuple).isTrue();
+ }
+
+ public Datum eval(Schema schema, Tuple tuple) {
+ return result.eval(schema, tuple);
+ }
+
+ public EvalNode getConditionExpr() {
+ return this.condition;
+ }
+
+ public EvalNode getResultExpr() {
+ return this.result;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof IfThenEval) {
+ IfThenEval other = (IfThenEval) object;
+ return condition.equals(other.condition) && result.equals(other.result);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "WHEN " + condition + " THEN " + result;
+ }
+
+ @Override
+ public String toJson() {
+ return CoreGsonHelper.toJson(IfThenEval.this, IfThenEval.class);
+ }
+
+ @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);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/CastEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/CastEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/CastEval.java
new file mode 100644
index 0000000..a024b01
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/CastEval.java
@@ -0,0 +1,87 @@
+/**
+ * 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.Schema;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.datum.DatumFactory;
+import org.apache.tajo.storage.Tuple;
+
+import static org.apache.tajo.common.TajoDataTypes.DataType;
+
+public class CastEval extends EvalNode {
+ @Expose private EvalNode operand;
+ @Expose private DataType target;
+
+ public CastEval(EvalNode operand, DataType target) {
+ super(EvalType.CAST);
+ this.operand = operand;
+ this.target = target;
+ }
+
+ public EvalNode getOperand() {
+ return operand;
+ }
+
+ @Override
+ public DataType getValueType() {
+ return target;
+ }
+
+ @Override
+ public String getName() {
+ return target.getType().name();
+ }
+
+ public Datum eval(Schema schema, Tuple tuple) {
+ Datum operandDatum = operand.eval(schema, tuple);
+ if (operandDatum.isNull()) {
+ return operandDatum;
+ }
+
+ return DatumFactory.cast(operandDatum, target);
+ }
+
+ public String toString() {
+ return "CAST (" + operand + " AS " + target.getType() + ")";
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ boolean valid = obj != null && obj instanceof CastEval;
+ if (valid) {
+ CastEval another = (CastEval) obj;
+ return operand.equals(another.operand) && target.equals(another.target);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void preOrder(EvalNodeVisitor visitor) {
+ visitor.visit(this);
+ operand.preOrder(visitor);
+ }
+
+ public void postOrder(EvalNodeVisitor visitor) {
+ operand.postOrder(visitor);
+ visitor.visit(this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/ConstEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/ConstEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/ConstEval.java
new file mode 100644
index 0000000..2cb530d
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/ConstEval.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.engine.eval;
+
+import com.google.common.base.Objects;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.CatalogUtil;
+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 ConstEval extends EvalNode implements Comparable<ConstEval>, Cloneable {
+ @Expose Datum datum = null;
+
+ public ConstEval(Datum datum) {
+ super(EvalType.CONST);
+ this.datum = datum;
+ }
+
+ public Datum getValue() {
+ return this.datum;
+ }
+
+ public String toString() {
+ return datum.toString();
+ }
+
+ @Override
+ public Datum eval(Schema schema, Tuple tuple) {
+ return datum;
+ }
+
+ @Override
+ public DataType getValueType() {
+ return CatalogUtil.newSimpleDataType(datum.type());
+ }
+
+ @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/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNode.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
new file mode 100644
index 0000000..1180bde
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNode.java
@@ -0,0 +1,118 @@
+/**
+ * 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.Schema;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.engine.json.CoreGsonHelper;
+import org.apache.tajo.json.GsonObject;
+import org.apache.tajo.storage.Tuple;
+
+/**
+ * An annotated expression which includes actual data domains.
+ * It is also used for evaluation.
+ */
+public abstract class EvalNode implements Cloneable, GsonObject {
+ @Expose protected EvalType type;
+ @Expose protected EvalNode leftExpr;
+ @Expose protected EvalNode rightExpr;
+
+ public EvalNode(EvalType type) {
+ this.type = type;
+ }
+
+ public EvalNode(EvalType type, EvalNode left, EvalNode right) {
+ this(type);
+ this.leftExpr = left;
+ this.rightExpr = right;
+ }
+
+ public EvalType getType() {
+ return this.type;
+ }
+
+ public void setLeftExpr(EvalNode expr) {
+ this.leftExpr = expr;
+ }
+
+ public <T extends EvalNode> T getLeftExpr() {
+ return (T) this.leftExpr;
+ }
+
+ public void setRightExpr(EvalNode expr) {
+ this.rightExpr = expr;
+ }
+
+ public <T extends EvalNode> T getRightExpr() {
+ return (T) 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() + "))";
+ }
+
+ @Override
+ public String toJson() {
+ return CoreGsonHelper.toJson(this, EvalNode.class);
+ }
+
+ public abstract <T extends Datum> T eval(Schema schema, Tuple tuple);
+
+ @Deprecated
+ public void preOrder(EvalNodeVisitor visitor) {
+ visitor.visit(this);
+ leftExpr.preOrder(visitor);
+ rightExpr.preOrder(visitor);
+ }
+
+ @Deprecated
+ public void postOrder(EvalNodeVisitor visitor) {
+ leftExpr.postOrder(visitor);
+ rightExpr.postOrder(visitor);
+ visitor.visit(this);
+ }
+
+ 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/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java
new file mode 100644
index 0000000..1680b31
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor.java
@@ -0,0 +1,24 @@
+/**
+ * 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;
+
+@Deprecated
+public interface EvalNodeVisitor {
+ public void visit(EvalNode node);
+}
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor2.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor2.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor2.java
new file mode 100644
index 0000000..024a988
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalNodeVisitor2.java
@@ -0,0 +1,71 @@
+/**
+ * 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 java.util.Stack;
+
+public interface EvalNodeVisitor2<CONTEXT, RESULT> {
+ RESULT visitChild(CONTEXT context, EvalNode evalNode, Stack<EvalNode> stack);
+
+ // Column and Value reference expressions
+ RESULT visitConst(CONTEXT context, ConstEval evalNode, Stack<EvalNode> stack);
+ RESULT visitRowConstant(CONTEXT context, RowConstantEval evalNode, Stack<EvalNode> stack);
+ RESULT visitField(CONTEXT context, Stack<EvalNode> stack, FieldEval evalNode);
+
+ // Arithmetic expression
+ RESULT visitPlus(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+ RESULT visitMinus(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+ RESULT visitMultiply(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+ RESULT visitDivide(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+ RESULT visitModular(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+
+ // Logical Predicates
+ RESULT visitAnd(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+ RESULT visitOr(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+ RESULT visitNot(CONTEXT context, NotEval evalNode, Stack<EvalNode> stack);
+
+ // Comparison Predicates
+ RESULT visitEqual(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+ RESULT visitNotEqual(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+ RESULT visitLessThan(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+ RESULT visitLessThanOrEqual(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+ RESULT visitGreaterThan(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+ RESULT visitGreaterThanOrEqual(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+
+ // Other Predicates
+ RESULT visitIsNull(CONTEXT context, IsNullEval evalNode, Stack<EvalNode> stack);
+ RESULT visitBetween(CONTEXT context, BetweenPredicateEval evalNode, Stack<EvalNode> stack);
+ RESULT visitCaseWhen(CONTEXT context, CaseWhenEval evalNode, Stack<EvalNode> stack);
+ RESULT visitIfThen(CONTEXT context, CaseWhenEval.IfThenEval evalNode, Stack<EvalNode> stack);
+ RESULT visitInPredicate(CONTEXT context, InEval evalNode, Stack<EvalNode> stack);
+
+ // String operator and Pattern matching predicates
+ RESULT visitLike(CONTEXT context, LikePredicateEval evalNode, Stack<EvalNode> stack);
+ RESULT visitSimilarTo(CONTEXT context, SimilarToPredicateEval evalNode, Stack<EvalNode> stack);
+ RESULT visitRegex(CONTEXT context, RegexPredicateEval evalNode, Stack<EvalNode> stack);
+ RESULT visitConcatenate(CONTEXT context, BinaryEval evalNode, Stack<EvalNode> stack);
+
+ // Functions
+ RESULT visitFuncCall(CONTEXT context, GeneralFunctionEval evalNode, Stack<EvalNode> stack);
+ RESULT visitAggrFuncCall(CONTEXT context, AggregationFunctionCallEval evalNode, Stack<EvalNode> stack);
+
+ RESULT visitSigned(CONTEXT context, SignedEval signedEval, Stack<EvalNode> stack);
+
+ RESULT visitCast(CONTEXT context, CastEval signedEval, Stack<EvalNode> stack);
+}
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeFactory.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeFactory.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeFactory.java
new file mode 100644
index 0000000..aa72f25
--- /dev/null
+++ b/tajo-core/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(EvalType type, EvalNode e1,
+ EvalNode e2) {
+ return new BinaryEval(type, e1, e2);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
new file mode 100644
index 0000000..7dcc26a
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
@@ -0,0 +1,350 @@
+/**
+ * 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.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.datum.Datum;
+import org.apache.tajo.engine.planner.Target;
+import org.apache.tajo.exception.InternalException;
+import org.apache.tajo.util.TUtil;
+
+import java.util.*;
+
+public class EvalTreeUtil {
+
+ public static void changeColumnRef(EvalNode node, String oldName, String newName) {
+ node.postOrder(new ChangeColumnRefVisitor(oldName, newName));
+ }
+
+ public static void replace(EvalNode expr, EvalNode targetExpr, EvalNode tobeReplaced) {
+ EvalReplaceVisitor replacer = new EvalReplaceVisitor(targetExpr, tobeReplaced);
+ replacer.visitChild(null, expr, new Stack<EvalNode>());
+ }
+
+ public static class EvalReplaceVisitor extends BasicEvalNodeVisitor<EvalNode, EvalNode> {
+ private EvalNode target;
+ private EvalNode tobeReplaced;
+
+ public EvalReplaceVisitor(EvalNode target, EvalNode tobeReplaced) {
+ this.target = target;
+ this.tobeReplaced = tobeReplaced;
+ }
+
+ @Override
+ public EvalNode visitChild(EvalNode context, EvalNode evalNode, Stack<EvalNode> stack) {
+ super.visitChild(context, evalNode, stack);
+
+ if (evalNode.equals(target)) {
+ EvalNode parent = stack.peek();
+
+ if (parent.getLeftExpr().equals(evalNode)) {
+ parent.setLeftExpr(tobeReplaced);
+ }
+ if (parent.getRightExpr().equals(evalNode)) {
+ parent.setRightExpr(tobeReplaced);
+ }
+ }
+
+ return evalNode;
+ }
+ }
+
+ /**
+ * It finds unique columns from a EvalNode.
+ */
+ public static LinkedHashSet<Column> findUniqueColumns(EvalNode node) {
+ UniqueColumnFinder finder = new UniqueColumnFinder();
+ node.postOrder(finder);
+ return finder.getColumnRefs();
+ }
+
+ public static List<Column> findAllColumnRefs(EvalNode node) {
+ AllColumnRefFinder finder = new AllColumnRefFinder();
+ node.postOrder(finder);
+ return finder.getColumnRefs();
+ }
+
+ 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()));
+ }
+
+ 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 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<EvalType, 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
+ */
+ 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.getSimpleName())) {
+ exprSet.add(field);
+ }
+ break;
+ case CONST:
+ return;
+ default:
+ _containColumnRef(expr.getLeftExpr(), target, exprSet);
+ _containColumnRef(expr.getRightExpr(), target, exprSet);
+ }
+ }
+
+ /**
+ * If a given expression is join condition, it returns TRUE. Otherwise, it returns FALSE.
+ *
+ * @param expr EvalNode to be evaluated
+ * @param includeThetaJoin If true, it will return equi as well as non-equi join conditions.
+ * Otherwise, it only returns equi-join conditions.
+ * @return True if it is join condition.
+ */
+ public static boolean isJoinQual(EvalNode expr, boolean includeThetaJoin) {
+ boolean joinComparator;
+ if (includeThetaJoin) {
+ joinComparator = AlgebraicUtil.isComparisonOperator(expr);
+ } else {
+ joinComparator = expr.getType() == EvalType.EQUAL;
+ }
+
+ return joinComparator && expr.getLeftExpr().getType() == EvalType.FIELD &&
+ expr.getRightExpr().getType() == EvalType.FIELD;
+ }
+
+ 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 == EvalType.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() == EvalType.FIELD) {
+ field = (FieldEval) node;
+ colList.add(field.getColumnRef());
+ }
+ }
+
+ public List<Column> getColumnRefs() {
+ return this.colList;
+ }
+ }
+
+ public static class UniqueColumnFinder implements EvalNodeVisitor {
+ private LinkedHashSet<Column> columnSet = Sets.newLinkedHashSet();
+ private FieldEval field = null;
+
+ @Override
+ public void visit(EvalNode node) {
+ if (node.getType() == EvalType.FIELD) {
+ field = (FieldEval) node;
+ columnSet.add(field.getColumnRef());
+ }
+ }
+
+ public LinkedHashSet<Column> getColumnRefs() {
+ return this.columnSet;
+ }
+ }
+
+ public static class VariableCounter implements EvalNodeVisitor {
+ private final Map<EvalType, Integer> counter;
+
+ public VariableCounter() {
+ counter = Maps.newHashMap();
+ counter.put(EvalType.FUNCTION, 0);
+ counter.put(EvalType.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<EvalType, Integer> getCounter() {
+ return counter;
+ }
+ }
+
+ public static Set<AggregationFunctionCallEval> findDistinctAggFunction(EvalNode expr) {
+ AllAggFunctionFinder finder = new AllAggFunctionFinder();
+ expr.postOrder(finder);
+ return finder.getAggregationFunction();
+ }
+
+ public static class AllAggFunctionFinder implements EvalNodeVisitor {
+ private Set<AggregationFunctionCallEval> aggFucntions = Sets.newHashSet();
+ private AggregationFunctionCallEval field = null;
+
+ @Override
+ public void visit(EvalNode node) {
+ if (node.getType() == EvalType.AGG_FUNCTION) {
+ field = (AggregationFunctionCallEval) node;
+ aggFucntions.add(field);
+ }
+ }
+
+ public Set<AggregationFunctionCallEval> getAggregationFunction() {
+ return this.aggFucntions;
+ }
+ }
+
+ public static <T extends EvalNode> Collection<T> findEvalsByType(EvalNode evalNode, EvalType type) {
+ EvalFinder finder = new EvalFinder(type);
+ finder.visitChild(null, evalNode, new Stack<EvalNode>());
+ return (Collection<T>) finder.evalNodes;
+ }
+
+ public static class EvalFinder extends BasicEvalNodeVisitor<Object, Object> {
+ private EvalType targetType;
+ List<EvalNode> evalNodes = TUtil.newList();
+
+ public EvalFinder(EvalType targetType) {
+ this.targetType = targetType;
+ }
+
+ @Override
+ public Object visitChild(Object context, EvalNode evalNode, Stack<EvalNode> stack) {
+ super.visitChild(context, evalNode, stack);
+
+ if (evalNode.type == targetType) {
+ evalNodes.add(evalNode);
+ }
+
+ return evalNode;
+ }
+ }
+
+ public static boolean checkIfCanBeConstant(EvalNode evalNode) {
+ return findUniqueColumns(evalNode).size() == 0 && findDistinctAggFunction(evalNode).size() == 0;
+ }
+
+ public static Datum evaluateImmediately(EvalNode evalNode) {
+ return evalNode.eval(null, null);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalType.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalType.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalType.java
new file mode 100644
index 0000000..71db934
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalType.java
@@ -0,0 +1,83 @@
+/**
+ * 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 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, "/"),
+
+ // Function
+ 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 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/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/FieldEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
new file mode 100644
index 0000000..ea2b031
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
@@ -0,0 +1,114 @@
+/**
+ * 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.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) {
+ fieldId = schema.getColumnId(column.getQualifiedName());
+ if (fieldId == -1) {
+ throw new IllegalStateException("No Such Column Reference: " + column + ", schema: " + schema);
+ }
+ }
+ return tuple.get(fieldId);
+ }
+
+ @Override
+ public DataType getValueType() {
+ return column.getDataType();
+ }
+
+ 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/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/FunctionEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/FunctionEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/FunctionEval.java
new file mode 100644
index 0000000..de982e5
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/FunctionEval.java
@@ -0,0 +1,144 @@
+/**
+ * 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.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;
+ this.argEvals = argEvals;
+ }
+
+ 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 setArgs(EvalNode [] args) {
+ this.argEvals = args;
+ }
+
+ public DataType getValueType() {
+ return this.funcDesc.getReturnType();
+ }
+
+ @Override
+ public abstract Datum eval(Schema schema, Tuple tuple);
+
+ @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() + "(" + (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();
+ 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);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/GeneralFunctionEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/GeneralFunctionEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/GeneralFunctionEval.java
new file mode 100644
index 0000000..9446d70
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/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.engine.eval;
+
+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.engine.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/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/InEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/InEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/InEval.java
new file mode 100644
index 0000000..51097e6
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/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.engine.eval;
+
+
+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/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/InvalidCastException.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/InvalidCastException.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/InvalidCastException.java
new file mode 100644
index 0000000..b907f06
--- /dev/null
+++ b/tajo-core/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/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/InvalidEvalException.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/InvalidEvalException.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/InvalidEvalException.java
new file mode 100644
index 0000000..96eda91
--- /dev/null
+++ b/tajo-core/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);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java
new file mode 100644
index 0000000..5704aa5
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/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.engine.eval;
+
+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 BinaryEval {
+ // 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, DUMMY_EVAL);
+ this.isNot = not;
+ }
+
+ @Override
+ public DataType getValueType() {
+ return RES_TYPE;
+ }
+
+ @Override
+ public String getName() {
+ return "?";
+ }
+
+ @Override
+ public String toString() {
+ return leftExpr + " IS " + (isNot ? "NOT NULL" : "NULL");
+ }
+
+ @Override
+ public Datum eval(Schema schema, Tuple tuple) {
+ boolean isNull = leftExpr.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/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/LikePredicateEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/LikePredicateEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/LikePredicateEval.java
new file mode 100644
index 0000000..bfac33e
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/LikePredicateEval.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.engine.eval;
+
+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, 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/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/NotEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/NotEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/NotEval.java
new file mode 100644
index 0000000..1a16af4
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/NotEval.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.engine.eval;
+
+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 NotEval extends EvalNode implements Cloneable {
+ @Expose private EvalNode childEval;
+ private static final DataType RES_TYPE = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.BOOLEAN);
+
+ public NotEval(EvalNode childEval) {
+ super(EvalType.NOT);
+ this.childEval = childEval;
+ }
+
+ public EvalNode getChild() {
+ return childEval;
+ }
+
+ @Override
+ public DataType getValueType() {
+ return RES_TYPE;
+ }
+
+ @Override
+ public String getName() {
+ return "?";
+ }
+
+ @Override
+ public Datum eval(Schema schema, Tuple tuple) {
+ Datum datum = childEval.eval(schema, tuple);
+ return !datum.isNull() ? DatumFactory.createBool(!datum.asBool()) : datum;
+ }
+
+ @Override
+ public String toString() {
+ return "NOT " + childEval.toString();
+ }
+
+ @Override
+ public void preOrder(EvalNodeVisitor visitor) {
+ visitor.visit(this);
+ childEval.preOrder(visitor);
+ }
+
+ @Override
+ public void postOrder(EvalNodeVisitor visitor) {
+ childEval.postOrder(visitor);
+ visitor.visit(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof NotEval) {
+ NotEval other = (NotEval) obj;
+ return this.childEval.equals(other.childEval);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ NotEval eval = (NotEval) super.clone();
+ eval.childEval = (EvalNode) this.childEval.clone();
+ return eval;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/PartialBinaryExpr.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/PartialBinaryExpr.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/PartialBinaryExpr.java
new file mode 100644
index 0000000..0f4411d
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/PartialBinaryExpr.java
@@ -0,0 +1,70 @@
+/**
+ * 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.Schema;
+import org.apache.tajo.common.TajoDataTypes.DataType;
+import org.apache.tajo.datum.Datum;
+import org.apache.tajo.storage.Tuple;
+
+public class PartialBinaryExpr extends EvalNode {
+
+ public PartialBinaryExpr(EvalType type) {
+ super(type);
+ }
+
+ public PartialBinaryExpr(EvalType type, EvalNode left, EvalNode right) {
+ super(type, left, right);
+ }
+
+ @Override
+ public DataType getValueType() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return "nonamed";
+ }
+
+ @Override
+ public Datum eval(Schema schema, Tuple tuple) {
+ throw new InvalidEvalException(
+ "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/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/PatternMatchPredicateEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/PatternMatchPredicateEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/PatternMatchPredicateEval.java
new file mode 100644
index 0000000..8d78b0b
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/PatternMatchPredicateEval.java
@@ -0,0 +1,82 @@
+/**
+ * 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.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;
+
+ @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/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/RegexPredicateEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/RegexPredicateEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/RegexPredicateEval.java
new file mode 100644
index 0000000..f1e0241
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/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.engine.eval;
+
+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/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.java
new file mode 100644
index 0000000..646a627
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/RowConstantEval.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.engine.eval;
+
+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 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);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/SignedEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/SignedEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/SignedEval.java
new file mode 100644
index 0000000..3c2eeb4
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/SignedEval.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.engine.eval;
+
+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 EvalNode implements Cloneable {
+ @Expose private EvalNode childEval;
+ @Expose private boolean negative;
+
+ public SignedEval(boolean negative, EvalNode childEval) {
+ super(EvalType.SIGNED);
+ this.negative = negative;
+ this.childEval = childEval;
+ }
+
+ public boolean isNegative() {
+ return negative;
+ }
+
+ public EvalNode getChild() {
+ return childEval;
+ }
+
+ @Override
+ public DataType getValueType() {
+ return childEval.getValueType();
+ }
+
+ @Override
+ public String getName() {
+ return "?";
+ }
+
+ @Override
+ public Datum eval(Schema schema, Tuple tuple) {
+ NumericDatum result = childEval.eval(schema, tuple);
+ if (negative) {
+ return result.inverseSign();
+ }
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return (negative ? "-" : "+") + childEval.toString();
+ }
+
+ @Override
+ public void preOrder(EvalNodeVisitor visitor) {
+ visitor.visit(this);
+ childEval.preOrder(visitor);
+ }
+
+ @Override
+ public void postOrder(EvalNodeVisitor visitor) {
+ childEval.postOrder(visitor);
+ visitor.visit(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof SignedEval) {
+ SignedEval other = (SignedEval) obj;
+ return negative == other.negative && this.childEval.equals(other.childEval);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ SignedEval eval = (SignedEval) super.clone();
+ eval.negative = negative;
+ eval.childEval = (EvalNode) this.childEval.clone();
+ return eval;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tajo/blob/6594ac1c/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimilarToPredicateEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimilarToPredicateEval.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimilarToPredicateEval.java
new file mode 100644
index 0000000..9ac0e62
--- /dev/null
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimilarToPredicateEval.java
@@ -0,0 +1,43 @@
+/**
+ * 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 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) {
+ 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