/* * 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.sql.planner; import com.facebook.presto.sql.analyzer.RelationType; import com.facebook.presto.sql.analyzer.Scope; import com.facebook.presto.sql.planner.plan.PlanNode; import com.google.common.collect.ImmutableList; import java.util.List; import java.util.Optional; import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; /** * The purpose of this class is to hold the current plan built so far * for a relation (query, table, values, etc.), and the mapping to * indicate how the fields (by position) in the relation map to * the outputs of the plan. * * Fields are resolved by {@link TranslationMap} within local scopes hierarchy. * Indexes of resolved parent scope fields start from "total number of child scope fields". * For instance if a child scope has n fields, then first parent scope field * will have index n. */ class RelationPlan { private final PlanNode root; private final List<Symbol> fieldMappings; // for each field in the relation, the corresponding symbol from "root" private final Scope scope; public RelationPlan(PlanNode root, Scope scope, List<Symbol> fieldMappings) { requireNonNull(root, "root is null"); requireNonNull(fieldMappings, "outputSymbols is null"); requireNonNull(scope, "scope is null"); int allFieldCount = getAllFieldCount(scope); checkArgument(allFieldCount == fieldMappings.size(), "Number of outputs (%s) doesn't match number of fields in scopes tree (%s)", fieldMappings.size(), allFieldCount); this.root = root; this.scope = scope; this.fieldMappings = ImmutableList.copyOf(fieldMappings); } public Symbol getSymbol(int fieldIndex) { checkArgument(fieldIndex >= 0 && fieldIndex < fieldMappings.size() && fieldMappings.get(fieldIndex) != null, "No field->symbol mapping for field %s", fieldIndex); return fieldMappings.get(fieldIndex); } public PlanNode getRoot() { return root; } public List<Symbol> getFieldMappings() { return fieldMappings; } public RelationType getDescriptor() { return scope.getRelationType(); } public Scope getScope() { return scope; } private static int getAllFieldCount(Scope root) { int allFieldCount = 0; Optional<Scope> current = Optional.of(root); while (current.isPresent()) { allFieldCount += current.get().getRelationType().getAllFieldCount(); current = current.get().getLocalParent(); } return allFieldCount; } }