package com.tesora.dve.sql.statement.dml; /* * #%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.Arrays; import java.util.List; 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.TableKey; import com.tesora.dve.sql.node.Edge; import com.tesora.dve.sql.node.EdgeName; import com.tesora.dve.sql.node.LanguageNode; import com.tesora.dve.sql.node.MultiEdge; import com.tesora.dve.sql.node.SingleEdge; import com.tesora.dve.sql.node.expression.ExpressionNode; import com.tesora.dve.sql.node.expression.TableInstance; import com.tesora.dve.sql.node.structural.FromTableReference; import com.tesora.dve.sql.node.structural.LimitSpecification; import com.tesora.dve.sql.node.structural.SortingSpecification; import com.tesora.dve.sql.parser.SourceLocation; import com.tesora.dve.sql.schema.DistributionKey; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.schema.SchemaContext.DistKeyOpType; import com.tesora.dve.sql.schema.TriggerEvent; import com.tesora.dve.sql.statement.StatementType; import com.tesora.dve.sql.transform.execution.DeleteExecutionStep; import com.tesora.dve.sql.transform.execution.ExecutionStep; import com.tesora.dve.sql.transform.execution.ExecutionType; public class DeleteStatement extends MultiTableDMLStatement { // when we support multitable delete, this will need to be a multiedge private MultiEdge<DeleteStatement, TableInstance> deleteTableRef = new MultiEdge<DeleteStatement, TableInstance>(DeleteStatement.class, this, EdgeName.DELETE_TABLE); private MultiEdge<DeleteStatement, SortingSpecification> orderBys = new MultiEdge<DeleteStatement, SortingSpecification>(DeleteStatement.class, this, EdgeName.ORDERBY); private SingleEdge<DeleteStatement, LimitSpecification> limitExpression = new SingleEdge<DeleteStatement, LimitSpecification>(DeleteStatement.class, this, EdgeName.LIMIT); // true if this delete was originally a truncate statement. private boolean truncate; @SuppressWarnings("rawtypes") private List edges = Arrays.asList(new Edge[] { this.deleteTableRef, this.tableReferences, this.whereClause }); public DeleteStatement(List<FromTableReference> tableRefs, ExpressionNode whereClause, boolean truncateTable, AliasInformation ai) { this(null, tableRefs, whereClause, null, null, truncateTable, ai, null); } public DeleteStatement(List<TableInstance> explicitDeleteTables, List<FromTableReference> tableRefs, ExpressionNode whereClause, List<SortingSpecification> orderbys, LimitSpecification limit, boolean truncateTable, AliasInformation ai, SourceLocation sloc) { super(sloc); setTargetDeletes(explicitDeleteTables); setTables(tableRefs); setWhereClause(whereClause); setOrderBy(orderbys); setLimit(limit); truncate = truncateTable; setAliases(ai); } public DeleteStatement() { super(null); } public List<SortingSpecification> getOrderBys() { return orderBys.getMulti(); } public MultiEdge<DeleteStatement, SortingSpecification> getOrderBysEdge() { return orderBys; } public DeleteStatement setOrderBy(List<SortingSpecification> order) { orderBys.set(order); SortingSpecification.setOrdering(order, Boolean.TRUE); return this; } public LimitSpecification getLimit() { return limitExpression.get(); } public DeleteStatement setLimit(LimitSpecification ls) { limitExpression.set(ls); return this;} public Edge<DeleteStatement, LimitSpecification> getLimitEdge() { return limitExpression; } public boolean isTruncate() { return truncate; } public DeleteStatement setTruncate(boolean v) { truncate = v; return this; } public MultiEdge<DeleteStatement, TableInstance> getTargetDeleteEdge() { return this.deleteTableRef; } public List<TableInstance> getTargetDeletes() { return deleteTableRef.getMulti(); } public void setTargetDeletes(List<TableInstance> ti) { deleteTableRef.set(ti); } @Override public void normalize(SchemaContext sc) { // the front end does not actually accept delete T from T where f(T) // but we're going to normalize to that // the emitter takes care of not emitting this if it's not allowed if (!deleteTableRef.has()) { FromTableReference first = tableReferences.get(0); TableInstance fti = first.getBaseTable(); TableInstance oti = (TableInstance) fti.copy(null); deleteTableRef.set(oti); } for(TableInstance ti : deleteTableRef.getMulti()) { if (ti.getAbstractTable().isView()) throw new SchemaException(Pass.NORMALIZE,"No support for updatable views"); } } @Override public ExecutionStep buildSingleKeyStep(SchemaContext sc, TableKey tab, DistributionKey kv, DMLStatement sql) throws PEException { return DeleteExecutionStep.build( sc, getDatabase(sc), getStorageGroup(sc), tab, kv, sql, false, distKeyExplain); } @Override public DistKeyOpType getKeyOpType() { return DistKeyOpType.UPDATE; } @Override public ExecutionType getExecutionType() { return ExecutionType.DELETE; } @SuppressWarnings("unchecked") @Override public <T extends Edge<?,?>> List<T> getEdges() { return edges; } @Override public StatementType getStatementType() { return StatementType.DELETE; } @Override protected boolean schemaSelfEqual(LanguageNode other) { DeleteStatement ds = (DeleteStatement) other; return truncate == ds.truncate; } @Override protected int selfHashCode() { return addSchemaHash(1,truncate); } @Override public TriggerEvent getTriggerEvent() { return TriggerEvent.DELETE; } }