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