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.ArrayList; import java.util.List; import com.tesora.dve.common.catalog.PersistentDatabase; import com.tesora.dve.common.catalog.StorageGroup; import com.tesora.dve.common.catalog.UserDatabase; import com.tesora.dve.db.Emitter.EmitOptions; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.queryplan.QueryStepOperation; import com.tesora.dve.resultset.ResultRow; import com.tesora.dve.sql.schema.ConnectionValues; import com.tesora.dve.sql.schema.Database; import com.tesora.dve.sql.schema.ExplainOptions; import com.tesora.dve.sql.schema.PEStorageGroup; 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.util.Functional; import com.tesora.dve.sql.util.UnaryProcedure; public abstract class ExecutionStep implements HasPlanning { protected Database<?> database; protected PEStorageGroup sg; protected ExecutionType type; public ExecutionStep(Database<?> db, PEStorageGroup storageGroup, ExecutionType givenType) { database = db; sg = storageGroup; type = givenType; } public Database<?> getDatabase() { return database; } public PersistentDatabase getPersistentDatabase() { return database; } public UserDatabase getUserDatabase(SchemaContext sc) { if (database == null) return null; return database.getPersistent(sc); } public StorageGroup getStorageGroup(SchemaContext sc, ConnectionValues cv) { if (sg == null) return null; StorageGroup out = sg.getScheduledGroup(sc, cv); return out; } public PEStorageGroup getPEStorageGroup() { return sg; } public void getSQL(SchemaContext sc, ConnectionValuesMap cvm, ExecutionPlan containing, List<String> buf, EmitOptions opts) { } @Override public ExecutionType getExecutionType() { return type; } public ExecutionType getEffectiveExecutionType() { return getExecutionType(); } public String getSQL(SchemaContext sc, ConnectionValuesMap cvm, ExecutionPlan containing, EmitOptions opts) { ArrayList<String> buf = new ArrayList<String>(); getSQL(sc,cvm, containing, buf, opts); return Functional.join(buf,";"); } public void displaySQL(SchemaContext sc, ConnectionValuesMap cvm, ExecutionPlan containing, List<String> buf, String indent, EmitOptions opts) { buf.add(indent + " sql:"); buf.add(getSQL(sc,cvm,containing,opts)); } @Override public void display(SchemaContext sc, ConnectionValuesMap cvm, ExecutionPlan containingPlan, List<String> buf, String indent, EmitOptions opts) { String execType = null; if (getEffectiveExecutionType() != getExecutionType()) { execType = getEffectiveExecutionType().name() + " (" + getExecutionType().name() + ")"; } else { execType = getEffectiveExecutionType().name(); } ConnectionValues cv = cvm.getValues(containingPlan); buf.add(indent + execType + " on " + (getDatabase() == null ? "null" : getDatabase().getName().get()) + "/" + getStorageGroup(sc,cv)); if (opts == null) buf.add(indent + " sql: '" + getSQL(sc,cvm,containingPlan,opts) + "'"); else displaySQL(sc, cvm, containingPlan, buf, indent, opts); } @Override public void explain(SchemaContext sc, ConnectionValuesMap cvm, ExecutionPlan containing, List<ResultRow> rows, ExplainOptions opts) { ResultRow rr = new ResultRow(); ConnectionValues cv = cvm.getValues(containing); addExplainColumns(sc,cv,rr,opts); // add any nulls that are needed int width = RootExecutionPlan.basicExplainColumns.length + (opts.isStatistics() ? StepExecutionStatistics.statsExplainColumns.length : 0); int diff = width - 1 - rr.getRow().size(); for(int i = 0; i < diff; i++) rr.addResultColumn(null,true); rr.addResultColumn(getSQL(sc,cvm,containing,null), false); rows.add(rr); } protected void addStringResult(ResultRow rr, String v) { if (v == null) rr.addResultColumn(null, true); else rr.addResultColumn(v, false); } protected String explainStorageGroup(SchemaContext sc, PEStorageGroup storageGroup, ConnectionValues cv) { if (storageGroup == null) return null; return storageGroup.getPersistent(sc,cv).getName(); } protected String explainStepType() { return getExecutionType().toString(); } protected String explainSourceGroup(SchemaContext sc, ConnectionValues cv) { return explainStorageGroup(sc,getPEStorageGroup(),cv); } protected void addExplainColumns(SchemaContext sc, ConnectionValues cv, ResultRow rr,ExplainOptions opts) { addStringResult(rr, explainStepType()); } @Override public boolean useRowCount() { return false; } @Override public Long getlastInsertId(ValueManager vm, SchemaContext sc, ConnectionValues cv) { return null; } @Override public Long getUpdateCount(SchemaContext sc, ConnectionValues cv) { return null; } @Override public CacheInvalidationRecord getCacheInvalidation(SchemaContext sc) { return null; } @Override public void prepareForCache() { } @Override public void visitInExecutionOrder(UnaryProcedure<HasPlanning> proc) { proc.execute(this); } @Override public void visitInTestVerificationOrder(UnaryProcedure<HasPlanning> proc) { proc.execute(this); } protected QueryStepOperation buildOperation(ExecutionPlanOptions opts, SchemaContext sc, ConnectionValuesMap cvm, ExecutionPlan containing, HasPlanning toSchedule) throws PEException { List<QueryStepOperation> sub = new ArrayList<QueryStepOperation>(); toSchedule.schedule(opts, sub, null, sc, cvm, containing); if (sub.isEmpty()) return null; return ExecutionPlan.collapseOperationList(sub); } }