use of org.teiid.query.sql.util.SymbolMap in project teiid by teiid.
the class FrameUtil method convertNode.
// If newGroup == null, this will be performing a straight symbol swap - that is,
// an oldGroup is undergoing a name change and that is the only difference in the
// symbols. In that case, some additional work can be done because we can assume
// that an oldElement isn't being replaced by an expression using elements from
// multiple new groups.
static void convertNode(PlanNode node, GroupSymbol oldGroup, Set<GroupSymbol> newGroups, Map symbolMap, QueryMetadataInterface metadata, boolean rewrite) throws QueryPlannerException {
if (node.getType() == NodeConstants.Types.GROUP) {
correctSymbolMap(symbolMap, node);
}
// Convert expressions from correlated subquery references;
List<SymbolMap> refMaps = node.getAllReferences();
LinkedList<Expression> correlatedExpression = new LinkedList<Expression>();
for (SymbolMap refs : refMaps) {
for (Map.Entry<ElementSymbol, Expression> ref : refs.asUpdatableMap().entrySet()) {
Expression expr = ref.getValue();
Expression convertedExpr = convertExpression(expr, symbolMap);
ref.setValue(convertedExpr);
correlatedExpression.add(convertedExpr);
}
}
// Update groups for current node
Set<GroupSymbol> groups = node.getGroups();
boolean hasOld = groups.remove(oldGroup);
int type = node.getType();
boolean singleMapping = newGroups != null && newGroups.size() == 1;
if (singleMapping) {
if (!hasOld) {
return;
}
groups.addAll(newGroups);
} else if ((type & (NodeConstants.Types.ACCESS | NodeConstants.Types.JOIN | NodeConstants.Types.SOURCE)) == type) {
if (newGroups != null) {
groups.addAll(newGroups);
}
} else {
groups.clear();
}
groups.addAll(GroupsUsedByElementsVisitor.getGroups(correlatedExpression));
if (type == NodeConstants.Types.SELECT) {
Criteria crit = (Criteria) node.getProperty(NodeConstants.Info.SELECT_CRITERIA);
crit = convertCriteria(crit, symbolMap, metadata, rewrite);
node.setProperty(NodeConstants.Info.SELECT_CRITERIA, crit);
if (!singleMapping) {
GroupsUsedByElementsVisitor.getGroups(crit, groups);
}
} else if (type == NodeConstants.Types.PROJECT) {
List<Expression> projectedSymbols = (List<Expression>) node.getProperty(NodeConstants.Info.PROJECT_COLS);
Select select = new Select(projectedSymbols);
ExpressionMappingVisitor.mapExpressions(select, symbolMap);
if (rewrite) {
for (LanguageObject expr : select.getSymbols()) {
rewriteSingleElementSymbol(metadata, (Expression) expr);
}
}
node.setProperty(NodeConstants.Info.PROJECT_COLS, select.getSymbols());
if (!singleMapping) {
GroupsUsedByElementsVisitor.getGroups(select, groups);
}
} else if (type == NodeConstants.Types.JOIN) {
// Convert join criteria property
List<Criteria> joinCrits = (List<Criteria>) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
if (joinCrits != null && !joinCrits.isEmpty()) {
Criteria crit = new CompoundCriteria(joinCrits);
crit = convertCriteria(crit, symbolMap, metadata, rewrite);
if (crit instanceof CompoundCriteria && ((CompoundCriteria) crit).getOperator() == CompoundCriteria.AND) {
node.setProperty(NodeConstants.Info.JOIN_CRITERIA, ((CompoundCriteria) crit).getCriteria());
} else {
joinCrits = new ArrayList<Criteria>();
joinCrits.add(crit);
node.setProperty(NodeConstants.Info.JOIN_CRITERIA, joinCrits);
}
}
convertAccessPatterns(symbolMap, node);
} else if (type == NodeConstants.Types.SORT) {
OrderBy orderBy = (OrderBy) node.getProperty(NodeConstants.Info.SORT_ORDER);
ExpressionMappingVisitor.mapExpressions(orderBy, symbolMap);
if (rewrite) {
for (OrderByItem item : orderBy.getOrderByItems()) {
rewriteSingleElementSymbol(metadata, item.getSymbol());
}
}
if (!singleMapping) {
GroupsUsedByElementsVisitor.getGroups(orderBy, groups);
}
} else if (type == NodeConstants.Types.GROUP) {
List<Expression> groupCols = (List<Expression>) node.getProperty(NodeConstants.Info.GROUP_COLS);
if (groupCols != null) {
GroupBy groupBy = new GroupBy(groupCols);
ExpressionMappingVisitor.mapExpressions(groupBy, symbolMap);
node.setProperty(NodeConstants.Info.GROUP_COLS, groupBy.getSymbols());
if (!singleMapping) {
GroupsUsedByElementsVisitor.getGroups(groupBy, groups);
}
}
if (!singleMapping) {
// add back the anon group
SymbolMap property = (SymbolMap) node.getProperty(Info.SYMBOL_MAP);
if (!property.asMap().isEmpty()) {
groups.add(property.asMap().keySet().iterator().next().getGroupSymbol());
}
}
} else if (type == NodeConstants.Types.SOURCE || type == NodeConstants.Types.ACCESS) {
convertAccessPatterns(symbolMap, node);
}
}
use of org.teiid.query.sql.util.SymbolMap in project teiid by teiid.
the class FrameUtil method convertFrame.
public static void convertFrame(PlanNode startNode, GroupSymbol oldGroup, Set<GroupSymbol> newGroups, Map symbolMap, QueryMetadataInterface metadata) throws QueryPlannerException {
PlanNode current = startNode;
// correct the partition info keys
if (oldGroup != null && newGroups != null && newGroups.size() == 1 && startNode.getType() == NodeConstants.Types.SOURCE) {
Map<ElementSymbol, List<Set<Constant>>> partitionInfo = (Map<ElementSymbol, List<Set<Constant>>>) startNode.getProperty(Info.PARTITION_INFO);
if (partitionInfo != null) {
startNode.setProperty(Info.PARTITION_INFO, RelationalPlanner.remapPartitionInfo(newGroups.iterator().next(), partitionInfo));
}
}
PlanNode endNode = NodeEditor.findParent(startNode.getType() == NodeConstants.Types.SOURCE ? startNode.getParent() : startNode, NodeConstants.Types.SOURCE);
boolean rewrite = false;
if (newGroups != null && newGroups.size() == 1) {
for (Expression expression : (Collection<Expression>) symbolMap.values()) {
if (!(expression instanceof ElementSymbol)) {
rewrite = true;
break;
}
}
} else {
rewrite = true;
}
while (current != endNode) {
// Make translations as defined in node in each current node
convertNode(current, oldGroup, newGroups, symbolMap, metadata, rewrite);
PlanNode parent = current.getParent();
// check if this is not the first set op branch
if (parent != null && parent.getType() == NodeConstants.Types.SET_OP && parent.getFirstChild() != current) {
return;
}
// Move up the tree
current = parent;
}
if (endNode == null) {
return;
}
correctSymbolMap(symbolMap, endNode);
}
use of org.teiid.query.sql.util.SymbolMap in project teiid by teiid.
the class FrameUtil method canConvertAccessPatterns.
static boolean canConvertAccessPatterns(PlanNode sourceNode) {
List<AccessPattern> accessPatterns = (List) sourceNode.getProperty(NodeConstants.Info.ACCESS_PATTERNS);
if (accessPatterns == null) {
return true;
}
SymbolMap symbolMap = (SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
for (Iterator<AccessPattern> i = accessPatterns.iterator(); i.hasNext(); ) {
AccessPattern ap = i.next();
for (Iterator<ElementSymbol> elems = ap.getUnsatisfied().iterator(); elems.hasNext(); ) {
ElementSymbol symbol = elems.next();
Expression mapped = convertExpression(symbol, symbolMap.asMap());
if (ElementCollectorVisitor.getElements(mapped, true).isEmpty()) {
return false;
}
}
}
return true;
}
use of org.teiid.query.sql.util.SymbolMap in project teiid by teiid.
the class RuleAssignOutputElements method determineSourceOutput.
/**
* A special case to consider is when the virtual group is defined by a
* UNION (no ALL) or a SELECT DISTINCT. In this case, the dup removal means
* that all columns need to be used to determine duplicates. So, filtering the
* columns at all will alter the number of rows flowing through the frame.
* So, in this case filtering should not occur. In fact the output columns
* that were set on root above are filtered, but we actually want all the
* virtual elements - so just reset it and proceed as before
* @throws TeiidComponentException
* @throws QueryMetadataException
* @throws QueryPlannerException
*/
static List<? extends Expression> determineSourceOutput(PlanNode root, List<Expression> outputElements, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
PlanNode virtualRoot = root.getLastChild();
if (hasDupRemoval(virtualRoot)) {
// Reset the outputColumns for this source node to be all columns for the virtual group
SymbolMap symbolMap = (SymbolMap) root.getProperty(NodeConstants.Info.SYMBOL_MAP);
if (!symbolMap.asMap().keySet().containsAll(outputElements)) {
outputElements.removeAll(symbolMap.asMap().keySet());
throw new QueryPlannerException(QueryPlugin.Event.TEIID30259, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30259, outputElements));
}
return symbolMap.getKeys();
}
PlanNode limit = NodeEditor.findNodePreOrder(root, NodeConstants.Types.TUPLE_LIMIT, NodeConstants.Types.PROJECT);
if (limit == null) {
return outputElements;
}
// reset the output elements to be the output columns + what's required by the sort
PlanNode sort = NodeEditor.findNodePreOrder(limit, NodeConstants.Types.SORT, NodeConstants.Types.PROJECT);
if (sort == null) {
return outputElements;
}
PlanNode access = NodeEditor.findParent(sort, NodeConstants.Types.ACCESS);
if (sort.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT) || (access != null && capFinder != null && CapabilitiesUtil.supports(Capability.QUERY_ORDERBY_UNRELATED, RuleRaiseAccess.getModelIDFromAccess(access, metadata), metadata, capFinder))) {
return outputElements;
}
OrderBy sortOrder = (OrderBy) sort.getProperty(NodeConstants.Info.SORT_ORDER);
List<Expression> topCols = FrameUtil.findTopCols(sort);
SymbolMap symbolMap = (SymbolMap) root.getProperty(NodeConstants.Info.SYMBOL_MAP);
List<ElementSymbol> symbolOrder = symbolMap.getKeys();
for (OrderByItem item : sortOrder.getOrderByItems()) {
final Expression expr = item.getSymbol();
int index = topCols.indexOf(expr);
if (index < 0) {
continue;
}
ElementSymbol symbol = symbolOrder.get(index);
if (!outputElements.contains(symbol)) {
outputElements.add(symbol);
}
}
return outputElements;
}
use of org.teiid.query.sql.util.SymbolMap in project teiid by teiid.
the class TriggerActionPlanner method rewritePlan.
/**
* look for the simple case of a mapping to a single insert statement trigger action - and reconstruct the plan as a single insert
* TODO: need internal primitives for delete/update batching in a loop for delete/update cases
*/
private ProcessorPlan rewritePlan(TriggerAction ta, IDGenerator idGenerator, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord, CommandContext context, QueryCommand query, Map<ElementSymbol, Expression> mapping, Insert insert) throws QueryMetadataException, QueryResolverException, TeiidComponentException, QueryPlannerException {
if (ta.getBlock().getStatements().size() != 1) {
return null;
}
Statement s = ta.getBlock().getStatements().get(0);
if (!(s instanceof CommandStatement)) {
return null;
}
CommandStatement cs = (CommandStatement) s;
if (!(cs.getCommand() instanceof Insert)) {
return null;
}
Insert mapped = (Insert) cs.getCommand();
if (mapped.getQueryExpression() != null) {
return null;
}
if (insert.getQueryExpression() != null) {
// use a unique inline view name to make the final remapping easier
GroupSymbol group = new GroupSymbol("X");
Collection<GroupSymbol> groups = GroupCollectorVisitor.getGroups(query, true);
for (int i = 0; groups.contains(group); i++) {
group.setName("X_" + i);
}
List<Expression> projectedSymbols = query.getProjectedSymbols();
Query queryExpression = QueryRewriter.createInlineViewQuery(group, query, metadata, projectedSymbols);
List<Expression> viewSymbols = new ArrayList<Expression>(queryExpression.getSelect().getSymbols());
// switch to the values
queryExpression.getSelect().clearSymbols();
List<Expression> values = mapped.getValues();
queryExpression.getSelect().addSymbols(values);
values.clear();
// update the mapping to the view symbols
for (int i = 0; i < projectedSymbols.size(); i++) {
ElementSymbol es = insert.getVariables().get(i);
mapping.put(new ElementSymbol(es.getShortName(), new GroupSymbol(SQLConstants.Reserved.NEW)), SymbolMap.getExpression(viewSymbols.get(i)));
}
// map to the query form - changes references back to element form
SymbolMap queryMapping = new SymbolMap();
queryMapping.asUpdatableMap().putAll(mapping);
ExpressionMappingVisitor visitor = new RuleMergeCriteria.ReferenceReplacementVisitor(queryMapping);
DeepPostOrderNavigator.doVisit(queryExpression.getSelect(), visitor);
// now we can return a plan based off a single insert statement
mapped.setQueryExpression(queryExpression);
return QueryOptimizer.optimizePlan(mapped, metadata, idGenerator, capFinder, analysisRecord, context);
}
List<Expression> values = mapped.getValues();
SymbolMap queryMapping = new SymbolMap();
queryMapping.asUpdatableMap().putAll(mapping);
ExpressionMappingVisitor visitor = new RuleMergeCriteria.ReferenceReplacementVisitor(queryMapping);
Select select = new Select();
select.addSymbols(values);
DeepPostOrderNavigator.doVisit(select, visitor);
values.clear();
for (Expression ex : select.getSymbols()) {
try {
values.add(QueryRewriter.rewriteExpression(SymbolMap.getExpression(ex), context, metadata));
} catch (TeiidProcessingException e) {
throw new QueryPlannerException(e);
}
}
return QueryOptimizer.optimizePlan(mapped, metadata, idGenerator, capFinder, analysisRecord, context);
}
Aggregations