/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.query.processor;
import static org.teiid.query.analysis.AnalysisRecord.*;
import java.util.Arrays;
import java.util.List;
import org.teiid.adminapi.impl.ModelMetaData;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.client.plan.PlanNode;
import org.teiid.common.buffer.BlockedException;
import org.teiid.common.buffer.BufferManager;
import org.teiid.common.buffer.TupleBatch;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.TeiidRuntimeException;
import org.teiid.dqp.internal.process.DQPWorkContext;
import org.teiid.language.SQLConstants;
import org.teiid.metadata.AbstractMetadataRecord;
import org.teiid.metadata.Column;
import org.teiid.metadata.ColumnStats;
import org.teiid.metadata.MetadataRepository;
import org.teiid.metadata.Procedure;
import org.teiid.metadata.Table;
import org.teiid.metadata.Table.TriggerEvent;
import org.teiid.metadata.TableStats;
import org.teiid.query.QueryPlugin;
import org.teiid.query.metadata.DatabaseStore;
import org.teiid.query.metadata.MetadataValidator;
import org.teiid.query.metadata.TransformationMetadata;
import org.teiid.query.parser.QueryParser;
import org.teiid.query.resolver.QueryResolver;
import org.teiid.query.sql.LanguageVisitor;
import org.teiid.query.sql.lang.AlterProcedure;
import org.teiid.query.sql.lang.AlterTrigger;
import org.teiid.query.sql.lang.AlterView;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.StoredProcedure;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.util.CommandContext;
public class DdlPlan extends ProcessorPlan {
class AlterProcessor extends LanguageVisitor {
DQPWorkContext workContext = getContext().getDQPWorkContext();
VDBMetaData vdb = getContext().getVdb();
TransformationMetadata metadata = vdb.getAttachment(TransformationMetadata.class);
private MetadataRepository getMetadataRepository(VDBMetaData vdb, String schemaName) {
ModelMetaData model = vdb.getModel(schemaName);
return model.getAttachment(MetadataRepository.class);
}
@Override
public void visit(AlterView obj) {
Table t = (Table)obj.getTarget().getMetadataID();
String sql = obj.getDefinition().toString();
if (getMetadataRepository(vdb, t.getParent().getName()) != null) {
getMetadataRepository(vdb, t.getParent().getName()).setViewDefinition(workContext.getVdbName(), workContext.getVdbVersion(), t, sql);
}
alterView(vdb, t, sql, false);
if (pdm.getEventDistributor() != null) {
pdm.getEventDistributor().setViewDefinition(workContext.getVdbName(), workContext.getVdbVersion(), t.getParent().getName(), t.getName(), sql);
}
}
@Override
public void visit(AlterProcedure obj) {
Procedure p = (Procedure)obj.getTarget().getMetadataID();
String sql = obj.getDefinition().toString();
if (getMetadataRepository(vdb, p.getParent().getName()) != null) {
getMetadataRepository(vdb, p.getParent().getName()).setProcedureDefinition(workContext.getVdbName(), workContext.getVdbVersion(), p, sql);
}
alterProcedureDefinition(vdb, p, sql, false);
if (pdm.getEventDistributor() != null) {
pdm.getEventDistributor().setProcedureDefinition(workContext.getVdbName(), workContext.getVdbVersion(), p.getParent().getName(), p.getName(), sql);
}
}
@Override
public void visit(AlterTrigger obj) {
Table t = (Table)obj.getTarget().getMetadataID();
String sql = null;
TriggerEvent event = obj.getEvent();
if (obj.getEnabled() == null) {
if (obj.isCreate()) {
if (getPlanForEvent(t, event) != null) {
throw new TeiidRuntimeException(new TeiidProcessingException(QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30156, t.getName(), obj.getEvent())));
}
} else if (getPlanForEvent(t, event) == null) {
throw new TeiidRuntimeException(new TeiidProcessingException(QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30158, t.getName(), obj.getEvent())));
}
sql = obj.getDefinition().toString();
} else if (getPlanForEvent(t, event) == null) {
throw new TeiidRuntimeException(new TeiidProcessingException(QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30158, t.getName(), obj.getEvent())));
}
if (getMetadataRepository(vdb, t.getParent().getName()) != null) {
if (sql != null) {
getMetadataRepository(vdb, t.getParent().getName()).setInsteadOfTriggerDefinition(workContext.getVdbName(), workContext.getVdbVersion(), t, obj.getEvent(), sql);
} else {
getMetadataRepository(vdb, t.getParent().getName()).setInsteadOfTriggerEnabled(workContext.getVdbName(), workContext.getVdbVersion(), t, obj.getEvent(), obj.getEnabled());
}
}
alterInsteadOfTrigger(vdb, t, sql, obj.getEnabled(), event, false);
if (pdm.getEventDistributor() != null) {
pdm.getEventDistributor().setInsteadOfTriggerDefinition(workContext.getVdbName(), workContext.getVdbVersion(), t.getParent().getName(), t.getName(), obj.getEvent(), sql, obj.getEnabled());
}
}
}
public static void alterView(final VDBMetaData vdb, final Table t, final String sql, boolean updateStore) {
TransformationMetadata metadata = vdb.getAttachment(TransformationMetadata.class);
DatabaseStore store = vdb.getAttachment(DatabaseStore.class);
try {
Command command = QueryParser.getQueryParser().parseCommand(t.getSelectTransformation());
QueryResolver.resolveCommand(command, metadata);
MetadataValidator.determineDependencies(t, command);
} catch (TeiidException e) {
//should have been caught in validation, but this logic
//is also not mature so since there is no lock on the vdb
//it is possible that the plan is no longer valid at this point due
//to a concurrent execution
}
t.setSelectTransformation(sql);
t.setLastModified(System.currentTimeMillis());
metadata.addToMetadataCache(t, "transformation/"+SQLConstants.Reserved.SELECT, null); //$NON-NLS-1$
}
public static String setProperty(final VDBMetaData vdb, final AbstractMetadataRecord record, final String key, final String value) {
TransformationMetadata metadata = vdb.getAttachment(TransformationMetadata.class);
String result = record.setProperty(key, value);
metadata.addToMetadataCache(record, "transformation/matview", null); //$NON-NLS-1$
if (record instanceof Table) {
((Table)record).setLastModified(System.currentTimeMillis());
} else if (record instanceof Procedure) {
((Procedure)record).setLastModified(System.currentTimeMillis());
}
return result;
}
public static void setColumnStats(final VDBMetaData vdb, Column column, final ColumnStats columnStats) {
column.setColumnStats(columnStats);
if (column.getParent() instanceof Table) {
((Table)column.getParent()).setLastModified(System.currentTimeMillis());
}
}
public static void setTableStats(final VDBMetaData vdb, final Table table, final TableStats tableStats) {
table.setTableStats(tableStats);
table.setLastModified(System.currentTimeMillis());
}
public static void alterProcedureDefinition(final VDBMetaData vdb, final Procedure p, final String sql, boolean updateStore) {
TransformationMetadata metadata = vdb.getAttachment(TransformationMetadata.class);
DatabaseStore store = vdb.getAttachment(DatabaseStore.class);
try {
Command command = QueryParser.getQueryParser().parseProcedure(p.getQueryPlan(), false);
QueryResolver.resolveCommand(command, new GroupSymbol(p.getFullName()), Command.TYPE_STORED_PROCEDURE, metadata, false);
MetadataValidator.determineDependencies(p, command);
} catch (TeiidException e) {
//should have been caught in validation, but this logic
//is also not mature so since there is no lock on the vdb
//it is possible that the plan is no longer valid at this point due
//to a concurrent execution
}
p.setQueryPlan(sql);
p.setLastModified(System.currentTimeMillis());
metadata.addToMetadataCache(p, "transformation/"+StoredProcedure.class.getSimpleName().toUpperCase(), null); //$NON-NLS-1$
}
public static void alterInsteadOfTrigger(final VDBMetaData vdb, final Table t,
final String sql, final Boolean enabled, final TriggerEvent event, boolean updateStore) {
switch (event) {
case DELETE:
if (sql != null) {
t.setDeletePlan(sql);
} else {
t.setDeletePlanEnabled(enabled);
}
break;
case INSERT:
if (sql != null) {
t.setInsertPlan(sql);
} else {
t.setInsertPlanEnabled(enabled);
}
break;
case UPDATE:
if (sql != null) {
t.setUpdatePlan(sql);
} else {
t.setUpdatePlanEnabled(enabled);
}
break;
}
TransformationMetadata indexMetadata = vdb.getAttachment(TransformationMetadata.class);
indexMetadata.addToMetadataCache(t, "transformation/"+event, null); //$NON-NLS-1$
t.setLastModified(System.currentTimeMillis());
}
private static String getPlanForEvent(Table t, TriggerEvent event) {
switch (event) {
case DELETE:
return t.getDeletePlan();
case INSERT:
return t.getInsertPlan();
case UPDATE:
return t.getUpdatePlan();
}
throw new AssertionError();
}
private Command command;
private ProcessorDataManager pdm;
public DdlPlan(Command command) {
this.command = command;
}
@Override
public ProcessorPlan clone() {
return new DdlPlan(command);
}
@Override
public void close() throws TeiidComponentException {
}
@Override
public List getOutputElements() {
return command.getProjectedSymbols();
}
@Override
public void initialize(CommandContext context,
ProcessorDataManager dataMgr, BufferManager bufferMgr) {
this.setContext(context);
this.pdm = dataMgr;
}
@Override
public TupleBatch nextBatch() throws BlockedException,
TeiidComponentException, TeiidProcessingException {
TupleBatch tupleBatch = new TupleBatch(1, new List[] {Arrays.asList(0)});
tupleBatch.setTerminationFlag(true);
return tupleBatch;
}
@Override
public void open() throws TeiidComponentException, TeiidProcessingException {
AlterProcessor ap = new AlterProcessor();
try {
command.acceptVisitor(ap);
} catch (TeiidRuntimeException e) {
if (e.getCause() instanceof TeiidProcessingException) {
throw (TeiidProcessingException)e.getCause();
}
throw e;
}
}
@Override
public PlanNode getDescriptionProperties() {
PlanNode props = super.getDescriptionProperties();
props.addProperty(PROP_SQL, this.command.toString());
return props;
}
@Override
public String toString() {
return command.toString();
}
}