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.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.TreeMap; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.sql.ParserException.Pass; import com.tesora.dve.sql.SchemaException; import com.tesora.dve.sql.expression.ExpressionUtils; import com.tesora.dve.sql.expression.RewriteKey; import com.tesora.dve.sql.expression.TableKey; import com.tesora.dve.sql.jg.DPart; import com.tesora.dve.sql.node.Edge; 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.expression.LiteralExpression; import com.tesora.dve.sql.schema.DistributionVector; import com.tesora.dve.sql.schema.FunctionName; import com.tesora.dve.sql.schema.PEAbstractTable; import com.tesora.dve.sql.schema.PEColumn; import com.tesora.dve.sql.schema.PEStorageGroup; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.statement.dml.SelectStatement; import com.tesora.dve.sql.transform.execution.DMLExplainRecord; import com.tesora.dve.sql.transform.strategy.ExecutionCost; import com.tesora.dve.sql.transform.strategy.featureplan.FeatureStep; import com.tesora.dve.sql.transform.strategy.featureplan.ProjectingFeatureStep; import com.tesora.dve.sql.util.Functional; import com.tesora.dve.sql.util.ListSet; import com.tesora.dve.sql.util.UnaryFunction; abstract class PartitionEntry { protected ExecutionCost score = null; protected Set<TableKey> tables = null; protected Set<DPart> partitions = null; protected SelectStatement basis; protected PEStorageGroup sourceGroup = null; protected Set<DistributionVector> distributedOn = null; // not always a projecting step - could be a redist step (temporarily) protected FeatureStep step = null; // these are the joins that this entry protected ListSet<JoinEntry> referencingJoins = new ListSet<JoinEntry>(); // and these are the entries which are built upon this entry - valid for everything except partition entries protected ListSet<PartitionEntry> referencingEntries = new ListSet<PartitionEntry>(); // once this partition entry has actually been scheduled, this will point to the ipe that // contains it protected PartitionEntry scheduled; protected DMLExplainRecord explain; protected final SchemaContext sc; protected final long id; public PartitionEntry(SchemaContext sc, SelectStatement orig, DMLExplainRecord expl) { basis = orig; this.sc = sc; this.id = sc.getNextObjectID(); this.explain = expl; } public SelectStatement getBasis() { return basis; } public SchemaContext getSchemaContext() { return sc; } public ExecutionCost getScore() throws PEException { if (score == null) { if (scheduled != null) score = scheduled.getScore(); else score = computeScore(); } return score; } protected void clearScore() { score = null; // when my score is cleared any joins that reference this should get a new score for(JoinEntry je : referencingJoins) je.clearScore(); } protected void setScore(ExecutionCost given) { if (score != null && given == null) return; score = given; } protected abstract ExecutionCost computeScore() throws PEException; protected abstract Set<TableKey> computeTables(); public Set<TableKey> getSpanningTables() { if (tables == null) tables = computeTables(); return tables; } public boolean containsTable(TableKey tk) { return getSpanningTables().contains(tk); } protected abstract Set<DPart> computePartitions(); public Set<DPart> getPartitions() { if (partitions == null) partitions = computePartitions(); return partitions; } protected abstract PEStorageGroup computeSourceGroup(); public PEStorageGroup getSourceGroup() { if (sourceGroup == null) sourceGroup = computeSourceGroup(); return sourceGroup; } protected abstract Set<DistributionVector> computeDistributedOn(); public Set<DistributionVector> getDistributedOn() { if (distributedOn == null) distributedOn = computeDistributedOn(); return distributedOn; } public abstract List<ExpressionNode> getProjection() throws PEException; public abstract SelectStatement getJoinQuery(RewriteBuffers buffers) throws PEException; public abstract List<ExpressionNode> mapDistributedOn(List<ExpressionNode> in) throws PEException; // debugging help public abstract SelectStatement getCurrentExecQuery(); public List<ColumnInstance> mapDistributionVectorColumns(List<PEColumn> in) throws PEException { ArrayList<ColumnInstance> out = new ArrayList<ColumnInstance>(); if (in.isEmpty()) return out; PEAbstractTable<?> ofTable = in.get(0).getTable(); TableKey tk = null; for(TableKey i : getSpanningTables()) { if (i.getTable().equals(ofTable)) { tk = i; break; } } for(PEColumn c : in) { out.add(new ColumnInstance(c,tk.toInstance())); } return out; } public List<Integer> mapDistributedOn(List<ExpressionNode> in, SelectStatement projSource) throws PEException { List<RewriteKey> ascols = Functional.apply(in, new UnaryFunction<RewriteKey,ExpressionNode>() { @Override public RewriteKey evaluate(ExpressionNode object) { return object.getRewriteKey(); } }); return getDistVectOffsets(ascols, projSource); } public List<Integer> getDistVectOffsets(List<RewriteKey> distVectColumns, SelectStatement ss) throws PEException { ArrayList<Integer> out = new ArrayList<Integer>(); if (distVectColumns.isEmpty()) return out; HashMap<RewriteKey,Integer> dvectoff = new HashMap<RewriteKey,Integer>(); for(int i = 0; i < distVectColumns.size(); i++) dvectoff.put(distVectColumns.get(i), i); TreeMap<Integer, Integer> results = new TreeMap<Integer,Integer>(); for(int i = 0; i < ss.getProjectionEdge().size(); i++) { ExpressionNode en = ExpressionUtils.getTarget(ss.getProjectionEdge().get(i)); RewriteKey rk = en.getRewriteKey(); Integer any = dvectoff.get(rk); if (any != null) results.put(any,i); } return Functional.toList(results.values()); } public abstract SelectStatement getTempTableSource() throws PEException; public abstract List<BufferEntry> getBufferEntries(); public List<Integer> getInvisibleColumns() { ArrayList<Integer> out = new ArrayList<Integer>(); List<BufferEntry> entries = getBufferEntries(); for(int i = 0; i < entries.size(); i++) { if (entries.get(i).isInvisible()) out.add(i); } return out; } protected abstract String describe() throws PEException; @Override public final String toString() { return getClass().getSimpleName() + "@" + id; } public void maybeForceDoublePrecision(ProjectingFeatureStep pfs) { List<BufferEntry> bufferEntries = getBufferEntries(); SelectStatement in = (SelectStatement) pfs.getPlannedStatement(); for(int i = 0; i < bufferEntries.size(); i++) { BufferEntry be = bufferEntries.get(i); if (!be.isInvisible()) continue; ExpressionNode t = ExpressionUtils.getTarget(in.getProjectionEdge().get(i)); Edge<?, ExpressionNode> parentEdge = t.getParentEdge(); FunctionCall fc = new FunctionCall(FunctionName.makeMult(), t, LiteralExpression.makeDoubleLiteral(1.0D)); parentEdge.set(fc); } } protected void sane(String reason, int nbuffers, int nproj, SelectStatement ss) { if (nbuffers != nproj) throw new SchemaException(Pass.REWRITER,"Internal error at " + reason + "; found " + nbuffers + " but expected " + nproj + " on join kern " + ss.getSQL(sc)); } public void addReferencingJoin(JoinEntry je) { referencingJoins.add(je); } public void addReferencingEntry(PartitionEntry jre) { referencingEntries.add(jre); } public void setPlanned(PartitionEntry owner) { boolean notify = (scheduled != owner); scheduled = owner; if (notify) clearScore(); } public PartitionEntry getActualEntry() { return this; } public void setExplain(DMLExplainRecord rec) { explain = rec; } public DMLExplainRecord getExplain() { return explain; } public void setStep(FeatureStep psf) { step = psf; } public FeatureStep getStep(RewriteBuffers projInfo) throws PEException { return step; } }