/*
* Licensed 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 com.facebook.presto.operator.project;
import com.facebook.presto.Session;
import com.facebook.presto.metadata.Metadata;
import com.facebook.presto.spi.ConnectorSession;
import com.facebook.presto.spi.Page;
import com.facebook.presto.spi.type.Type;
import com.facebook.presto.sql.parser.SqlParser;
import com.facebook.presto.sql.planner.DeterminismEvaluator;
import com.facebook.presto.sql.planner.ExpressionInterpreter;
import com.facebook.presto.sql.planner.Symbol;
import com.facebook.presto.sql.planner.SymbolToInputParameterRewriter;
import com.facebook.presto.sql.tree.Expression;
import com.facebook.presto.util.maps.IdentityLinkedHashMap;
import com.google.common.collect.ImmutableMap;
import javax.annotation.concurrent.NotThreadSafe;
import java.util.List;
import java.util.Map;
import static com.facebook.presto.sql.analyzer.ExpressionAnalyzer.getExpressionTypesFromInput;
import static java.lang.Boolean.TRUE;
import static java.util.Collections.emptyList;
@NotThreadSafe
public class InterpretedPageFilter
implements PageFilter
{
private final ExpressionInterpreter evaluator;
private final InputChannels inputChannels;
private final boolean deterministic;
private boolean[] selectedPositions = new boolean[0];
public InterpretedPageFilter(
Expression expression,
Map<Symbol, Type> symbolTypes,
Map<Symbol, Integer> symbolToInputMappings,
Metadata metadata,
SqlParser sqlParser,
Session session)
{
SymbolToInputParameterRewriter rewriter = new SymbolToInputParameterRewriter(symbolTypes, symbolToInputMappings);
Expression rewritten = rewriter.rewrite(expression);
this.inputChannels = new InputChannels(rewriter.getInputChannels());
this.deterministic = DeterminismEvaluator.isDeterministic(expression);
// analyze rewritten expression so we can know the type of every expression in the tree
List<Type> inputTypes = rewriter.getInputTypes();
ImmutableMap.Builder<Integer, Type> parameterTypes = ImmutableMap.builder();
for (int parameter = 0; parameter < inputTypes.size(); parameter++) {
Type type = inputTypes.get(parameter);
parameterTypes.put(parameter, type);
}
IdentityLinkedHashMap<Expression, Type> expressionTypes = getExpressionTypesFromInput(session, metadata, sqlParser, parameterTypes.build(), rewritten, emptyList());
this.evaluator = ExpressionInterpreter.expressionInterpreter(rewritten, metadata, session, expressionTypes);
}
@Override
public boolean isDeterministic()
{
return deterministic;
}
@Override
public InputChannels getInputChannels()
{
return inputChannels;
}
@Override
public SelectedPositions filter(ConnectorSession session, Page page)
{
if (selectedPositions.length < page.getPositionCount()) {
selectedPositions = new boolean[page.getPositionCount()];
}
for (int position = 0; position < page.getPositionCount(); position++) {
selectedPositions[position] = filter(page, position);
}
return PageFilter.positionsArrayToSelectedPositions(selectedPositions, page.getPositionCount());
}
private boolean filter(Page page, int position)
{
return TRUE.equals(evaluator.evaluate(position, page.getBlocks()));
}
}