/**
* 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.TajoInternalError;
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, (UnaryEval) evalNode, stack);
} 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, (FieldEval) evalNode, stack);
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;
case SUBQUERY:
result = visitSubquery(context, (SubqueryEval) evalNode, stack);
break;
default:
throw new TajoInternalError("Unknown EvalType: " + evalNode);
}
}
return result;
}
protected EvalNode visitUnaryEval(CONTEXT context, UnaryEval unaryEval, Stack<EvalNode> stack) {
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, FieldEval evalNode, Stack<EvalNode> stack) {
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;
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Functions
///////////////////////////////////////////////////////////////////////////////////////////////
protected EvalNode visitFuncCall(CONTEXT context, FunctionEval evalNode, Stack<EvalNode> stack) {
return visitDefaultFunctionEval(context, stack, evalNode);
}
protected EvalNode visitSubquery(CONTEXT context, SubqueryEval evalNode, Stack<EvalNode> stack) {
return evalNode;
}
}