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.Collections; import java.util.List; import com.tesora.dve.common.catalog.AutoIncrementTracker; import com.tesora.dve.common.catalog.CatalogEntity; import com.tesora.dve.db.DBResultConsumer; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.queryplan.ExecutionState; import com.tesora.dve.queryplan.QueryStepDDLNestedOperation.NestedOperationDDLCallback; import com.tesora.dve.server.connectionmanager.SSConnection; import com.tesora.dve.sql.expression.MTTableKey; import com.tesora.dve.sql.expression.TableKey; import com.tesora.dve.sql.node.LanguageNode; import com.tesora.dve.sql.node.expression.TableInstance; import com.tesora.dve.sql.parser.SourceLocation; import com.tesora.dve.sql.schema.DistributionKey; import com.tesora.dve.sql.schema.LockInfo; import com.tesora.dve.sql.schema.PEDatabase; import com.tesora.dve.sql.schema.PEStorageGroup; import com.tesora.dve.sql.schema.PETable; 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.schema.cache.CacheInvalidationRecord; import com.tesora.dve.sql.schema.cache.InvalidationScope; import com.tesora.dve.sql.schema.cache.SchemaCacheKey; import com.tesora.dve.sql.schema.mt.PETenant; import com.tesora.dve.sql.schema.mt.TableScope; import com.tesora.dve.sql.statement.StatementTraits; import com.tesora.dve.sql.statement.StatementType; import com.tesora.dve.sql.transform.behaviors.BehaviorConfiguration; import com.tesora.dve.sql.transform.execution.ComplexDDLExecutionStep; import com.tesora.dve.sql.transform.execution.ExecutionSequence; import com.tesora.dve.sql.transform.execution.ExecutionStep; import com.tesora.dve.sql.transform.execution.ExecutionType; import com.tesora.dve.sql.transform.execution.FilterExecutionStep; import com.tesora.dve.sql.transform.execution.SimpleDDLExecutionStep; import com.tesora.dve.sql.transform.execution.CatalogModificationExecutionStep.Action; import com.tesora.dve.sql.transform.execution.LateBindingUpdateCountFilter.LateBindingUpdateCounter; import com.tesora.dve.worker.WorkerGroup; public class TruncateStatement extends UnaryTableDMLStatement { public static class ResetAutoIncrementTrackerCallback extends NestedOperationDDLCallback { private final PETable table; private final TableScope scope; public ResetAutoIncrementTrackerCallback(final TableKey tk) { this.table = tk.getAbstractTable().asTable(); this.scope = (tk instanceof MTTableKey) ? ((MTTableKey) tk).getScope() : null; } @Override public boolean canRetry(Throwable t) { // TODO Auto-generated method stub return false; } @Override public boolean requiresFreshTxn() { // TODO Auto-generated method stub return false; } @Override public String description() { return "Reset the AI tracker of a given table."; } @Override public CacheInvalidationRecord getInvalidationRecord() { final SchemaCacheKey<?> cacheKey = (this.scope != null) ? this.scope.getCacheKey() : this.table.getCacheKey(); return new CacheInvalidationRecord(cacheKey, InvalidationScope.LOCAL); } @Override public boolean requiresWorkers() { // TODO Auto-generated method stub return false; } @Override public void executeNested(ExecutionState estate, WorkerGroup wg, DBResultConsumer resultConsumer) throws Throwable { SSConnection conn = estate.getConnection(); final SchemaContext sc = SchemaContext.createContext(conn); if (table.hasAutoInc()) { AutoIncrementTracker ait = null; TableScope actualScope = null; if (scope != null) { final PETenant currentTenant = (PETenant) sc.getCurrentTenant().get(sc); actualScope = currentTenant.lookupScope(sc, scope.getName(), new LockInfo(StatementTraits.getLockType(TruncateStatement.class), "truncate statement callback")); } if (actualScope != null) ait = sc.getCatalog().getBackingTracker(sc, actualScope); else ait = sc.getCatalog().getBackingTracker(sc, table); if (ait != null) { ait.reset(sc.getCatalog().getDAO()); } } } } public TruncateStatement(TableInstance tab, SourceLocation loc) { super(loc); this.intoTable.set(tab); } public TableInstance getTruncatedTable() { return intoTable.get(); } @Override public List<PEStorageGroup> getStorageGroups(SchemaContext pc) { return Collections.singletonList(getTable().getStorageGroup(pc)); } @Override public void normalize(SchemaContext pc) { // no-op } /** * Although TRUNCATE TABLE is similar to DELETE, it is classified as a DDL * statement rather than a DML statement. */ @Override public boolean isDML() { return false; } /** * Any AUTO_INCREMENT value is reset to its start value. This is true even * for MyISAM and InnoDB, which normally do not reuse sequence values. */ @Override public void plan(SchemaContext pc, ExecutionSequence es, BehaviorConfiguration config) throws PEException { planViaTransforms(pc, this, es, config); /* * TRUNCATE always returns 0 update count. * Make sure, we use the count from this step * even in the MT case. */ final TableInstance truncatedTable = getTruncatedTable(); if (!truncatedTable.isMT()) { es.append(new SimpleDDLExecutionStep((PEDatabase) getDatabase(pc), getStorageGroup(pc), truncatedTable.getAbstractTable(), Action.ALTER, getSQLCommand(pc), Collections.<CatalogEntity> emptyList(), Collections.<CatalogEntity> emptyList(), new CacheInvalidationRecord(truncatedTable .getAbstractTable().getCacheKey(), InvalidationScope.LOCAL))); } es.append(new FilterExecutionStep(buildResetAutoIncrementTrackerStep(pc), new LateBindingUpdateCounter())); } @Override public ExecutionStep buildSingleKeyStep(SchemaContext sc, TableKey tab, DistributionKey kv, DMLStatement sql) throws PEException { return buildResetAutoIncrementTrackerStep(sc); } @Override public ExecutionType getExecutionType() { return ExecutionType.DELETE; } @Override public DistKeyOpType getKeyOpType() { return null; } @Override public StatementType getStatementType() { return StatementType.TRUNCATE; } public ExecutionStep buildResetAutoIncrementTrackerStep(final SchemaContext sc) throws PEException { return new ComplexDDLExecutionStep((PEDatabase) getDatabase(sc), getStorageGroup(sc), getTruncatedTable().getAbstractTable(), Action.ALTER, new ResetAutoIncrementTrackerCallback(getTruncatedTable().getTableKey())); } @Override protected boolean schemaSelfEqual(LanguageNode other) { return true; } @Override protected int selfHashCode() { return 0; } @Override public TriggerEvent getTriggerEvent() { return null; } }