blob: 2ad6b6f103c3169807701617bdedc905a4daf43f [file] [log] [blame]
/**
* 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.util;
import org.apache.tajo.algebra.*;
import org.apache.tajo.common.TajoDataTypes;
import org.apache.tajo.datum.DateDatum;
import org.apache.tajo.datum.Datum;
import org.apache.tajo.datum.TimeDatum;
import org.apache.tajo.datum.TimestampDatum;
import org.apache.tajo.exception.UnsupportedException;
import org.apache.tajo.plan.expr.*;
import java.util.Stack;
/**
* This converts EvalNode tree to Expr tree.
*
*/
public class EvalNodeToExprConverter extends SimpleEvalNodeVisitor<Object> {
private Stack<Expr> exprs = new Stack<>();
private String tableName;
public EvalNodeToExprConverter(String tableName) {
this.tableName = tableName;
}
public Expr getResult() {
return exprs.pop();
}
@Override
protected EvalNode visitBinaryEval(Object o, Stack<EvalNode> stack, BinaryEval binaryEval) {
stack.push(binaryEval);
visit(o, binaryEval.getLeftExpr(), stack);
Expr left = exprs.pop();
visit(o, binaryEval.getRightExpr(), stack);
Expr right = exprs.pop();
Expr expr = null;
switch (binaryEval.getType()) {
// Arithmetic expression
case PLUS:
expr = new BinaryOperator(OpType.Plus, left, right);
break;
case MINUS:
expr = new BinaryOperator(OpType.Minus, left, right);
break;
case MULTIPLY:
expr = new BinaryOperator(OpType.Multiply, left, right);
break;
case DIVIDE:
expr = new BinaryOperator(OpType.Divide, left, right);
break;
case MODULAR:
expr = new BinaryOperator(OpType.Modular, left, right);
break;
// Logical Predicates
case AND:
expr = new BinaryOperator(OpType.And, left, right);
break;
case OR:
expr = new BinaryOperator(OpType.Or, left, right);
break;
case NOT:
expr = new BinaryOperator(OpType.Not, left, right);
break;
// Comparison Predicates
case EQUAL:
expr = new BinaryOperator(OpType.Equals, left, right);
break;
case NOT_EQUAL:
expr = new BinaryOperator(OpType.NotEquals, left, right);
break;
case LTH:
expr = new BinaryOperator(OpType.LessThan, left, right);
break;
case LEQ:
expr = new BinaryOperator(OpType.LessThanOrEquals, left, right);
break;
case GTH:
expr = new BinaryOperator(OpType.GreaterThan, left, right);
break;
case GEQ:
expr = new BinaryOperator(OpType.GreaterThanOrEquals, left, right);
break;
// SQL standard predicates
case IS_NULL:
expr = new BinaryOperator(OpType.IsNullPredicate, left, right);
break;
case CASE:
expr = new BinaryOperator(OpType.CaseWhen, left, right);
break;
case IN:
InEval inEval = (InEval) binaryEval;
expr = new InPredicate(left, right, inEval.isNot());
break;
// String operators and Pattern match predicates
case LIKE:
LikePredicateEval likePredicateEval = (LikePredicateEval) binaryEval;
expr = new PatternMatchPredicate(OpType.LikePredicate, likePredicateEval.isNot(), left, right);
break;
case SIMILAR_TO:
SimilarToPredicateEval similarToPredicateEval = (SimilarToPredicateEval) binaryEval;
expr = new PatternMatchPredicate(OpType.SimilarToPredicate, similarToPredicateEval.isNot(), left, right);
break;
case REGEX:
RegexPredicateEval regexPredicateEval = (RegexPredicateEval) binaryEval;
expr = new PatternMatchPredicate(OpType.Regexp, regexPredicateEval.isNot(), left, right);
break;
case CONCATENATE:
default:
throw new RuntimeException("Unsupported type: " + binaryEval.getType().name());
}
if (expr != null) {
exprs.push(expr);
}
stack.pop();
return null;
}
@Override
protected EvalNode visitConst(Object o, ConstEval evalNode, Stack<EvalNode> stack) {
exprs.push(convertDatumToExpr(evalNode.getValueType().kind(), evalNode.getValue()));
return super.visitConst(o, evalNode, stack);
}
@Override
protected EvalNode visitRowConstant(Object o, RowConstantEval evalNode, Stack<EvalNode> stack) {
Expr[] values = new Expr[evalNode.getValues().length];
for (int i = 0; i < evalNode.getValues().length; i++) {
Datum datum = evalNode.getValues()[i];
values[i] = convertDatumToExpr(datum.type(), datum);
}
ValueListExpr expr = new ValueListExpr(values);
exprs.push(expr);
return super.visitRowConstant(o, evalNode, stack);
}
/**
* Convert specified Datum to Expr
*
* @param type value type
* @param datum target datum
* @return converted datum
*/
private Expr convertDatumToExpr(TajoDataTypes.Type type, Datum datum) {
Expr value = null;
DateValue dateValue;
TimeValue timeValue;
switch (type) {
case NULL_TYPE:
value = new NullLiteral();
break;
case BOOLEAN:
value = new BooleanLiteral(datum.asBool());
break;
case INT1:
case INT2:
case INT4:
value = new LiteralValue(datum.asChars(), LiteralValue.LiteralType.Unsigned_Integer);
break;
case INT8:
value = new LiteralValue(datum.asChars(), LiteralValue.LiteralType.Unsigned_Large_Integer);
break;
case FLOAT4:
case FLOAT8:
value = new LiteralValue(datum.asChars(), LiteralValue.LiteralType.Unsigned_Float);
break;
case TEXT:
value = new LiteralValue(datum.asChars(), LiteralValue.LiteralType.String);
break;
case DATE:
DateDatum dateDatum = (DateDatum) datum;
dateValue = new DateValue(""+dateDatum.getYear(),
""+dateDatum.getMonthOfYear(), ""+dateDatum.getDayOfMonth());
value = new DateLiteral(dateValue);
break;
case TIMESTAMP:
TimestampDatum timestampDatum = (TimestampDatum) datum;
dateValue = new DateValue(""+timestampDatum.getYear(),
""+timestampDatum.getMonthOfYear(), ""+timestampDatum.getDayOfMonth());
timeValue = new TimeValue(""+timestampDatum.getHourOfDay()
, ""+timestampDatum.getMinuteOfHour(), ""+timestampDatum.getSecondOfMinute());
value = new TimestampLiteral(dateValue, timeValue);
break;
case TIME:
TimeDatum timeDatum = (TimeDatum) datum;
timeValue = new TimeValue(""+timeDatum.getHourOfDay()
, ""+timeDatum.getMinuteOfHour(), ""+timeDatum.getSecondOfMinute());
value = new TimeLiteral(timeValue);
break;
default:
throw new RuntimeException(new UnsupportedException(type.name()));
}
return value;
}
@Override
protected EvalNode visitField(Object o, FieldEval evalNode, Stack<EvalNode> stack) {
ColumnReferenceExpr expr = new ColumnReferenceExpr(tableName, evalNode.getColumnName());
exprs.push(expr);
return super.visitField(o, evalNode, stack);
}
@Override
protected EvalNode visitBetween(Object o, BetweenPredicateEval evalNode, Stack<EvalNode> stack) {
stack.push(evalNode);
visit(o, evalNode.getPredicand(), stack);
Expr predicand = exprs.pop();
visit(o, evalNode.getBegin(), stack);
Expr begin = exprs.pop();
visit(o, evalNode.getEnd(), stack);
Expr end = exprs.pop();
Expr expr = new BetweenPredicate(evalNode.isNot(), evalNode.isSymmetric(), predicand, begin, end);
exprs.push(expr);
stack.pop();
return null;
}
@Override
protected EvalNode visitCaseWhen(Object o, CaseWhenEval evalNode, Stack<EvalNode> stack) {
stack.push(evalNode);
CaseWhenPredicate caseWhenPredicate = new CaseWhenPredicate();
for (CaseWhenEval.IfThenEval ifThenEval : evalNode.getIfThenEvals()) {
visit(o, ifThenEval.getCondition(), stack);
Expr condition = exprs.pop();
visit(o, ifThenEval.getResult(), stack);
Expr result = exprs.pop();
caseWhenPredicate.addWhen(condition, result);
}
if (evalNode.hasElse()) {
visit(o, evalNode.getElse(), stack);
Expr elseResult = exprs.pop();
caseWhenPredicate.setElseResult(elseResult);
}
exprs.push(caseWhenPredicate);
stack.pop();
return null;
}
}