/* * 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.block.Block; import com.facebook.presto.spi.block.BlockBuilder; import com.facebook.presto.spi.block.BlockBuilderStatus; 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 java.util.List; import java.util.Map; import static com.facebook.presto.spi.type.TypeUtils.writeNativeValue; import static com.facebook.presto.sql.analyzer.ExpressionAnalyzer.getExpressionTypesFromInput; import static java.util.Collections.emptyList; public class InterpretedPageProjection implements PageProjection { private final ExpressionInterpreter evaluator; private final InputChannels inputChannels; private final boolean deterministic; private BlockBuilder blockBuilder; public InterpretedPageProjection( 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); blockBuilder = evaluator.getType().createBlockBuilder(new BlockBuilderStatus(), 1); } @Override public Type getType() { return evaluator.getType(); } @Override public boolean isDeterministic() { return deterministic; } @Override public InputChannels getInputChannels() { return inputChannels; } @Override public Block project(ConnectorSession session, Page page, SelectedPositions selectedPositions) { if (selectedPositions.isList()) { project(page, selectedPositions.getPositions(), selectedPositions.getOffset(), selectedPositions.size()); } else { project(page, selectedPositions.getOffset(), selectedPositions.size()); } Block block = blockBuilder.build(); blockBuilder = blockBuilder.newBlockBuilderLike(new BlockBuilderStatus()); return block; } private void project(Page page, int[] selectedPositions, int offset, int length) { for (int index = offset; index < offset + length; index++) { project(page, selectedPositions[index]); } } private void project(Page page, int offset, int length) { for (int position = offset; position < offset + length; position++) { project(page, position); } } private void project(Page page, int position) { Object value = evaluator.evaluate(position, page.getBlocks()); writeNativeValue(evaluator.getType(), blockBuilder, value); } }