/**
* 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<>());
}
}
@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, UnaryEval unaryEval, Stack<EvalNode> stack) {
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;
}
}