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.List;
import com.tesora.dve.common.MultiMap;
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.jg.DPart;
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.node.structural.FromTableReference;
import com.tesora.dve.sql.node.structural.JoinedTable;
import com.tesora.dve.sql.node.test.EngineConstant;
import com.tesora.dve.sql.schema.SchemaContext;
import com.tesora.dve.sql.statement.dml.SelectStatement;
import com.tesora.dve.sql.transform.ColumnInstanceCollector;
import com.tesora.dve.sql.util.ListSet;
import com.tesora.dve.sql.util.Pair;
class ExplicitJoinBuffer extends FinalBuffer {
protected PartitionLookup partitionLookup;
protected MultiMap<FromTableReference,JoinedTable> logicalOrder;
public ExplicitJoinBuffer(Buffer prev, PartitionLookup pl) {
super(BufferKind.J, prev,pl);
partitionLookup = pl;
logicalOrder = new MultiMap<FromTableReference,JoinedTable>();
}
@Override
public void adapt(SchemaContext sc, SelectStatement stmt) throws PEException {
P2ProjectionBuffer proj = (P2ProjectionBuffer) getBuffer(BufferKind.P2);
for(FromTableReference ftr : stmt.getTables()) {
if (ftr.getBaseSubquery() != null)
throw new PEException("Failed to handle nested query correctly");
Pair<ExpressionNode,List<JoinedTable>> unrolled = ftr.getUnrolledOrder();
for(int i = 0; i < unrolled.getSecond().size(); i++) {
JoinedTable jt = unrolled.getSecond().get(i);
logicalOrder.put(ftr, jt);
ExpressionNode joinEx = jt.getJoinOn();
JoinBufferEntry jbe = null;
ListSet<DPart> parts = null;
ListSet<ExpressionNode> redistOn = null;
ListSet<ColumnInstance> allColumns = null;
if (joinEx != null) {
partitionLookup.getRestrictionManager().take(joinEx);
allColumns = ColumnInstanceCollector.getColumnInstances(joinEx);
Pair<ListSet<ExpressionNode>, ListSet<ColumnInstance>> argh = buildRedistExprs(sc, joinEx);
ListSet<ExpressionNode> exprs = new ListSet<ExpressionNode>();
redistOn = argh.getFirst();
exprs.addAll(redistOn);
exprs.addAll(argh.getSecond());
ListSet<TableKey> tabs = ColumnInstanceCollector.getTableKeys(allColumns);
parts = partitionLookup.getPartitionsFor(tabs);
jbe = new JoinBufferEntry(joinEx,ftr,jt, tabs, exprs);
} else {
// one of those joins with a regular where clause - in this case we're going to look
// at whatever the lhs is.
ListSet<TableKey> tabs = new ListSet<TableKey>();
tabs.add(ftr.getBaseTable().getTableKey());
tabs.add(jt.getJoinedToTable().getTableKey());
parts = partitionLookup.getPartitionsFor(tabs);
jbe = new JoinBufferEntry(null,ftr,jt,tabs,null);
}
if (parts.size() > 1 && redistOn != null) {
// bridging. add one entry for each column used in the expression; then do the compound entries
for(ColumnInstance ci : allColumns) {
BufferEntry nbe = proj.addForJoin(ci,false);
jbe.addDependency(nbe);
}
for(ExpressionNode en : redistOn) {
if (en instanceof ColumnInstance) continue;
ListSet<DPart> eparts = null;
ListSet<ColumnInstance> cols = ColumnInstanceCollector.getColumnInstances(en);
ListSet<TableKey> tabs = ColumnInstanceCollector.getTableKeys(cols);
eparts = partitionLookup.getPartitionsFor(tabs);
BufferEntry nbe = proj.addForJoin(en, true);
jbe.addDependency(nbe);
jbe.registerCompoundRedist(en, (RedistBufferEntry) nbe);
nbe.registerCompoundRedist(en, (RedistBufferEntry) nbe);
proj.partitionInfo.add(nbe,eparts);
}
}
partitionInfo.add(jbe, parts);
add(jbe);
}
}
}
public ListSet<JoinBufferEntry> getJoinEntriesFor(DPart p) {
ListSet<JoinBufferEntry> out = new ListSet<JoinBufferEntry>();
for(BufferEntry be : getEntries()) {
JoinBufferEntry jbe = (JoinBufferEntry) be;
if (partitionInfo.isOfPartition(jbe, p))
out.add(jbe);
}
return out;
}
@Override
public void setBridging(ListSet<BufferEntry> set) throws PEException {
// no sense scoring
bridging = set;
scoredBridges = new ListSet<BufferEntry>(bridging);
}
public MultiMap<FromTableReference,JoinedTable> getLogicalOrder() {
return logicalOrder;
}
private Pair<ListSet<ExpressionNode>, ListSet<ColumnInstance>> buildRedistExprs(SchemaContext sc, ExpressionNode joinEx) {
List<ExpressionNode> decomp = ExpressionUtils.decomposeAndClause(joinEx);
ListSet<ExpressionNode> out = new ListSet<ExpressionNode>();
ListSet<ExpressionNode> nonEJ = new ListSet<ExpressionNode>();
for(ExpressionNode en : decomp) {
ListSet<FunctionCall> eqjs = EngineConstant.EQUIJOINS.getValue(en, sc);
if (eqjs.isEmpty()) {
nonEJ.add(en);
continue;
}
for(FunctionCall fc : eqjs) {
ListSet<TableKey> tabKeys = ColumnInstanceCollector.getTableKeys(fc);
if (tabKeys.size() < 2) {
// not a join
nonEJ.add(fc);
continue;
}
out.addAll(fc.getParameters());
}
}
return new Pair<ListSet<ExpressionNode>, ListSet<ColumnInstance>>(out,ColumnInstanceCollector.getColumnInstances(nonEJ));
}
}