package com.tesora.dve.sql.transform.execution; /* * #%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.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import com.tesora.dve.db.Emitter.EmitOptions; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.queryplan.QueryStepOperation; import com.tesora.dve.resultset.ProjectionInfo; import com.tesora.dve.resultset.ResultRow; import com.tesora.dve.sql.schema.ConnectionValues; import com.tesora.dve.sql.schema.ExplainOptions; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.schema.ValueManager; import com.tesora.dve.sql.schema.cache.CacheInvalidationRecord; import com.tesora.dve.sql.transform.strategy.PlannerContext; import com.tesora.dve.sql.transform.strategy.featureplan.FeatureStep; import com.tesora.dve.sql.util.Functional; import com.tesora.dve.sql.util.UnaryFunction; import com.tesora.dve.sql.util.UnaryPredicate; import com.tesora.dve.sql.util.UnaryProcedure; public class ExecutionSequence extends ExecutionStep { protected LinkedList<HasPlanning> steps; //NOPMD // backward links, good for getting to the plan during construction protected ExecutionPlan plan; public ExecutionSequence(ExecutionPlan p) { super(null,null,ExecutionType.SEQUENCE); steps = new LinkedList<HasPlanning>(); plan = p; } public static HasPlanning buildSubSequence(PlannerContext pc, FeatureStep step, ExecutionPlan parentPlan) throws PEException { final ExecutionSequence sub = new ExecutionSequence(parentPlan); step.schedule(pc, sub, new HashSet<FeatureStep>()); if (sub.getSteps().size() == 1) return sub.getSteps().get(0); return sub; } public void append(HasPlanning es) { if (es == null) return; steps.add(es); } public ExecutionPlan getPlan() { return plan; } protected String sequenceName() { return "SEQUENCE"; } @Override public void display(final SchemaContext sc, final ConnectionValuesMap cv, final ExecutionPlan containing, final List<String> sb, String indent, final EmitOptions opts) { if (steps.isEmpty()) return; sb.add(indent + sequenceName() + " {"); final String subindent = indent + " "; apply(true,new UnaryProcedure<HasPlanning>() { @Override public void execute(HasPlanning object) { object.display(sc, cv, containing, sb, subindent, opts); } }); sb.add(indent + "}"); } @Override public void explain(final SchemaContext sc, final ConnectionValuesMap cv, final ExecutionPlan containing, final List<ResultRow> rows, final ExplainOptions opts) { if (steps.isEmpty()) return; apply(true,new UnaryProcedure<HasPlanning>() { @Override public void execute(HasPlanning object) { object.explain(sc, cv, containing, rows, opts); } }); } public List<HasPlanning> getSteps() { return steps; } public void setSteps(List<HasPlanning> other) { steps.addAll(other); } public HasPlanning getLastStep() { if (steps.isEmpty()) return null; return steps.getLast(); } @Override public Long getlastInsertId(final ValueManager vm, final SchemaContext sc, final ConnectionValues cv) { return getLastExisting(new UnaryFunction<Long, HasPlanning>() { @Override public Long evaluate(HasPlanning object) { return object.getlastInsertId(vm,sc, cv); } }); } @Override public Long getUpdateCount(final SchemaContext sc, final ConnectionValues cv) { final Long[] summed = new Long[1]; apply(true, new UnaryProcedure<HasPlanning>() { @Override public void execute(HasPlanning object) { Long uc = object.getUpdateCount(sc,cv); if (uc != null) { if (summed[0] == null) summed[0] = uc; else summed[0] = new Long(summed[0].longValue() + uc.longValue()); } } }); return summed[0]; } @Override public boolean useRowCount() { return any(new UnaryPredicate<HasPlanning>() { @Override public boolean test(HasPlanning object) { return object.useRowCount(); } }); } public void apply(boolean ascending, UnaryProcedure<HasPlanning> f) { if (steps.isEmpty()) return; for(Iterator<HasPlanning> iter = (ascending ? steps.iterator() : steps.descendingIterator()); iter.hasNext();) { f.execute(iter.next()); } } public boolean any(UnaryPredicate<HasPlanning> f) { if (steps.isEmpty()) return false; return Functional.any(steps, f); } public <T> T getLastExisting(UnaryFunction<T, HasPlanning> f) { if (steps.isEmpty()) return null; for(Iterator<HasPlanning> iter = steps.descendingIterator(); iter.hasNext();) { T any = f.evaluate(iter.next()); if (any != null) return any; } return null; } @Override public void prepareForCache() { apply(true, new UnaryProcedure<HasPlanning>() { @Override public void execute(HasPlanning object) { object.prepareForCache(); } }); } @Override public void schedule(ExecutionPlanOptions opts, List<QueryStepOperation> qsteps, ProjectionInfo projection, SchemaContext sc, ConnectionValuesMap cv, ExecutionPlan containingPlan) throws PEException { if (steps.isEmpty()) return; for(HasPlanning hp : steps) hp.schedule(opts, qsteps, projection, sc, cv, containingPlan); } @Override public ExecutionType getExecutionType() { return null; } public int getRedistributionStepCount(final SchemaContext sc) { final AtomicLong counter = new AtomicLong(0); this.analyze(new UnaryProcedure<DirectExecutionStep>() { @Override public void execute(final DirectExecutionStep object) { if (object instanceof RedistributionExecutionStep) { counter.incrementAndGet(); } } }); return counter.intValue(); } public void analyze(UnaryProcedure<DirectExecutionStep> f) { if (steps.isEmpty()) return; for(HasPlanning hp : steps) { if (hp instanceof DirectExecutionStep) { f.execute((DirectExecutionStep)hp); } else if (hp instanceof ParallelExecutionStep) { ((ParallelExecutionStep)hp).analyze(f); } } } @Override public CacheInvalidationRecord getCacheInvalidation(SchemaContext sc) { for(HasPlanning hp : steps) { CacheInvalidationRecord any = hp.getCacheInvalidation(sc); if (any != null) return any; } return null; } @Override public void visitInExecutionOrder(UnaryProcedure<HasPlanning> proc) { if (steps.isEmpty()) return; for(HasPlanning hp : steps) hp.visitInExecutionOrder(proc); } @Override public void visitInTestVerificationOrder(UnaryProcedure<HasPlanning> proc) { if (steps.isEmpty()) return; for(HasPlanning hp : steps) hp.visitInTestVerificationOrder(proc); } }