use of org.teiid.query.sql.lang.Criteria 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.lang.Criteria in project teiid by teiid.
the class JoinRegion method getJoinCriteriaForGroups.
// TODO: this should be better than a linear search
protected List<PlanNode> getJoinCriteriaForGroups(Set<GroupSymbol> groups, Collection<PlanNode> nodes) {
List<PlanNode> result = new LinkedList<PlanNode>();
for (PlanNode critNode : nodes) {
if (groups.containsAll(critNode.getGroups())) {
Criteria crit = (Criteria) critNode.getProperty(Info.SELECT_CRITERIA);
if (crit instanceof CompareCriteria && ((CompareCriteria) crit).isOptional()) {
continue;
}
result.add(critNode);
}
}
return result;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RuleAccessPatternValidation method validateAccessPatterns.
/**
* @param node
* @throws QueryPlannerException
*/
private void validateAccessPatterns(PlanNode node) throws QueryPlannerException {
if (!node.hasCollectionProperty(NodeConstants.Info.ACCESS_PATTERNS)) {
return;
}
Criteria criteria = null;
if (node.hasProperty(NodeConstants.Info.ATOMIC_REQUEST)) {
Object req = node.getProperty(NodeConstants.Info.ATOMIC_REQUEST);
if (req instanceof Insert) {
return;
}
if (req instanceof Delete) {
criteria = ((Delete) req).getCriteria();
} else if (req instanceof Update) {
criteria = ((Update) req).getCriteria();
}
}
List accessPatterns = (List) node.getProperty(NodeConstants.Info.ACCESS_PATTERNS);
if (criteria != null) {
for (Criteria crit : Criteria.separateCriteriaByAnd(criteria)) {
Collection<ElementSymbol> elements = ElementCollectorVisitor.getElements(crit, true);
if (RulePushSelectCriteria.satisfyAccessPatterns(accessPatterns, elements)) {
return;
}
}
}
Object groups = node.getGroups();
throw new QueryPlannerException(QueryPlugin.Event.TEIID30278, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30278, new Object[] { groups, accessPatterns }));
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RuleApplySecurity method execute.
@Override
public PlanNode execute(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
try {
for (PlanNode sourceNode : NodeEditor.findAllNodes(plan, NodeConstants.Types.SOURCE)) {
GroupSymbol group = sourceNode.getGroups().iterator().next();
if (!RowBasedSecurityHelper.applyRowSecurity(metadata, group, context)) {
continue;
}
List<ElementSymbol> cols = null;
Command command = (Command) sourceNode.getProperty(Info.VIRTUAL_COMMAND);
if (group.isProcedure()) {
if (command == null) {
// proc relational, will instead apply at the proc level
continue;
}
if (cols == null) {
cols = (List) command.getProjectedSymbols();
}
} else if (command != null && !command.returnsResultSet()) {
// should be handled in the planner
continue;
}
if (cols == null) {
cols = ResolverUtil.resolveElementsInGroup(group, metadata);
}
// apply masks first
List<? extends Expression> masked = ColumnMaskingHelper.maskColumns(cols, group, metadata, context);
Map<ElementSymbol, Expression> mapping = null;
// TODO: we don't actually allow window function masks yet becuase they won't pass
// validation. but if we do, we need to check for them here
List<WindowFunction> windowFunctions = new ArrayList<WindowFunction>(2);
for (int i = 0; i < masked.size(); i++) {
Expression maskedCol = masked.get(i);
AggregateSymbolCollectorVisitor.getAggregates(maskedCol, null, null, null, windowFunctions, null);
if (maskedCol.equals(cols.get(i))) {
continue;
}
if (mapping == null) {
mapping = new HashMap<ElementSymbol, Expression>();
}
mapping.put(cols.get(i), maskedCol);
}
PlanNode parentJoin = NodeEditor.findParent(sourceNode.getParent(), NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE);
if (mapping != null) {
// some element symbol has been replaced
PlanNode project = null;
if (group.isProcedure()) {
project = NodeEditor.findParent(sourceNode, NodeConstants.Types.PROJECT);
project.setProperty(NodeConstants.Info.PROJECT_COLS, masked);
}
if (windowFunctions.isEmpty() && RuleMergeVirtual.checkProjectedSymbols(group, parentJoin, metadata, masked, Collections.singleton(group), true)) {
if (!group.isProcedure()) {
// just upwardly project - TODO: we could also handle some subquery simple projection situations here
FrameUtil.convertFrame(sourceNode.getParent(), group, Collections.singleton(group), mapping, metadata);
}
} else {
if (!group.isProcedure()) {
project = RelationalPlanner.createProjectNode(masked);
}
rules.getPlanner().planSubqueries(sourceNode.getGroups(), project, project.getSubqueryContainers(), true);
project.addGroups(GroupsUsedByElementsVisitor.getGroups(project.getCorrelatedReferenceElements()));
if (!group.isProcedure()) {
// we need to insert a view to give a single place to evaluate the subqueries
PlanNode root = sourceNode;
if (sourceNode.getParent().getType() == NodeConstants.Types.ACCESS) {
root = sourceNode.getParent();
}
root.addAsParent(project);
addView(metadata, context, group, cols, masked, project);
parentJoin = null;
}
}
if (!windowFunctions.isEmpty() && project != null) {
project.setProperty(Info.HAS_WINDOW_FUNCTIONS, true);
}
}
// logically filters are applied below masking
Criteria filter = RowBasedSecurityHelper.getRowBasedFilters(metadata, group, context, false);
if (filter == null) {
continue;
}
List<Criteria> crits = Criteria.separateCriteriaByAnd(filter);
PlanNode root = sourceNode;
if (sourceNode.getParent().getType() == NodeConstants.Types.ACCESS) {
root = sourceNode.getParent();
}
PlanNode parent = null;
for (Criteria crit : crits) {
PlanNode critNode = RelationalPlanner.createSelectNode(crit, false);
if (parent == null) {
parent = critNode;
}
rules.getPlanner().planSubqueries(sourceNode.getGroups(), critNode, critNode.getSubqueryContainers(), true);
critNode.addGroups(GroupsUsedByElementsVisitor.getGroups(critNode.getCorrelatedReferenceElements()));
root.addAsParent(critNode);
}
if (!RuleMergeVirtual.checkJoinCriteria(parent, group, parentJoin)) {
PlanNode project = RelationalPlanner.createProjectNode(cols);
parent.addAsParent(project);
// a view is needed to keep the logical placement of the criteria
addView(metadata, context, group, cols, cols, project);
}
}
} catch (TeiidProcessingException e) {
throw new QueryPlannerException(e);
}
return plan;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class QueryParser method parseCriteria.
/**
* Takes a SQL string representing an SQL criteria (i.e. just the WHERE
* clause) and returns the object representation.
* @param sql SQL criteria (WHERE clause) string
* @return Criteria SQL object representation
* @throws QueryParserException if parsing fails
* @throws IllegalArgumentException if sql is null
*/
public Criteria parseCriteria(String sql) throws QueryParserException {
if (sql == null) {
// $NON-NLS-1$
throw new IllegalArgumentException(QueryPlugin.Util.getString("QueryParser.nullSqlCrit"));
}
ParseInfo dummyInfo = new ParseInfo();
Criteria result = null;
try {
result = getSqlParser(sql).criteria(dummyInfo);
} catch (ParseException pe) {
throw convertParserException(pe);
} finally {
tm.reinit();
}
return result;
}
Aggregations