/* * 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.analyzer; import com.facebook.presto.Session; import com.facebook.presto.execution.DataDefinitionTask; import com.facebook.presto.metadata.Metadata; import com.facebook.presto.security.AccessControl; import com.facebook.presto.sql.parser.SqlParser; import com.facebook.presto.sql.planner.LogicalPlanner; import com.facebook.presto.sql.planner.Plan; import com.facebook.presto.sql.planner.PlanFragmenter; import com.facebook.presto.sql.planner.PlanNodeIdAllocator; import com.facebook.presto.sql.planner.PlanOptimizers; import com.facebook.presto.sql.planner.SubPlan; import com.facebook.presto.sql.planner.optimizations.PlanOptimizer; import com.facebook.presto.sql.planner.planPrinter.PlanPrinter; import com.facebook.presto.sql.tree.ExplainType.Type; import com.facebook.presto.sql.tree.Expression; import com.facebook.presto.sql.tree.Statement; import com.google.common.collect.ImmutableMap; import javax.inject.Inject; import java.util.List; import java.util.Map; import java.util.Optional; import static java.util.Objects.requireNonNull; public class QueryExplainer { private final List<PlanOptimizer> planOptimizers; private final Metadata metadata; private final AccessControl accessControl; private final SqlParser sqlParser; private final Map<Class<? extends Statement>, DataDefinitionTask<?>> dataDefinitionTask; @Inject public QueryExplainer( PlanOptimizers planOptimizers, Metadata metadata, AccessControl accessControl, SqlParser sqlParser, Map<Class<? extends Statement>, DataDefinitionTask<?>> dataDefinitionTask) { this(planOptimizers.get(), metadata, accessControl, sqlParser, dataDefinitionTask); } public QueryExplainer( List<PlanOptimizer> planOptimizers, Metadata metadata, AccessControl accessControl, SqlParser sqlParser, Map<Class<? extends Statement>, DataDefinitionTask<?>> dataDefinitionTask) { this.planOptimizers = requireNonNull(planOptimizers, "planOptimizers is null"); this.metadata = requireNonNull(metadata, "metadata is null"); this.accessControl = requireNonNull(accessControl, "accessControl is null"); this.sqlParser = requireNonNull(sqlParser, "sqlParser is null"); this.dataDefinitionTask = ImmutableMap.copyOf(requireNonNull(dataDefinitionTask, "dataDefinitionTask is null")); } public Analysis analyze(Session session, Statement statement, List<Expression> parameters) { Analyzer analyzer = new Analyzer(session, metadata, sqlParser, accessControl, Optional.of(this), parameters); return analyzer.analyze(statement); } public String getPlan(Session session, Statement statement, Type planType, List<Expression> parameters) { DataDefinitionTask<?> task = dataDefinitionTask.get(statement.getClass()); if (task != null) { return explainTask(statement, task, parameters); } switch (planType) { case LOGICAL: Plan plan = getLogicalPlan(session, statement, parameters); return PlanPrinter.textLogicalPlan(plan.getRoot(), plan.getTypes(), metadata, session); case DISTRIBUTED: SubPlan subPlan = getDistributedPlan(session, statement, parameters); return PlanPrinter.textDistributedPlan(subPlan, metadata, session); } throw new IllegalArgumentException("Unhandled plan type: " + planType); } private static <T extends Statement> String explainTask(Statement statement, DataDefinitionTask<T> task, List<Expression> parameters) { return task.explain((T) statement, parameters); } public String getGraphvizPlan(Session session, Statement statement, Type planType, List<Expression> parameters) { DataDefinitionTask<?> task = dataDefinitionTask.get(statement.getClass()); if (task != null) { // todo format as graphviz return explainTask(statement, task, parameters); } switch (planType) { case LOGICAL: Plan plan = getLogicalPlan(session, statement, parameters); return PlanPrinter.graphvizLogicalPlan(plan.getRoot(), plan.getTypes()); case DISTRIBUTED: SubPlan subPlan = getDistributedPlan(session, statement, parameters); return PlanPrinter.graphvizDistributedPlan(subPlan); } throw new IllegalArgumentException("Unhandled plan type: " + planType); } private Plan getLogicalPlan(Session session, Statement statement, List<Expression> parameters) { // analyze statement Analysis analysis = analyze(session, statement, parameters); PlanNodeIdAllocator idAllocator = new PlanNodeIdAllocator(); // plan statement LogicalPlanner logicalPlanner = new LogicalPlanner(session, planOptimizers, idAllocator, metadata, sqlParser); return logicalPlanner.plan(analysis); } private SubPlan getDistributedPlan(Session session, Statement statement, List<Expression> parameters) { Plan plan = getLogicalPlan(session, statement, parameters); return PlanFragmenter.createSubPlans(session, metadata, plan); } }