package com.tesora.dve.sql.transform.strategy;
/*
* #%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.Collections;
import java.util.List;
import com.tesora.dve.exceptions.PEException;
import com.tesora.dve.sql.expression.ExpressionPath;
import com.tesora.dve.sql.expression.TableKey;
import com.tesora.dve.sql.schema.DistributionVector.Model;
import com.tesora.dve.sql.schema.PEStorageGroup;
import com.tesora.dve.sql.schema.SchemaContext;
import com.tesora.dve.sql.schema.TempTableCreateOptions;
import com.tesora.dve.sql.statement.dml.DMLStatement;
import com.tesora.dve.sql.statement.dml.DeleteStatement;
import com.tesora.dve.sql.statement.dml.ProjectingStatement;
import com.tesora.dve.sql.statement.dml.SelectStatement;
import com.tesora.dve.sql.statement.dml.UpdateStatement;
import com.tesora.dve.sql.transform.CopyVisitor;
import com.tesora.dve.sql.transform.behaviors.ComplexFeaturePlannerFilter;
import com.tesora.dve.sql.transform.behaviors.defaults.DefaultFeaturePlannerFilter;
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.RedistFeatureStep;
import com.tesora.dve.sql.util.ListOfPairs;
import com.tesora.dve.sql.util.ListSet;
import com.tesora.dve.sql.util.Pair;
/**
* This transformation colocates all subqueries on a single group.
*/
public class NestedQueryBroadcastTransformFactory extends TransformFactory {
/**
* Check if the parent statement has all tables (including nested) broadcast
* on the it's storage group.
*/
protected static boolean hasAllNestedCollocated(final SchemaContext sc, final DMLStatement parent) {
final ListSet<ProjectingStatement> nestedQueries = parent.getDerivedInfo().getLocalNestedQueries();
if (nestedQueries.isEmpty()) {
return true;
}
final List<PEStorageGroup> storageGroups = parent.getStorageGroups(sc);
if (storageGroups.size() != 1) {
return false;
}
return hasAllTablesBroadcast(sc, parent);
}
private static boolean hasAllTablesBroadcast(final SchemaContext sc, final DMLStatement stmt) {
final List<TableKey> localTables = stmt.getDerivedInfo().getLocalTableKeys();
for (final TableKey table : stmt.getDerivedInfo().getAllTableKeys()) {
if (!localTables.contains(table) && !table.getAbstractTable().getDistributionVector(sc).isBroadcast()) {
return false;
}
}
return true;
}
private static boolean applies(SchemaContext sc, DMLStatement stmt) throws PEException {
if ((stmt instanceof UpdateStatement) || (stmt instanceof DeleteStatement)) {
return !hasAllNestedCollocated(sc, stmt);
}
return false;
}
@Override
public FeaturePlannerIdentifier getFeaturePlannerID() {
return FeaturePlannerIdentifier.NESTED_QUERY_BROADCAST;
}
@Override
public FeatureStep plan(DMLStatement stmt, PlannerContext ipc)
throws PEException {
if (!applies(ipc.getContext(),stmt))
return null;
PlannerContext context = ipc.withTransform(getFeaturePlannerID());
final DMLStatement stmtCopy = CopyVisitor.copy(stmt);
final PEStorageGroup targetGroup = stmtCopy.getBaseTables().get(0).getAbstractTable().getStorageGroup(context.getContext());
final ListSet<ProjectingStatement> nestedQueries = new ListSet<ProjectingStatement>(stmtCopy.getDerivedInfo().getLocalNestedQueries());
ListOfPairs<ProjectingStatement, FeatureStep> subs = new ListOfPairs<ProjectingStatement,FeatureStep>();
for (final ProjectingStatement nested : nestedQueries) {
FeatureStep childStep = buildPlan(nested, context, DefaultFeaturePlannerFilter.INSTANCE);
subs.add(nested,childStep);
}
ListSet<FeatureStep> deps = new ListSet<FeatureStep>();
for(Pair<ProjectingStatement,FeatureStep> planned : subs) {
ProjectingFeatureStep pfs = (ProjectingFeatureStep) planned.getSecond();
RedistFeatureStep rfs =
pfs.redist(context, this,
new TempTableCreateOptions(Model.BROADCAST, targetGroup),
null,
null);
SelectStatement ss = rfs.buildNewSelect(context);
ExpressionPath replacer = ExpressionPath.build(planned.getFirst(), stmtCopy);
replacer.update(stmtCopy, ss);
stmtCopy.getDerivedInfo().getLocalNestedQueries().remove(planned.getFirst());
stmtCopy.getDerivedInfo().addNestedStatements(Collections.singletonList((ProjectingStatement)ss));
stmtCopy.getBlock().clear();
deps.add(rfs);
}
FeatureStep out = buildPlan(stmtCopy, context,
new ComplexFeaturePlannerFilter(Collections.singleton(getFeaturePlannerID()), Collections.<FeaturePlannerIdentifier> emptySet()));
out.prefixChildren(deps);
return out;
}
}