Search in sources :

Example 1 with ExpressionMappingVisitor

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;
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) Expression(org.teiid.query.sql.symbol.Expression) Constant(org.teiid.query.sql.symbol.Constant) ExpressionMappingVisitor(org.teiid.query.sql.visitor.ExpressionMappingVisitor)

Example 2 with ExpressionMappingVisitor

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;
            }
    }
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) List(java.util.List) ArrayList(java.util.ArrayList) QueryMetadataInterface(org.teiid.query.metadata.QueryMetadataInterface) SymbolMap(org.teiid.query.sql.util.SymbolMap) ExpressionMappingVisitor(org.teiid.query.sql.visitor.ExpressionMappingVisitor) Evaluatable(org.teiid.query.sql.lang.SubqueryContainer.Evaluatable) Map(java.util.Map) HashMap(java.util.HashMap) SymbolMap(org.teiid.query.sql.util.SymbolMap)

Example 3 with ExpressionMappingVisitor

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;
}
Also used : ExpressionMappingVisitor(org.teiid.query.sql.visitor.ExpressionMappingVisitor) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) SymbolMap(org.teiid.query.sql.util.SymbolMap)

Example 4 with ExpressionMappingVisitor

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);
}
Also used : ExpressionMappingVisitor(org.teiid.query.sql.visitor.ExpressionMappingVisitor) Expression(org.teiid.query.sql.symbol.Expression) DataPolicyMetadata(org.teiid.adminapi.impl.DataPolicyMetadata) LanguageObject(org.teiid.query.sql.LanguageObject) DataPolicy(org.teiid.adminapi.DataPolicy) Map(java.util.Map) HashMap(java.util.HashMap) PermissionMetaData(org.teiid.adminapi.impl.DataPolicyMetadata.PermissionMetaData)

Example 5 with ExpressionMappingVisitor

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;
}
Also used : SearchedCaseExpression(org.teiid.query.sql.symbol.SearchedCaseExpression) Expression(org.teiid.query.sql.symbol.Expression) ArrayList(java.util.ArrayList) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) DataPolicy(org.teiid.adminapi.DataPolicy) ExpressionMappingVisitor(org.teiid.query.sql.visitor.ExpressionMappingVisitor)

Aggregations

ExpressionMappingVisitor (org.teiid.query.sql.visitor.ExpressionMappingVisitor)13 Expression (org.teiid.query.sql.symbol.Expression)6 SymbolMap (org.teiid.query.sql.util.SymbolMap)6 ArrayList (java.util.ArrayList)4 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)3 HashMap (java.util.HashMap)2 Map (java.util.Map)2 DataPolicy (org.teiid.adminapi.DataPolicy)2 TeiidRuntimeException (org.teiid.core.TeiidRuntimeException)2 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)2 RuleMergeCriteria (org.teiid.query.optimizer.relational.rules.RuleMergeCriteria)2 LanguageObject (org.teiid.query.sql.LanguageObject)2 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)2 Reference (org.teiid.query.sql.symbol.Reference)2 UpdateMapping (org.teiid.query.validator.UpdateValidator.UpdateMapping)2 List (java.util.List)1 DataPolicyMetadata (org.teiid.adminapi.impl.DataPolicyMetadata)1 PermissionMetaData (org.teiid.adminapi.impl.DataPolicyMetadata.PermissionMetaData)1 QueryMetadataException (org.teiid.api.exception.query.QueryMetadataException)1 QueryPlannerException (org.teiid.api.exception.query.QueryPlannerException)1