package com.tesora.dve.sql.transform.behaviors.defaults;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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/>.
* #L%
*/
import java.util.List;
import com.tesora.dve.sql.ParserException.Pass;
import com.tesora.dve.sql.SchemaException;
import com.tesora.dve.sql.expression.TableKey;
import com.tesora.dve.sql.node.expression.ExpressionNode;
import com.tesora.dve.sql.node.expression.FunctionCall;
import com.tesora.dve.sql.node.expression.TableInstance;
import com.tesora.dve.sql.node.test.EngineConstant;
import com.tesora.dve.sql.schema.Database;
import com.tesora.dve.sql.schema.DistributionKey;
import com.tesora.dve.sql.schema.DistributionVector;
import com.tesora.dve.sql.schema.PEStorageGroup;
import com.tesora.dve.sql.schema.SchemaContext;
import com.tesora.dve.sql.statement.dml.DMLStatement;
import com.tesora.dve.sql.statement.dml.DeleteStatement;
import com.tesora.dve.sql.statement.dml.InsertIntoSelectStatement;
import com.tesora.dve.sql.statement.dml.ProjectingStatement;
import com.tesora.dve.sql.statement.dml.UpdateStatement;
import com.tesora.dve.sql.transform.ColumnInstanceCollector;
import com.tesora.dve.sql.transform.behaviors.FeatureStepBuilder;
import com.tesora.dve.sql.transform.execution.DMLExplainRecord;
import com.tesora.dve.sql.transform.strategy.ExecutionCost;
import com.tesora.dve.sql.transform.strategy.PlannerContext;
import com.tesora.dve.sql.transform.strategy.featureplan.DeleteFeatureStep;
import com.tesora.dve.sql.transform.strategy.featureplan.FeaturePlanner;
import com.tesora.dve.sql.transform.strategy.featureplan.FeatureStep;
import com.tesora.dve.sql.transform.strategy.featureplan.ProjectingFeatureStep;
import com.tesora.dve.sql.transform.strategy.featureplan.UpdateFeatureStep;
import com.tesora.dve.sql.util.ListSet;
public class DefaultFeatureStepBuilder implements FeatureStepBuilder {
public static final FeatureStepBuilder INSTANCE = new DefaultFeatureStepBuilder();
@Override
public FeatureStep buildStep(PlannerContext pc, FeaturePlanner planner,
DMLStatement ds, DistributionKey distKey,
DMLExplainRecord explain) {
if (ds instanceof ProjectingStatement)
invalid(pc.getContext(),"buildStep",ds,"use buildProjectingStep instead");
if (ds instanceof DeleteStatement) {
DeleteStatement del = (DeleteStatement) ds;
List<TableInstance> tabs = del.getTargetDeletes();
if (tabs.size() > 1)
invalid(pc.getContext(),"buildStep",ds,"found multiple (" + tabs.size() + ") delete tables");
DeleteFeatureStep dfs = new DeleteFeatureStep(planner, del,tabs.get(0).getTableKey(),
tabs.get(0).getAbstractTable().getStorageGroup(pc.getContext()), distKey);
if (explain != null)
dfs.withExplain(explain);
return dfs;
} else if (ds instanceof UpdateStatement) {
UpdateStatement us = (UpdateStatement) ds;
ListSet<TableKey> tabs = new ListSet<TableKey>();
for(ExpressionNode en : us.getUpdateExpressionsEdge()) {
FunctionCall fc = (FunctionCall) en;
tabs.addAll(ColumnInstanceCollector.getTableKeys(fc.getParametersEdge().get(0)));
}
TableKey tk = ensureColocation(pc.getContext(), tabs);
if (tk == null)
invalid(pc.getContext(),"buildStep",ds,"found multiple (" + tabs.size() + ") update tables");
UpdateFeatureStep ufs = new UpdateFeatureStep(planner, us, tk,
tk.getAbstractTable().getStorageGroup(pc.getContext()), distKey);
if (explain != null)
ufs.withExplain(explain);
return ufs;
} else if (ds instanceof InsertIntoSelectStatement) {
InsertIntoSelectStatement iiss = (InsertIntoSelectStatement) ds;
UpdateFeatureStep ufs = new UpdateFeatureStep(planner, iiss, iiss.getTableInstance().getTableKey(),
iiss.getTableInstance().getAbstractTable().getStorageGroup(pc.getContext()), distKey);
if (explain != null)
ufs.withExplain(explain);
return ufs;
} else {
invalid(pc.getContext(),"buildStep",ds,"unhandled");
return null;
}
}
private TableKey ensureColocation(SchemaContext sc, ListSet<TableKey> tabs) {
if (tabs.size() == 1)
return tabs.get(0);
for(TableKey tk : tabs) {
if (!tk.getAbstractTable().getDistributionVector(sc).isBroadcast())
return null;
}
return tabs.get(0);
}
@Override
public ProjectingFeatureStep buildProjectingStep(
PlannerContext pc,
FeaturePlanner planner,
ProjectingStatement statement, ExecutionCost cost,
PEStorageGroup group, Database<?> db, DistributionVector vector,
DistributionKey distKey,
DMLExplainRecord explain) {
if (vector == null)
vector = EngineConstant.BROADEST_DISTRIBUTION_VECTOR.getValue(statement, pc.getContext());
ProjectingFeatureStep pfs = new ProjectingFeatureStep(pc, planner, statement, cost, group, distKey,
db, vector);
if (explain != null)
pfs.withExplain(explain);
return pfs;
}
private void invalid(SchemaContext sc, String method, DMLStatement statement, String reason) {
StringBuilder buf = new StringBuilder();
buf.append("Invalid ")
.append(getClass().getSimpleName()).append(".").append(method)
.append(" call: ").append(reason).append(", stmt='");
buf.append(statement.getSQL(sc, "")).append("'");
throw new SchemaException(Pass.PLANNER, buf.toString());
}
}