package com.tesora.dve.sql.statement.ddl; /* * #%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.HashSet; import java.util.List; import java.util.Set; import com.tesora.dve.common.catalog.TemplateMode; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.sql.node.expression.TableInstance; import com.tesora.dve.sql.schema.DistributionVector; import com.tesora.dve.sql.schema.DistributionVector.Model; import com.tesora.dve.sql.schema.Name; import com.tesora.dve.sql.schema.PEColumn; import com.tesora.dve.sql.schema.PEDatabase; import com.tesora.dve.sql.schema.PETable; import com.tesora.dve.sql.schema.PETemplate; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.schema.UnqualifiedName; import com.tesora.dve.sql.schema.cache.CacheInvalidationRecord; import com.tesora.dve.sql.schema.cache.InvalidationScope; import com.tesora.dve.sql.statement.ddl.alter.ChangeTableDistributionAction; import com.tesora.dve.sql.template.TemplateManager; import com.tesora.dve.sql.template.jaxb.ModelType; import com.tesora.dve.sql.template.jaxb.TableTemplateType; import com.tesora.dve.sql.transform.behaviors.BehaviorConfiguration; import com.tesora.dve.sql.transform.execution.ExecutionSequence; import com.tesora.dve.sql.transform.execution.ExecutionStep; import com.tesora.dve.sql.util.Pair; /** * Update the template and "template mode" records on the target database. * If a template is specified (non-optional) also alter distribution models of * all database tables to match the updated template (perform redistribution if * necessary). * Distribution of any tables not specified in the provided template is not * affected. * Changes to the "template model" alone only affect creation of new tables. */ public class AlterDatabaseTemplateStatement extends PEAlterStatement<PEDatabase> { private final PEDatabase target; private final Name templateName; private final TemplateMode templateMode; public AlterDatabaseTemplateStatement(final PEDatabase target, final Pair<Name, TemplateMode> templateDeclaration) { super(target, true); this.target = target; this.templateName = templateDeclaration.getFirst(); this.templateMode = templateDeclaration.getSecond(); } @Override protected PEDatabase modify(SchemaContext pc, PEDatabase backing) throws PEException { backing.setTemplateName(this.templateName); backing.setTemplateMode(this.templateMode); return backing; } @Override public CacheInvalidationRecord getInvalidationRecord(SchemaContext sc) { return new CacheInvalidationRecord(this.target.getCacheKey(), InvalidationScope.CASCADE); } @Override public void plan(SchemaContext sc, ExecutionSequence es, BehaviorConfiguration config) throws PEException { final ExecutionStep alterDatabaseTemplate = buildStep(sc); es.append(alterDatabaseTemplate); /* Alter distribution models of individual tables. */ if (this.templateName != null) { final Set<PEAlterStatement<PETable>> alterTableStatements = buildAlterTableDistributionStmts(sc); for (final PEAlterStatement<PETable> stmt : alterTableStatements) { stmt.plan(sc, es, config); } } } private Set<PEAlterStatement<PETable>> buildAlterTableDistributionStmts(final SchemaContext sc) { assert (this.templateName != null); final PETemplate updatedTemplate = TemplateManager.findTemplate(sc, this.templateName.get()); final List<TableTemplateType> templateTableItems = updatedTemplate.getTemplate().getTabletemplate(); final Set<PEAlterStatement<PETable>> alterStatements = new HashSet<PEAlterStatement<PETable>>(templateTableItems.size()); for (final TableTemplateType item : templateTableItems) { final PEAlterStatement<PETable> stmt = getAlterDistributionStatementFor(sc, item); if (stmt != null) { alterStatements.add(stmt); } } return alterStatements; } private PEAlterStatement<PETable> getAlterDistributionStatementFor(final SchemaContext sc, final TableTemplateType item) { final String tableName = item.getMatch(); final TableInstance ti = this.target.getSchema().buildInstance(sc, new UnqualifiedName(tableName), null, true); if (ti != null) { final PETable table = ti.getAbstractTable().asTable(); final List<String> dvColumnNames = item.getColumn(); final List<PEColumn> dvColumns = lookupTableColumnsByName(sc, table, dvColumnNames); final ChangeTableDistributionAction alterAction = getUpdateDistributionActionFor(sc, dvColumns, item.getModel(), item.getRange()); return alterAction.requiresSingleStatement(sc, ti.getTableKey()); } return null; } private List<PEColumn> lookupTableColumnsByName(final SchemaContext sc, final PETable table, final List<String> columnNames) { if (!columnNames.isEmpty()) { final List<PEColumn> columns = new ArrayList<PEColumn>(columnNames.size()); for (final String name : columnNames) { columns.add(table.lookup(sc, name)); } return columns; } return null; } private ChangeTableDistributionAction getUpdateDistributionActionFor(final SchemaContext sc, final List<PEColumn> dvColumns, final ModelType model, final String rangeName) { final Model distributionModel = DistributionVector.Model.getModelFromPersistent(model.value()); final UnqualifiedName range = (rangeName != null) ? new UnqualifiedName(rangeName) : null; final DistributionVector dv = DistributionVector.buildDistributionVector(sc, distributionModel, dvColumns, range); return new ChangeTableDistributionAction(dv); } }