| /* |
| * 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.SessionVars; |
| import org.apache.tajo.datum.Datum; |
| import org.apache.tajo.plan.LogicalPlanner; |
| import org.apache.tajo.plan.annotator.Prioritized; |
| import org.apache.tajo.plan.expr.*; |
| import org.apache.tajo.plan.exprrewrite.EvalTreeOptimizationRule; |
| import org.apache.tajo.plan.function.python.PythonScriptEngine; |
| import org.apache.tajo.plan.function.python.TajoScriptEngine; |
| |
| import java.io.IOException; |
| import java.util.*; |
| |
| @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<>()); |
| } |
| |
| @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) { |
| binaryEval.bind(null, null); |
| return new ConstEval(binaryEval.eval(null)); |
| } |
| |
| return binaryEval; |
| } |
| |
| @Override |
| public EvalNode visitUnaryEval(LogicalPlanner.PlanContext context, UnaryEval unaryEval, Stack<EvalNode> stack) { |
| stack.push(unaryEval); |
| EvalNode child = visit(context, unaryEval.getChild(), stack); |
| stack.pop(); |
| |
| unaryEval.setChild(child); |
| if (child.getType() == EvalType.CONST) { |
| |
| // session's time zone |
| String timezoneId = context.getQueryContext().get(SessionVars.TIMEZONE); |
| EvalContext evalContext = new EvalContext(); |
| evalContext.setTimeZone(TimeZone.getTimeZone(timezoneId)); |
| unaryEval.bind(evalContext, null); |
| return new ConstEval(unaryEval.eval(null)); |
| } |
| |
| return unaryEval; |
| } |
| |
| // exceptional func names not to use constant folding |
| private static final Set<String> NON_CONSTANT_FUNC_NAMES = new HashSet<>(Arrays.asList("sleep", "random")); |
| |
| @Override |
| public EvalNode visitFuncCall(LogicalPlanner.PlanContext context, FunctionEval evalNode, Stack<EvalNode> stack) { |
| boolean constantOfAllDescendents = true; |
| |
| if (NON_CONSTANT_FUNC_NAMES.contains(evalNode.getFuncDesc().getFunctionName())) { |
| constantOfAllDescendents = false; |
| } else { |
| for (EvalNode arg : evalNode.getArgs()) { |
| arg = visit(context, arg, stack); |
| constantOfAllDescendents &= (arg.getType() == EvalType.CONST); |
| } |
| } |
| |
| if (constantOfAllDescendents && evalNode.getType() == EvalType.FUNCTION) { |
| EvalContext evalContext = new EvalContext(); |
| // session's time zone |
| String timezoneId = context.getQueryContext().get(SessionVars.TIMEZONE); |
| evalContext.setTimeZone(TimeZone.getTimeZone(timezoneId)); |
| |
| if (evalNode.getFuncDesc().getInvocation().hasPython()) { |
| TajoScriptEngine executor = new PythonScriptEngine(evalNode.getFuncDesc()); |
| try { |
| executor.start(context.getQueryContext().getConf()); |
| evalContext.addScriptEngine(evalNode, executor); |
| evalNode.bind(evalContext, null); |
| Datum funcRes = evalNode.eval(null); |
| executor.shutdown(); |
| return new ConstEval(funcRes); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } else { |
| evalNode.bind(evalContext, null); |
| return new ConstEval(evalNode.eval(null)); |
| } |
| |
| } else { |
| return evalNode; |
| } |
| } |
| } |