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.DistributionModel;
import com.tesora.dve.db.GenericSQLCommand;
import com.tesora.dve.db.Emitter.EmitOptions;
import com.tesora.dve.distribution.IKeyValue;
import com.tesora.dve.exceptions.PEException;
import com.tesora.dve.resultset.ResultRow;
import com.tesora.dve.server.messaging.SQLCommand;
import com.tesora.dve.sql.SchemaException;
import com.tesora.dve.sql.TransformException;
import com.tesora.dve.sql.ParserException.Pass;
import com.tesora.dve.sql.expression.TableKey;
import com.tesora.dve.sql.schema.ConnectionValues;
import com.tesora.dve.sql.schema.Database;
import com.tesora.dve.sql.schema.DistributionKey;
import com.tesora.dve.sql.schema.DistributionVector;
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.statement.dml.DMLStatement;
import com.tesora.dve.variables.KnownVariables;
public abstract class DirectExecutionStep extends ExecutionStep {
protected GenericSQLCommand sql;
// null if none (not a key qso)
protected DistributionKey distributionKey;
// effective type for execution steps that are not directly planned
protected ExecutionType effectiveType;
// how the query is distributed
protected DistributionVector distributionVector;
protected boolean requiresReferenceTimestamp = false;
protected final DMLExplainRecord explainHelp;
protected StepExecutionStatistics stats = new StepExecutionStatistics();
public DirectExecutionStep(Database<?> db, PEStorageGroup storageGroup, ExecutionType givenType,
DistributionVector vector, DistributionKey distKey, GenericSQLCommand command,
DMLExplainRecord splain) throws PEException {
this(db, storageGroup, givenType, vector, distKey, command, false, splain);
}
public DirectExecutionStep(Database<?> db, PEStorageGroup storageGroup, ExecutionType givenType,
DistributionVector vector, DistributionKey distKey, GenericSQLCommand command,
boolean requiresReferenceTimestamp,
DMLExplainRecord splain) throws PEException {
super(db, storageGroup, givenType);
sql = command;
distributionKey = distKey;
effectiveType = givenType;
distributionVector = vector;
this.requiresReferenceTimestamp = requiresReferenceTimestamp;
this.explainHelp = splain;
}
// TODO:
// should consider applying multitenant as a post-plan transform
protected static void maybeApplyMultitenant(SchemaContext sc, DMLStatement dmls) throws PEException {
sc.getPolicyContext().applyDegenerateMultitenantFilter(dmls);
}
@Override
public ExecutionType getEffectiveExecutionType() {
return effectiveType;
}
public GenericSQLCommand getRawSQL() {
return sql;
}
public GenericSQLCommand getSQL(SchemaContext sc, ConnectionValues cv, String pretty) {
return sql.resolve(cv, pretty);
}
@Override
public String getSQL(SchemaContext sc, ConnectionValuesMap cvm, ExecutionPlan containing, EmitOptions opts) {
return sql.resolve(cvm.getValues(containing), (opts == null ? null : opts.getMultilinePretty())).getDecoded();
}
public SQLCommand getCommand(SchemaContext sc, ConnectionValues cv) {
GenericSQLCommand gen = getSQL(sc,cv,(String)null);
List<Object> actualParams = sql.getFinalParams(sc);
return new SQLCommand(gen,actualParams);
}
public IKeyValue getKeyValue(SchemaContext sc,ConnectionValues cv) {
if (distributionKey != null) return distributionKey.getDetachedKey(sc,cv);
if (distributionVector != null) return (distributionVector.usesColumns(sc) ? null : distributionVector.getKeyValue(sc));
return null;
}
public DistributionKey getDistributionKey() {
return distributionKey;
}
public DistributionVector getDistributionVector() {
return distributionVector;
}
public DistributionModel getDistributionModel(SchemaContext sc) {
if (distributionVector == null) return null;
return distributionVector.getModel().getSingleton();
}
@Override
public void getSQL(SchemaContext sc, ConnectionValuesMap cvm, ExecutionPlan containing, List<String> buf, EmitOptions opts) {
buf.add(getSQL(sc,cvm,containing,opts));
}
@Override
public void displaySQL(SchemaContext sc, ConnectionValuesMap cvm, ExecutionPlan containing, List<String> buf, String indent, EmitOptions opts) {
ArrayList<String> sub = new ArrayList<String>();
sql.resolveAsTextLines(cvm.getValues(containing), false, " ", sub);
for(String s : sub) {
buf.add(indent + " " + s);
}
}
public static DirectExecutionStep buildUnplannedStep(SchemaContext sc, ExecutionType forType,
TableKey onTable, DistributionVector vect, Database<?> onDB, PEStorageGroup storageGroup,
DMLStatement stmt, ExecutionType effectiveType,
DMLExplainRecord splain) throws PEException {
DirectExecutionStep des = null;
if (forType == ExecutionType.SELECT || forType == ExecutionType.UNION) {
des = ProjectingExecutionStep.build(sc,onDB, storageGroup, vect, null, stmt, splain);
} else if (forType == ExecutionType.UPDATE) {
if (onTable.getAbstractTable().isView())
throw new SchemaException(Pass.PLANNER,"No support for updating views");
des = UpdateExecutionStep.build(sc,onDB, storageGroup, onTable.getAbstractTable().asTable(), null, stmt,
stmt.getDerivedInfo().doSetTimestampVariable(), splain);
} else if (forType == ExecutionType.DELETE) {
des = DeleteExecutionStep.build(
sc,
onDB,
storageGroup,
onTable,
null,
stmt,
false,
splain);
} else {
throw new TransformException(Pass.PLANNER, "No unplanned step available for " + forType.name());
}
des.effectiveType = effectiveType;
return des;
}
@Override
public void display(SchemaContext sc, ConnectionValuesMap cv, ExecutionPlan containing, List<String> buf, String indent, EmitOptions opts) {
super.display(sc, cv, containing, buf, indent, opts);
if (distributionKey != null) {
buf.add(indent + " dist key: " + distributionKey.describe(cv.getValues(containing)));
} else if (distributionVector != null) {
buf.add(indent + " dist on: " + distributionVector.describe(sc,cv.getValues(containing)));
}
if (explainHelp != null)
buf.add(indent + " reason: " + explainHelp);
}
protected String explainSourceModel() {
if (getDistributionVector() == null) return null;
return getDistributionVector().getModel().getPersistentName();
}
protected String explainSourceDistKey(SchemaContext sc) {
if (distributionKey == null) return null;
return distributionKey.describe(sc.getValues());
}
@Override
public void prepareForCache() {
if (distributionKey == null) return;
distributionKey.setFrozen();
}
public boolean requiresReferenceTimestamp() {
return requiresReferenceTimestamp;
}
public void setRequiresReferenceTimestamp(boolean requiresReferenceTimestamp) {
this.requiresReferenceTimestamp = requiresReferenceTimestamp;
}
public long getReferenceTimestamp(ConnectionValues cv) {
return (requiresReferenceTimestamp ? cv.getCurrentTimestamp() : 0);
}
public StepExecutionStatistics getReportStatistics() {
return stats;
}
public StepExecutionStatistics getStepStatistics(SchemaContext sc) {
if (KnownVariables.STEPWISE_STATISTICS.getValue(sc.getConnection().getVariableSource()).booleanValue())
return stats;
return null;
}
public void clearStatistics() {
stats = new StepExecutionStatistics();
}
public DMLExplainRecord getExplainHint() {
return explainHelp;
}
protected void addStepExplainColumns(SchemaContext sc, ConnectionValues cv, ResultRow rr, ExplainOptions opts) {
}
protected void addExplainColumns(SchemaContext sc, ConnectionValues cv, ResultRow rr,ExplainOptions opts) {
super.addExplainColumns(sc, cv, rr, opts);
addStepExplainColumns(sc,cv, rr, opts);
if (opts.isStatistics()) {
StepExecutionStatistics t = stats;
if (t != null)
t.addColumns(rr);
}
}
protected String explainExplainHint(SchemaContext sc) {
if (explainHelp == null)
return null;
return explainHelp.toString();
}
}