use of org.teiid.query.sql.proc.TriggerAction in project teiid by teiid.
the class TestIsDistinctCriteria method testParseClone.
@Test
public void testParseClone() throws QueryParserException {
TriggerAction ta = (TriggerAction) QueryParser.getQueryParser().parseProcedure("for each row begin atomic if (\"new\" is not distinct from \"old\") raise sqlexception ''; end", true);
assertEquals("FOR EACH ROW\nBEGIN ATOMIC\nIF(\"new\" IS NOT DISTINCT FROM \"old\")\nBEGIN\nRAISE SQLEXCEPTION '';\nEND\nEND", ta.toString());
QueryParser.getQueryParser().parseProcedure(ta.toString(), true);
TriggerAction clone = ta.clone();
assertEquals(ta.toString(), clone.toString());
UnitTestUtil.helpTestEquivalence(0, ta, ta.clone());
}
use of org.teiid.query.sql.proc.TriggerAction in project teiid by teiid.
the class SourceTriggerActionPlanner method optimize.
@Override
public ProcessorPlan optimize(Command command, IDGenerator idGenerator, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
SourceEventCommand sec = (SourceEventCommand) command;
Map<Expression, Integer> lookup = new HashMap<Expression, Integer>();
Map<ElementSymbol, Expression> params = new HashMap<ElementSymbol, Expression>();
List<Object> tuple = new ArrayList<Object>();
Map<String, Integer> map = null;
if (sec.getColumnNames() != null) {
map = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER);
for (String name : sec.getColumnNames()) {
map.put(name, map.size());
}
}
GroupSymbol changingGroup = new GroupSymbol(ProcedureReservedWords.CHANGING);
if (sec.newValues != null) {
GroupSymbol newGroup = new GroupSymbol(SQLConstants.Reserved.NEW);
newGroup.setMetadataID(sec.table);
for (int i = 0; i < sec.getTable().getColumns().size(); i++) {
Column c = sec.getTable().getColumns().get(i);
Integer index = null;
if (map != null) {
index = map.get(c.getName());
} else {
index = i;
}
ElementSymbol newElement = new ElementSymbol(c.getName(), newGroup);
newElement.setMetadataID(c);
ElementSymbol changingElement = new ElementSymbol(c.getName(), changingGroup);
lookup.put(newElement, tuple.size());
lookup.put(changingElement, tuple.size() + 1);
params.put(newElement, newElement);
params.put(changingElement, changingElement);
if (index == null) {
// not changing
tuple.add(new Constant(null));
tuple.add(new Constant(Boolean.FALSE));
} else {
// changing
tuple.add(new Constant(DataTypeManager.convertToRuntimeType(sec.newValues[index], true)));
tuple.add(new Constant(Boolean.TRUE));
}
}
}
if (sec.oldValues != null) {
GroupSymbol oldGroup = new GroupSymbol(SQLConstants.Reserved.OLD);
oldGroup.setMetadataID(sec.table);
for (int i = 0; i < sec.getTable().getColumns().size(); i++) {
Column c = sec.getTable().getColumns().get(i);
Integer index = null;
if (map != null) {
index = map.get(c.getName());
} else {
index = i;
}
ElementSymbol oldElement = new ElementSymbol(c.getName(), oldGroup);
oldElement.setMetadataID(c);
lookup.put(oldElement, tuple.size());
params.put(oldElement, oldElement);
if (index != null) {
tuple.add(new Constant(DataTypeManager.convertToRuntimeType(sec.oldValues[index], true)));
}
}
}
List<ProcessorPlan> plans = new ArrayList<ProcessorPlan>();
List<String> names = new ArrayList<String>();
for (Trigger tr : sec.getTable().getTriggers().values()) {
int updateType = Command.TYPE_UPDATE;
switch(tr.getEvent()) {
case DELETE:
updateType = Command.TYPE_DELETE;
if (sec.newValues != null) {
continue;
}
break;
case INSERT:
updateType = Command.TYPE_INSERT;
if (sec.oldValues != null) {
continue;
}
break;
case UPDATE:
if (sec.oldValues == null || sec.newValues == null) {
continue;
}
break;
}
// create plan
ForEachRowPlan result = new ForEachRowPlan();
result.setSingleRow(true);
result.setParams(params);
TriggerAction parseProcedure;
GroupSymbol gs = new GroupSymbol(sec.table.getFullName());
try {
parseProcedure = (TriggerAction) QueryParser.getQueryParser().parseProcedure(tr.getPlan(), true);
QueryResolver.resolveCommand(parseProcedure, gs, updateType, metadata.getDesignTimeMetadata(), false);
} catch (QueryParserException e) {
// should have been validated
throw new TeiidComponentException(e);
} catch (QueryResolverException e) {
// should have been validated
throw new TeiidComponentException(e);
}
CreateProcedureCommand cpc = new CreateProcedureCommand(parseProcedure.getBlock());
gs.setMetadataID(sec.table);
cpc.setVirtualGroup(gs);
cpc.setUpdateType(updateType);
ProcedurePlan rowProcedure = (ProcedurePlan) QueryOptimizer.optimizePlan(cpc, metadata, idGenerator, capFinder, analysisRecord, context);
rowProcedure.setRunInContext(false);
result.setRowProcedure(rowProcedure);
result.setLookupMap(lookup);
result.setTupleSource(new CollectionTupleSource(Arrays.asList(tuple).iterator()));
plans.add(result);
names.add(tr.getName());
}
return new CompositeProcessorPlan(plans, names, sec.table);
}
use of org.teiid.query.sql.proc.TriggerAction in project teiid by teiid.
the class RelationalPlanner method addNestedProcedure.
private boolean addNestedProcedure(PlanNode sourceNode, ProcedureContainer container, Object metadataId) throws TeiidComponentException, QueryMetadataException, TeiidProcessingException {
if (container instanceof StoredProcedure) {
StoredProcedure sp = (StoredProcedure) container;
if (sp.getProcedureID() instanceof Procedure) {
context.accessedPlanningObject(sp.getProcedureID());
}
}
for (SubqueryContainer<?> subqueryContainer : ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(container)) {
if (subqueryContainer.getCommand().getCorrelatedReferences() != null) {
continue;
}
List<Reference> correlatedReferences = new ArrayList<Reference>();
CorrelatedReferenceCollectorVisitor.collectReferences(subqueryContainer.getCommand(), Arrays.asList(container.getGroup()), correlatedReferences, metadata);
setCorrelatedReferences(subqueryContainer, correlatedReferences);
}
// $NON-NLS-1$
String cacheString = "transformation/" + container.getClass().getSimpleName().toUpperCase();
Command c = (Command) metadata.getFromMetadataCache(metadataId, cacheString);
if (c == null) {
c = QueryResolver.expandCommand(container, metadata, analysisRecord);
if (c != null) {
if (c instanceof CreateProcedureCommand) {
// TODO: find a better way to do this
((CreateProcedureCommand) c).setProjectedSymbols(container.getProjectedSymbols());
}
Request.validateWithVisitor(new ValidationVisitor(), metadata, c);
metadata.addToMetadataCache(metadataId, cacheString, c.clone());
}
} else {
c = (Command) c.clone();
if (c instanceof CreateProcedureCommand) {
// TODO: find a better way to do this
((CreateProcedureCommand) c).setProjectedSymbols(container.getProjectedSymbols());
}
}
boolean checkRowBasedSecurity = true;
if (!container.getGroup().isProcedure() && !metadata.isVirtualGroup(metadataId)) {
Set<PlanningStackEntry> entries = planningStack.get();
if (entries.contains(new PlanningStackEntry(container, container.getGroup()))) {
checkRowBasedSecurity = false;
}
}
if (checkRowBasedSecurity) {
c = RowBasedSecurityHelper.checkUpdateRowBasedFilters(container, c, this);
}
if (c != null) {
if (c instanceof TriggerAction) {
TriggerAction ta = (TriggerAction) c;
ProcessorPlan plan = new TriggerActionPlanner().optimize((ProcedureContainer) container.clone(), ta, idGenerator, metadata, capFinder, analysisRecord, context);
sourceNode.setProperty(NodeConstants.Info.PROCESSOR_PLAN, plan);
return true;
}
if (c.getCacheHint() != null) {
if (container instanceof StoredProcedure) {
StoredProcedure sp = (StoredProcedure) container;
boolean noCache = isNoCacheGroup(metadata, sp.getProcedureID(), option);
if (!noCache) {
if (!context.isResultSetCacheEnabled()) {
// $NON-NLS-1$ //$NON-NLS-2$
recordAnnotation(analysisRecord, Annotation.CACHED_PROCEDURE, Priority.MEDIUM, "SimpleQueryResolver.procedure_cache_not_usable", container.getGroup(), "result set cache disabled");
} else if (!container.areResultsCachable()) {
// $NON-NLS-1$ //$NON-NLS-2$
recordAnnotation(analysisRecord, Annotation.CACHED_PROCEDURE, Priority.MEDIUM, "SimpleQueryResolver.procedure_cache_not_usable", container.getGroup(), "procedure performs updates");
} else if (LobManager.getLobIndexes(new ArrayList<ElementSymbol>(sp.getProcedureParameters().keySet())) != null) {
// $NON-NLS-1$ //$NON-NLS-2$
recordAnnotation(analysisRecord, Annotation.CACHED_PROCEDURE, Priority.MEDIUM, "SimpleQueryResolver.procedure_cache_not_usable", container.getGroup(), "lob parameters");
}
container.getGroup().setGlobalTable(true);
container.setCacheHint(c.getCacheHint());
// $NON-NLS-1$*/
recordAnnotation(analysisRecord, Annotation.CACHED_PROCEDURE, Priority.LOW, "SimpleQueryResolver.procedure_cache_used", container.getGroup());
return false;
}
// $NON-NLS-1$
recordAnnotation(analysisRecord, Annotation.CACHED_PROCEDURE, Priority.LOW, "SimpleQueryResolver.procedure_cache_not_used", container.getGroup());
}
}
// skip the rewrite here, we'll do that in the optimizer
// so that we know what the determinism level is.
addNestedCommand(sourceNode, container.getGroup(), container, c, false, true);
}
List<SubqueryContainer<?>> subqueries = ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(container);
if (c == null && container instanceof FilteredCommand) {
// we force the evaluation of procedure params - TODO: inserts are fine except for nonpushdown functions on columns
// for non-temp source queries, we must pre-plan subqueries to know if they can be pushed down
boolean compensate = false;
boolean isTemp = container.getGroup().isTempTable() && metadata.getModelID(container.getGroup().getMetadataID()) == TempMetadataAdapter.TEMP_MODEL;
try {
planSubqueries(container, c, subqueries, true);
} catch (QueryPlannerException e) {
if (!isTemp) {
throw e;
}
compensate = true;
}
if (!isTemp && !CriteriaCapabilityValidatorVisitor.canPushLanguageObject(container, metadata.getModelID(container.getGroup().getMetadataID()), metadata, capFinder, analysisRecord)) {
compensate = true;
}
if (compensate) {
// do a workaround of row-by-row processing for update/delete
validateRowProcessing(container);
// treat this as an update procedure
if (container instanceof Update) {
c = QueryRewriter.createUpdateProcedure((Update) container, metadata, context);
} else {
c = QueryRewriter.createDeleteProcedure((Delete) container, metadata, context);
}
addNestedCommand(sourceNode, container.getGroup(), container, c, false, true);
return false;
}
}
// plan any subqueries in criteria/parameters/values
planSubqueries(container, c, subqueries, false);
return false;
}
use of org.teiid.query.sql.proc.TriggerAction in project teiid by teiid.
the class ProcedureContainerResolver method findChildCommandMetadata.
/**
* Set the appropriate "external" metadata for the given command
* @param inferProcedureResultSetColumns
* @throws QueryResolverException
*/
public static void findChildCommandMetadata(Command currentCommand, GroupSymbol container, int type, QueryMetadataInterface metadata, boolean inferProcedureResultSetColumns) throws QueryMetadataException, TeiidComponentException, QueryResolverException {
// find the childMetadata using a clean metadata store
TempMetadataStore childMetadata = new TempMetadataStore();
TempMetadataAdapter tma = new TempMetadataAdapter(metadata, childMetadata);
GroupContext externalGroups = new GroupContext();
if (currentCommand instanceof TriggerAction) {
TriggerAction ta = (TriggerAction) currentCommand;
ta.setView(container);
// TODO: it seems easier to just inline the handling here rather than have each of the resolvers check for trigger actions
List<ElementSymbol> viewElements = ResolverUtil.resolveElementsInGroup(ta.getView(), metadata);
if (type == Command.TYPE_UPDATE || type == Command.TYPE_INSERT) {
ProcedureContainerResolver.addChanging(tma.getMetadataStore(), externalGroups, viewElements);
ProcedureContainerResolver.addScalarGroup(SQLConstants.Reserved.NEW, tma.getMetadataStore(), externalGroups, viewElements, false);
if (type == Command.TYPE_INSERT) {
List<ElementSymbol> key = InsertResolver.getAutoIncrementKey(ta.getView().getMetadataID(), viewElements, metadata);
if (key != null) {
ProcedureContainerResolver.addScalarGroup(SQLConstants.NonReserved.KEY, tma.getMetadataStore(), externalGroups, key, true);
}
}
}
if (type == Command.TYPE_UPDATE || type == Command.TYPE_DELETE) {
ProcedureContainerResolver.addScalarGroup(SQLConstants.Reserved.OLD, tma.getMetadataStore(), externalGroups, viewElements, false);
}
} else if (currentCommand instanceof CreateProcedureCommand) {
CreateProcedureCommand cupc = (CreateProcedureCommand) currentCommand;
cupc.setVirtualGroup(container);
if (type == Command.TYPE_STORED_PROCEDURE) {
StoredProcedureInfo info = metadata.getStoredProcedureInfoForProcedure(container.getName());
// Create temporary metadata that defines a group based on either the stored proc
// name or the stored query name - this will be used later during planning
String procName = info.getProcedureCallableName();
// Look through parameters to find input elements - these become child metadata
List<ElementSymbol> tempElements = new ArrayList<ElementSymbol>(info.getParameters().size());
boolean[] updatable = new boolean[info.getParameters().size()];
int i = 0;
List<ElementSymbol> rsColumns = Collections.emptyList();
for (SPParameter param : info.getParameters()) {
if (param.getParameterType() != ParameterInfo.RESULT_SET) {
ElementSymbol symbol = param.getParameterSymbol();
tempElements.add(symbol);
updatable[i++] = param.getParameterType() != ParameterInfo.IN;
if (param.getParameterType() == ParameterInfo.RETURN_VALUE) {
cupc.setReturnVariable(symbol);
}
} else {
rsColumns = param.getResultSetColumns();
}
}
if (inferProcedureResultSetColumns) {
rsColumns = null;
}
GroupSymbol gs = ProcedureContainerResolver.addScalarGroup(procName, childMetadata, externalGroups, tempElements, updatable);
if (cupc.getReturnVariable() != null) {
ResolverVisitor.resolveLanguageObject(cupc.getReturnVariable(), Arrays.asList(gs), metadata);
}
cupc.setResultSetColumns(rsColumns);
// the relational planner will override this with the appropriate value
cupc.setProjectedSymbols(rsColumns);
} else {
cupc.setUpdateType(type);
}
}
QueryResolver.setChildMetadata(currentCommand, childMetadata, externalGroups);
}
use of org.teiid.query.sql.proc.TriggerAction in project teiid by teiid.
the class TestProcedureResolving method testProcedureScoping.
@Test
public void testProcedureScoping() throws Exception {
StringBuffer proc = // $NON-NLS-1$
new StringBuffer("FOR EACH ROW").append(// $NON-NLS-1$
"\nBEGIN").append(// $NON-NLS-1$
"\n declare integer e1 = 1;").append(// $NON-NLS-1$
"\n e1 = e1;").append(// $NON-NLS-1$
"\n LOOP ON (SELECT pm1.g1.e1 FROM pm1.g1) AS loopCursor").append(// $NON-NLS-1$
"\n BEGIN").append(// $NON-NLS-1$
"\n variables.e1 = convert(e1, integer);").append(// $NON-NLS-1$
"\n END").append(// $NON-NLS-1$
"\nEND");
// $NON-NLS-1$
String userUpdateStr = "UPDATE vm1.g1 SET e1='x'";
TriggerAction command = helpResolveUpdateProcedure(proc.toString(), userUpdateStr, Table.TriggerEvent.UPDATE);
Block block = command.getBlock();
AssignmentStatement assStmt = (AssignmentStatement) block.getStatements().get(1);
assertEquals(ProcedureReservedWords.VARIABLES, assStmt.getVariable().getGroupSymbol().getName());
assertEquals(ProcedureReservedWords.VARIABLES, ((ElementSymbol) assStmt.getExpression()).getGroupSymbol().getName());
Block inner = ((LoopStatement) block.getStatements().get(2)).getBlock();
assStmt = (AssignmentStatement) inner.getStatements().get(0);
ElementSymbol value = ElementCollectorVisitor.getElements(assStmt.getExpression(), false).iterator().next();
// $NON-NLS-1$
assertEquals("loopCursor", value.getGroupSymbol().getName());
}
Aggregations