use of org.teiid.query.sql.visitor.ExpressionMappingVisitor in project teiid by teiid.
the class JoinUtil method replaceWithNullValues.
private static LanguageObject replaceWithNullValues(final Collection<GroupSymbol> innerGroups, LanguageObject obj) {
ExpressionMappingVisitor emv = new ExpressionMappingVisitor(null) {
public Expression replaceExpression(Expression element) {
if (!(element instanceof ElementSymbol)) {
return element;
}
ElementSymbol symbol = (ElementSymbol) element;
if (innerGroups.contains(symbol.getGroupSymbol())) {
return new Constant(null, symbol.getType());
}
return element;
}
};
if (obj instanceof ElementSymbol) {
return emv.replaceExpression((ElementSymbol) obj);
}
obj = (LanguageObject) obj.clone();
PreOrderNavigator.doVisit(obj, emv);
return obj;
}
use of org.teiid.query.sql.visitor.ExpressionMappingVisitor in project teiid by teiid.
the class RuleCollapseSource method buildQuery.
void buildQuery(PlanNode accessRoot, PlanNode node, Query query, CommandContext context, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
QueryMetadataInterface metadata = context.getMetadata();
// visit source and join nodes as they appear
Object modelID = RuleRaiseAccess.getModelIDFromAccess(accessRoot, metadata);
switch(node.getType()) {
case NodeConstants.Types.JOIN:
{
prepareSubqueries(node.getSubqueryContainers());
JoinType joinType = (JoinType) node.getProperty(NodeConstants.Info.JOIN_TYPE);
List<Criteria> crits = (List<Criteria>) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
if (crits == null || crits.isEmpty()) {
crits = new ArrayList<Criteria>();
} else {
RuleChooseJoinStrategy.filterOptionalCriteria(crits, false);
if (crits.isEmpty() && joinType == JoinType.JOIN_INNER) {
joinType = JoinType.JOIN_CROSS;
}
}
PlanNode left = node.getFirstChild();
PlanNode right = node.getLastChild();
/* special handling is needed to determine criteria placement.
*
* if the join is a left outer join, criteria from the right side will be added to the on clause
*/
Criteria savedCriteria = null;
buildQuery(accessRoot, left, query, context, capFinder);
if (joinType == JoinType.JOIN_LEFT_OUTER) {
savedCriteria = query.getCriteria();
query.setCriteria(null);
}
buildQuery(accessRoot, right, query, context, capFinder);
if (joinType == JoinType.JOIN_LEFT_OUTER) {
moveWhereClauseIntoOnClause(query, crits);
query.setCriteria(savedCriteria);
}
if (joinType == JoinType.JOIN_LEFT_OUTER || joinType == JoinType.JOIN_FULL_OUTER) {
boolean subqueryOn = CapabilitiesUtil.supports(Capability.CRITERIA_ON_SUBQUERY, modelID, metadata, capFinder);
if (!subqueryOn) {
for (SubqueryContainer<?> subqueryContainer : ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(crits)) {
if (subqueryContainer instanceof Evaluatable && subqueryContainer.getCommand().getCorrelatedReferences() == null) {
((Evaluatable) subqueryContainer).setShouldEvaluate(true);
} else {
// $NON-NLS-1$
throw new AssertionError("On clause not expected to contain non-evaluatable subqueries");
}
}
}
}
// Get last two clauses added to the FROM and combine them into a JoinPredicate
From from = query.getFrom();
List<FromClause> clauses = from.getClauses();
int lastClause = clauses.size() - 1;
FromClause clause1 = clauses.get(lastClause - 1);
FromClause clause2 = clauses.get(lastClause);
// so this may not be needed moving forward
if (!joinType.isOuter() && !CapabilitiesUtil.supports(Capability.QUERY_FROM_JOIN_INNER, modelID, metadata, capFinder)) {
joinType = JoinType.JOIN_LEFT_OUTER;
if (!crits.isEmpty()) {
if (!useLeftOuterJoin(query, metadata, crits, right.getGroups())) {
if (!useLeftOuterJoin(query, metadata, crits, left.getGroups())) {
// $NON-NLS-1$
throw new AssertionError("Could not convert inner to outer join.");
}
FromClause temp = clause1;
clause1 = clause2;
clause2 = temp;
}
}
}
// correct the criteria or the join type if necessary
if (joinType != JoinType.JOIN_CROSS && crits.isEmpty()) {
crits.add(QueryRewriter.TRUE_CRITERIA);
} else if (joinType == JoinType.JOIN_CROSS && !crits.isEmpty()) {
joinType = JoinType.JOIN_INNER;
}
JoinPredicate jp = new JoinPredicate(clause1, clause2, joinType, crits);
// Replace last two clauses with new predicate
clauses.remove(lastClause);
clauses.set(lastClause - 1, jp);
return;
}
case NodeConstants.Types.SOURCE:
{
boolean pushedTableProcedure = false;
GroupSymbol symbol = node.getGroups().iterator().next();
if (node.hasBooleanProperty(Info.INLINE_VIEW)) {
PlanNode child = node.getFirstChild();
QueryCommand newQuery = createQuery(context, capFinder, accessRoot, child);
// ensure that the group is consistent
SubqueryFromClause sfc = new SubqueryFromClause(symbol, newQuery);
SymbolMap map = (SymbolMap) node.getProperty(NodeConstants.Info.CORRELATED_REFERENCES);
if (map != null) {
ExpressionMappingVisitor visitor = new RuleMergeCriteria.ReferenceReplacementVisitor(map);
DeepPostOrderNavigator.doVisit(newQuery, visitor);
sfc.setLateral(true);
}
query.getFrom().addClause(sfc);
// ensure that the column names are consistent
Query q = newQuery.getProjectedQuery();
List<Expression> expressions = q.getSelect().getSymbols();
List<Expression> outputCols = (List<Expression>) node.getProperty(NodeConstants.Info.OUTPUT_COLS);
Map<Expression, String> corrected = null;
for (int i = 0; i < outputCols.size(); i++) {
Expression ex = expressions.get(i);
Expression expected = outputCols.get(i);
String name = Symbol.getShortName(expected);
if (!name.equals(Symbol.getShortName(ex))) {
expressions.set(i, new AliasSymbol(name, SymbolMap.getExpression(ex)));
corrected = new HashMap<Expression, String>();
corrected.put(ex, name);
}
}
if (corrected != null && newQuery.getOrderBy() != null) {
for (OrderByItem item : newQuery.getOrderBy().getOrderByItems()) {
String name = corrected.get(item.getSymbol());
if (name != null) {
item.setSymbol(new AliasSymbol(name, SymbolMap.getExpression(item.getSymbol())));
}
}
}
// so we'll unwrap that here
if (newQuery instanceof Query) {
q = (Query) newQuery;
if (q.getFrom() != null && q.getFrom().getClauses().size() == 1 && q.getFrom().getClauses().get(0) instanceof SubqueryFromClause) {
SubqueryFromClause nested = (SubqueryFromClause) q.getFrom().getClauses().get(0);
if (nested.getCommand() instanceof StoredProcedure) {
sfc.setCommand(nested.getCommand());
}
}
}
return;
}
// handle lateral join of a procedure
Command command = (Command) node.getProperty(NodeConstants.Info.VIRTUAL_COMMAND);
if (command instanceof StoredProcedure) {
StoredProcedure storedProcedure = (StoredProcedure) command;
storedProcedure.setPushedInQuery(true);
SubqueryFromClause subqueryFromClause = new SubqueryFromClause(symbol, storedProcedure);
// TODO: it would be better to directly add
query.getFrom().addClause(subqueryFromClause);
pushedTableProcedure = true;
}
PlanNode subPlan = (PlanNode) node.getProperty(Info.SUB_PLAN);
if (subPlan != null) {
Map<GroupSymbol, PlanNode> subPlans = (Map<GroupSymbol, PlanNode>) accessRoot.getProperty(Info.SUB_PLANS);
if (subPlans == null) {
subPlans = new HashMap<GroupSymbol, PlanNode>();
accessRoot.setProperty(Info.SUB_PLANS, subPlans);
}
subPlans.put(symbol, subPlan);
}
if (!pushedTableProcedure) {
query.getFrom().addGroup(symbol);
}
break;
}
}
for (PlanNode childNode : node.getChildren()) {
buildQuery(accessRoot, childNode, query, context, capFinder);
}
switch(node.getType()) {
case NodeConstants.Types.SELECT:
{
Criteria crit = (Criteria) node.getProperty(NodeConstants.Info.SELECT_CRITERIA);
prepareSubqueries(node.getSubqueryContainers());
if (!node.hasBooleanProperty(NodeConstants.Info.IS_HAVING)) {
query.setCriteria(CompoundCriteria.combineCriteria(query.getCriteria(), crit));
} else {
query.setHaving(CompoundCriteria.combineCriteria(query.getHaving(), crit));
}
break;
}
case NodeConstants.Types.SORT:
{
prepareSubqueries(node.getSubqueryContainers());
processOrderBy(node, query, modelID, context, capFinder);
break;
}
case NodeConstants.Types.DUP_REMOVE:
{
boolean distinct = true;
PlanNode grouping = NodeEditor.findNodePreOrder(node.getFirstChild(), NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE);
if (grouping != null) {
List groups = (List) grouping.getProperty(NodeConstants.Info.GROUP_COLS);
if (groups == null || groups.isEmpty()) {
distinct = false;
}
}
query.getSelect().setDistinct(distinct);
break;
}
case NodeConstants.Types.GROUP:
{
List groups = (List) node.getProperty(NodeConstants.Info.GROUP_COLS);
if (groups != null && !groups.isEmpty()) {
query.setGroupBy(new GroupBy(groups));
if (node.hasBooleanProperty(Info.ROLLUP)) {
query.getGroupBy().setRollup(true);
}
}
break;
}
case NodeConstants.Types.TUPLE_LIMIT:
{
processLimit(node, query, metadata);
break;
}
}
}
use of org.teiid.query.sql.visitor.ExpressionMappingVisitor in project teiid by teiid.
the class RelationalPlanner method attachGrouping.
/**
* Attach a grouping node at top of tree.
* @param plan Existing plan
* @param aggs
* @param parentOrderBy
* @param groupBy Group by clause, which may be null
* @return Updated plan
* @throws TeiidComponentException
* @throws QueryMetadataException
*/
private PlanNode attachGrouping(PlanNode plan, Query query, Collection<AggregateSymbol> aggs, List<OrderBy> parentOrderBys) throws QueryMetadataException, TeiidComponentException {
GroupBy groupBy = query.getGroupBy();
List<Expression> groupingCols = null;
PlanNode groupNode = NodeFactory.getNewNode(NodeConstants.Types.GROUP);
if (groupBy != null) {
groupingCols = groupBy.getSymbols();
if (groupBy.isRollup()) {
groupNode.setProperty(Info.ROLLUP, Boolean.TRUE);
}
}
Map<Expression, ElementSymbol> mapping = buildGroupingNode(aggs, groupingCols, groupNode, this.context, this.idGenerator).inserseMapping();
attachLast(groupNode, plan);
// special handling if there is an expression in the grouping. we need to create the appropriate
// correlations
Map<Expression, Expression> subMapping = null;
for (Map.Entry<Expression, ElementSymbol> entry : mapping.entrySet()) {
if (entry.getKey() instanceof ElementSymbol) {
continue;
}
ExpressionMappingVisitor emv = new ExpressionMappingVisitor(null) {
@Override
public Expression replaceExpression(Expression element) {
if (element instanceof ElementSymbol) {
return new Reference((ElementSymbol) element);
}
return element;
}
};
Expression key = (Expression) entry.getKey().clone();
PostOrderNavigator.doVisit(key, emv);
if (subMapping == null) {
subMapping = new HashMap<Expression, Expression>();
}
ElementSymbol value = entry.getValue().clone();
value.setIsExternalReference(true);
subMapping.put(key, new Reference(value));
}
replaceExpressions(query.getHaving(), mapping, subMapping);
replaceExpressions(query.getSelect(), mapping, subMapping);
replaceExpressions(query.getOrderBy(), mapping, subMapping);
if (parentOrderBys != null) {
for (OrderBy parentOrderBy : parentOrderBys) {
replaceExpressions(parentOrderBy, mapping, subMapping);
}
}
// Mark in hints
hints.hasAggregates = true;
return groupNode;
}
use of org.teiid.query.sql.visitor.ExpressionMappingVisitor in project teiid by teiid.
the class RowBasedSecurityHelper method getRowBasedFilters.
public static Criteria getRowBasedFilters(QueryMetadataInterface metadata, final GroupSymbol group, CommandContext cc, boolean constraintsOnly) throws QueryMetadataException, TeiidComponentException, TeiidProcessingException {
Map<String, DataPolicy> policies = cc.getAllowedDataPolicies();
if (policies == null || policies.isEmpty()) {
return null;
}
boolean user = false;
ArrayList<Criteria> crits = null;
Object metadataID = group.getMetadataID();
String fullName = metadata.getFullName(metadataID);
for (Map.Entry<String, DataPolicy> entry : policies.entrySet()) {
DataPolicyMetadata dpm = (DataPolicyMetadata) entry.getValue();
PermissionMetaData pmd = dpm.getPermissionMap().get(fullName);
if (pmd == null) {
continue;
}
String filterString = pmd.getCondition();
if (filterString == null) {
continue;
}
if (constraintsOnly && Boolean.FALSE.equals(pmd.getConstraint())) {
continue;
}
Criteria filter = resolveCondition(metadata, group, fullName, entry, pmd, filterString);
if (!dpm.isAnyAuthenticated()) {
user = true;
}
if (crits == null) {
crits = new ArrayList<Criteria>(2);
}
crits.add(filter);
}
if (crits == null || crits.isEmpty()) {
return null;
}
Criteria result = null;
if (crits.size() == 1) {
result = crits.get(0);
} else {
result = new CompoundCriteria(CompoundCriteria.OR, crits);
}
if (group.getDefinition() != null) {
ExpressionMappingVisitor emv = new RecontextVisitor(group);
PreOrPostOrderNavigator.doVisit(result, emv, PreOrPostOrderNavigator.PRE_ORDER, true);
}
// we treat this as user deterministic since the data roles won't change. this may change if the logic becomes dynamic
if (user) {
cc.setDeterminismLevel(Determinism.USER_DETERMINISTIC);
}
Expression ex = QueryRewriter.rewriteExpression(result, cc, metadata, true);
if (ex instanceof Criteria) {
return (Criteria) ex;
}
return QueryRewriter.rewriteCriteria(new ExpressionCriteria(ex), cc, metadata);
}
use of org.teiid.query.sql.visitor.ExpressionMappingVisitor in project teiid by teiid.
the class ColumnMaskingHelper method maskColumns.
public static List<? extends Expression> maskColumns(List<ElementSymbol> cols, final GroupSymbol group, QueryMetadataInterface metadata, CommandContext cc) throws QueryMetadataException, TeiidComponentException, TeiidProcessingException {
Map<String, DataPolicy> policies = cc.getAllowedDataPolicies();
if (policies == null || policies.isEmpty()) {
return cols;
}
ArrayList<Expression> result = new ArrayList<Expression>(cols.size());
ExpressionMappingVisitor emv = new RowBasedSecurityHelper.RecontextVisitor(group);
GroupSymbol gs = group;
if (gs.getDefinition() != null) {
gs = new GroupSymbol(metadata.getFullName(group.getMetadataID()));
gs.setMetadataID(group.getMetadataID());
}
for (int i = 0; i < cols.size(); i++) {
result.add(maskColumn(cols.get(i), gs, metadata, emv, policies, cc));
}
return result;
}
Aggregations