/**
* diqube: Distributed Query Base.
*
* Copyright (C) 2015 Bastian Gloeckle
*
* This file is part of diqube.
*
* diqube is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diqube.plan;
import java.util.Map;
import org.diqube.diql.DiqlParseUtil;
import org.diqube.diql.ParseException;
import org.diqube.diql.antlr.DiqlParser.DiqlStmtContext;
import org.diqube.diql.request.ExecutionRequest;
import org.diqube.diql.visitors.SelectStmtVisitor;
import org.diqube.execution.ExecutablePlan;
import org.diqube.execution.ExecutablePlanStep;
import org.diqube.execution.RemotesTriggeredListener;
import org.diqube.execution.consumers.ColumnValueConsumer;
import org.diqube.execution.consumers.OrderedRowIdConsumer;
import org.diqube.execution.consumers.OverwritingRowIdConsumer;
import org.diqube.execution.steps.ExecuteRemotePlanOnShardsStep;
import org.diqube.execution.steps.FilterRequestedColumnsAndActiveRowIdsStep;
import org.diqube.execution.steps.HavingResultStep;
import org.diqube.execution.steps.OrderStep;
import org.diqube.executionenv.ExecutionEnvironment;
import org.diqube.executionenv.ExecutionEnvironmentFactory;
import org.diqube.name.FunctionBasedColumnNameBuilderFactory;
import org.diqube.name.RepeatedColumnNameGenerator;
import org.diqube.optimize.ExecutionRequestOptimizer;
import org.diqube.plan.exception.ValidationException;
import org.diqube.plan.validate.DefaultExecutionRequestValidator;
import org.diqube.plan.validate.ExecutionRequestValidator;
/**
* Build an {@link ExecutablePlan} from diql.
*
* @author Bastian Gloeckle
*/
public class ExecutionPlanBuilder {
private String diql;
private ExecutionPlannerFactory executionPlannerFactory;
private ColumnValueConsumer finalColumnValueConsumer;
private OrderedRowIdConsumer finalOrderedRowIdConsumer;
private ExecutionEnvironmentFactory executionEnvironmentFactory;
private OverwritingRowIdConsumer havingResultsConsumer;
private RepeatedColumnNameGenerator repeatedColNames;
private FunctionBasedColumnNameBuilderFactory functionBasedColumnNameBuilderFactory;
private RemotesTriggeredListener remotesTriggeredListener;
private ExecutionRequestValidator additionalValidator;
public ExecutionPlanBuilder(ExecutionPlannerFactory executionPlannerFactory,
ExecutionEnvironmentFactory executionEnvironmentFactory, RepeatedColumnNameGenerator repeatedColNames,
FunctionBasedColumnNameBuilderFactory functionBasedColumnNameBuilderFactory) {
this.executionPlannerFactory = executionPlannerFactory;
this.executionEnvironmentFactory = executionEnvironmentFactory;
this.repeatedColNames = repeatedColNames;
this.functionBasedColumnNameBuilderFactory = functionBasedColumnNameBuilderFactory;
}
public ExecutionPlanBuilder fromDiql(String diql) {
this.diql = diql;
return this;
}
public ExecutionPlanBuilder withFinalColumnValueConsumer(ColumnValueConsumer finalColumnValueConsumer) {
this.finalColumnValueConsumer = finalColumnValueConsumer;
return this;
}
public ExecutionPlanBuilder withFinalOrderedRowIdConsumer(OrderedRowIdConsumer finalOrderedRowIdConsumer) {
this.finalOrderedRowIdConsumer = finalOrderedRowIdConsumer;
return this;
}
public ExecutionPlanBuilder withHavingResultConsumer(OverwritingRowIdConsumer havingResultsConsumer) {
this.havingResultsConsumer = havingResultsConsumer;
return this;
}
public ExecutionPlanBuilder withRemotesTriggeredListener(RemotesTriggeredListener remotesTriggeredListener) {
this.remotesTriggeredListener = remotesTriggeredListener;
return this;
}
public ExecutionPlanBuilder withAdditionalRequestValidator(ExecutionRequestValidator additionalValidator) {
this.additionalValidator = additionalValidator;
return this;
}
/**
* @return An {@link ExecutablePlan} that is executable on the query master right away.
*/
public ExecutablePlan build() throws ParseException, ValidationException {
DiqlStmtContext sqlStmt = DiqlParseUtil.parseWithAntlr(diql);
ExecutionRequest executionRequest =
sqlStmt.accept(new SelectStmtVisitor(repeatedColNames, functionBasedColumnNameBuilderFactory));
executionRequest = new ExecutionRequestOptimizer(executionRequest).optimize();
Map<String, PlannerColumnInfo> colInfo =
new PlannerColumnInfoBuilder().withExecutionRequest(executionRequest).build();
new DefaultExecutionRequestValidator().validate(executionRequest, colInfo);
if (additionalValidator != null)
additionalValidator.validate(executionRequest, colInfo);
ExecutionEnvironment queryMasterDefaultExecutionEnvironment =
executionEnvironmentFactory.createQueryMasterExecutionEnvironment();
ExecutablePlan plan = executionPlannerFactory.createExecutionPlanner().plan(executionRequest, colInfo,
queryMasterDefaultExecutionEnvironment);
// wire manual consumers
for (ExecutablePlanStep step : plan.getSteps()) {
if (finalColumnValueConsumer != null && (step instanceof FilterRequestedColumnsAndActiveRowIdsStep))
step.addOutputConsumer(finalColumnValueConsumer);
if (finalOrderedRowIdConsumer != null && (step instanceof OrderStep))
step.addOutputConsumer(finalOrderedRowIdConsumer);
if (havingResultsConsumer != null && (step instanceof HavingResultStep))
step.addOutputConsumer(havingResultsConsumer);
if (remotesTriggeredListener != null && (step instanceof ExecuteRemotePlanOnShardsStep))
((ExecuteRemotePlanOnShardsStep) step).addRemotesTriggeredListener(remotesTriggeredListener);
}
return plan;
}
public ColumnValueConsumer getFinalColumnValueConsumer() {
return finalColumnValueConsumer;
}
public OrderedRowIdConsumer getFinalOrderedRowIdConsumer() {
return finalOrderedRowIdConsumer;
}
}