package com.tesora.dve.sql.transform.strategy.join;
/*
* #%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.Iterator;
import java.util.List;
import java.util.Set;
import com.tesora.dve.exceptions.PEException;
import com.tesora.dve.sql.expression.ExpressionUtils;
import com.tesora.dve.sql.expression.TableKey;
import com.tesora.dve.sql.node.expression.ColumnInstance;
import com.tesora.dve.sql.node.expression.ExpressionNode;
import com.tesora.dve.sql.node.expression.FunctionCall;
import com.tesora.dve.sql.schema.PEStorageGroup;
import com.tesora.dve.sql.schema.DistributionVector.Model;
import com.tesora.dve.sql.schema.TempTableCreateOptions;
import com.tesora.dve.sql.statement.dml.DMLStatementUtils;
import com.tesora.dve.sql.statement.dml.SelectStatement;
import com.tesora.dve.sql.transform.behaviors.defaults.DefaultFeatureStepBuilder;
import com.tesora.dve.sql.transform.execution.DMLExplainReason;
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.ProjectingFeatureStep;
import com.tesora.dve.sql.transform.strategy.featureplan.RedistFeatureStep;
/*
* We started out with A loj B, where A is broadcast distributed and B is not.
* We execute this as:
* [1] A ij B redist to a single site on the persistent group
* [2] On that single site, execute A loj T1
*/
public class BCastToPGOuterJoinStrategy extends JoinStrategy {
public BCastToPGOuterJoinStrategy(PlannerContext pc, JoinEntry p,
StrategyTable leftTable,
StrategyTable rightTable,
DMLExplainRecord rec) {
super(pc, p, leftTable, rightTable, rec);
}
@Override
public JoinedPartitionEntry build() throws PEException {
ExecutionCost combinedCost = BinaryJoinEntry.combineScores(getSchemaContext(),
left.getEntry().getScore(),
right.getEntry().getScore(),
rje.getJoin());
combinedCost.setSingleSite();
ProjectingFeatureStep leftStep = (ProjectingFeatureStep) left.getEntry().getStep(null);
ProjectingFeatureStep rightStep = (ProjectingFeatureStep) right.getEntry().getStep(null);
SelectStatement lhs = (SelectStatement) leftStep.getPlannedStatement();
SelectStatement rhs = (SelectStatement) rightStep.getPlannedStatement();
PEStorageGroup targGroup = null;
boolean isLeftJoin = getJoin().getJoinType().isLeftOuterJoin();
if (isLeftJoin) {
right.getEntry().maybeForceDoublePrecision(rightStep);
targGroup = left.getGroup();
} else {
left.getEntry().maybeForceDoublePrecision(leftStep);
targGroup = right.getGroup();
}
SelectStatement actualJoinStatement = DMLStatementUtils.compose(getSchemaContext(),rhs,lhs);
UniquedExpressionList uel = new UniquedExpressionList();
uel.addAll(ExpressionUtils.decomposeAndClause(actualJoinStatement.getWhereClause()));
// we will always have the original join entry for this strategy -
uel.addAll(ExpressionUtils.decomposeAndClause((FunctionCall) actualJoinStatement.getMapper().copyForward(getJoin().getJoin().getJoinOn())));
List<ExpressionNode> ands = uel.getExprs();
// now that the join condition is mapped - we need to get rid of everything from the bcast table in the projection -
// we're going to pick it up later on when we do the actual join.
PartitionEntry keepEntry = (isLeftJoin ? right.getEntry() : left.getEntry());
Set<TableKey> keepTabs = keepEntry.getSpanningTables();
for(Iterator<ExpressionNode> iter = actualJoinStatement.getProjectionEdge().iterator(); iter.hasNext();) {
ExpressionNode en = iter.next();
ExpressionNode target = ExpressionUtils.getTarget(en);
if (target instanceof ColumnInstance) {
ColumnInstance ci = (ColumnInstance)target;
TableKey tk = ci.getTableInstance().getTableKey();
if (!keepTabs.contains(tk))
iter.remove();
}
}
actualJoinStatement.setWhereClause(ExpressionUtils.safeBuildAnd(ands));
actualJoinStatement.normalize(getSchemaContext());
// so - we have the join - it's on the src group - build a new proj feature step for it
ProjectingFeatureStep innerJoin =
DefaultFeatureStepBuilder.INSTANCE.buildProjectingStep(
getPlannerContext(),
rje.getFeaturePlanner(),
actualJoinStatement,
combinedCost,
leftStep.getSourceGroup(),
leftStep.getDatabase(getPlannerContext()),
(isLeftJoin ? rightStep.getDistributionVector() : leftStep.getDistributionVector()),
null,
DMLExplainReason.BCAST_TO_PG_OUTER_JOIN.makeRecord());
// if either side has dependents, they become mine
innerJoin.getSelfChildren().addAll(left.getEntry().getStep(null).getAllChildren());
innerJoin.getSelfChildren().addAll(right.getEntry().getStep(null).getAllChildren());
// now remove the inner table from the mapper - we're going to join against it again in the next step
PartitionEntry puntEntry = (isLeftJoin ? left.getEntry() : right.getEntry());
for(TableKey tk : puntEntry.getSpanningTables())
actualJoinStatement.getMapper().remove(tk);
// now we're going to redist the inner join back onto targ group - we'll use bcast dist
targGroup = targGroup.anySite(getSchemaContext());
RedistFeatureStep redisted =
innerJoin.redist(getPlannerContext(),
rje.getFeaturePlanner(),
new TempTableCreateOptions(Model.BROADCAST,targGroup)
.withRowCount(rje.getScore().getRowCount()),
null,
DMLExplainReason.BCAST_TO_PG_OUTER_JOIN.makeRecord());
if (isLeftJoin) {
lhs = (SelectStatement) leftStep.getPlannedStatement();
rhs = redisted.buildNewSelect(getPlannerContext());
right.getEntry().setStep(redisted);
} else {
lhs = redisted.buildNewSelect(getPlannerContext());
left.getEntry().setStep(redisted);
rhs = (SelectStatement) rightStep.getPlannedStatement();
}
return buildResultEntry(
lhs,
leftStep.getDistributionVector(),
rhs,
rightStep.getDistributionVector(),
combinedCost,
targGroup,
false);
}
}