Search in sources :

Example 26 with PlanNode

use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.

the class RuleMergeCriteria method execute.

/**
 * @see OptimizerRule#execute(PlanNode, QueryMetadataInterface, RuleStack)
 */
public PlanNode execute(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, TeiidComponentException {
    dependent = false;
    // Find strings of criteria and merge them, removing duplicates
    List<PlanNode> criteriaChains = new ArrayList<PlanNode>();
    findCriteriaChains(plan, criteriaChains, analysisRecord);
    // Merge chains
    for (PlanNode critNode : criteriaChains) {
        mergeChain(critNode, metadata);
    }
    if (dependent) {
        // rules.push(new RuleAssignOutputElements(true));
        rules.push(RuleConstants.PUSH_SELECT_CRITERIA);
    }
    return plan;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) ArrayList(java.util.ArrayList)

Example 27 with PlanNode

use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.

the class RuleMergeVirtual method doMerge.

static PlanNode doMerge(PlanNode frame, PlanNode root, boolean beforeDecomposeJoin, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
    if (frame.hasBooleanProperty(Info.NO_UNNEST)) {
        return root;
    }
    GroupSymbol virtualGroup = frame.getGroups().iterator().next();
    // check to see if frame represents a proc relational query.
    if (virtualGroup.isProcedure()) {
        return root;
    }
    List<PlanNode> sources = NodeEditor.findAllNodes(frame.getFirstChild(), NodeConstants.Types.SOURCE, NodeConstants.Types.SOURCE);
    SymbolMap references = (SymbolMap) frame.getProperty(NodeConstants.Info.CORRELATED_REFERENCES);
    if (references != null) {
        if (!sources.isEmpty()) {
            // correlated nested table commands should not be merged
            return root;
        }
        // this is ok only if all of the references go above the correlating join
        // currently this check is simplistic - just look at the parent join more nested scenarios won't work
        PlanNode parentJoin = NodeEditor.findParent(frame, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE | NodeConstants.Types.GROUP);
        if (parentJoin != null && !parentJoin.getGroups().containsAll(GroupsUsedByElementsVisitor.getGroups(references.getValues()))) {
            return root;
        }
    }
    PlanNode parentProject = NodeEditor.findParent(frame, NodeConstants.Types.PROJECT);
    // Check whether the upper frame is a SELECT INTO
    if (parentProject.getProperty(NodeConstants.Info.INTO_GROUP) != null) {
        return root;
    }
    if (!FrameUtil.canConvertAccessPatterns(frame)) {
        return root;
    }
    PlanNode projectNode = frame.getFirstChild();
    // Check if lower frame has only a stored procedure execution - this cannot be merged to parent frame
    if (FrameUtil.isProcedure(projectNode)) {
        return root;
    }
    SymbolMap symbolMap = (SymbolMap) frame.getProperty(NodeConstants.Info.SYMBOL_MAP);
    PlanNode sortNode = NodeEditor.findParent(parentProject, NodeConstants.Types.SORT, NodeConstants.Types.SOURCE);
    if (sortNode != null && sortNode.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT)) {
        OrderBy sortOrder = (OrderBy) sortNode.getProperty(NodeConstants.Info.SORT_ORDER);
        boolean unrelated = false;
        for (OrderByItem item : sortOrder.getOrderByItems()) {
            if (!item.isUnrelated()) {
                continue;
            }
            Collection<ElementSymbol> elements = ElementCollectorVisitor.getElements(item.getSymbol(), true);
            for (ElementSymbol elementSymbol : elements) {
                if (virtualGroup.equals(elementSymbol.getGroupSymbol())) {
                    unrelated = true;
                }
            }
        }
        // the lower frame cannot contain DUP_REMOVE, GROUP, UNION if unrelated
        if (unrelated && NodeEditor.findNodePreOrder(frame, NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.PROJECT) != null || NodeEditor.findNodePreOrder(frame, NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE) != null || NodeEditor.findNodePreOrder(frame, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE) != null) {
            return root;
        }
    }
    PlanNode parentJoin = NodeEditor.findParent(frame, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE | NodeConstants.Types.GROUP);
    // 3. if the frame has no sources
    if (projectNode.getType() != NodeConstants.Types.PROJECT || NodeEditor.findNodePreOrder(frame.getFirstChild(), NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE | NodeConstants.Types.JOIN) != null || sources.isEmpty()) {
        PlanNode parentSource = NodeEditor.findParent(parentProject, NodeConstants.Types.SOURCE);
        if (beforeDecomposeJoin && parentSource != null && parentSource.hasProperty(Info.PARTITION_INFO) && !NodeEditor.findAllNodes(frame.getFirstChild(), NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE).isEmpty()) {
            // don't bother to merge until after
            return root;
        }
        root = checkForSimpleProjection(frame, root, parentProject, metadata, capFinder);
        if (frame.getParent() == null || !sources.isEmpty() || projectNode.getType() != NodeConstants.Types.PROJECT || parentJoin == null) {
            // only consider no sources when the frame is simple and there is a parent join
            return root;
        }
        if (sources.isEmpty() && parentJoin != null) {
            JoinType jt = (JoinType) parentJoin.getProperty(Info.JOIN_TYPE);
            if (jt.isOuter()) {
                // cannot remove if the no source side is an outer side, or if it can change the meaning of the plan
                return root;
            }
            PlanNode joinToTest = parentJoin;
            while (joinToTest != null) {
                if (FrameUtil.findJoinSourceNode(joinToTest.getFirstChild()).getGroups().contains(virtualGroup)) {
                    // scan all sources under the other side as there could be a join structure
                    for (PlanNode node : NodeEditor.findAllNodes(joinToTest.getLastChild(), NodeConstants.Types.SOURCE, NodeConstants.Types.SOURCE)) {
                        SymbolMap map = (SymbolMap) node.getProperty(NodeConstants.Info.CORRELATED_REFERENCES);
                        if (map != null && GroupsUsedByElementsVisitor.getGroups(map.getValues()).contains(virtualGroup)) {
                            // TODO: we don't have the logic yet to then replace the correlated references
                            return root;
                        }
                    }
                }
                joinToTest = NodeEditor.findParent(joinToTest, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE | NodeConstants.Types.GROUP);
            }
        }
    }
    if (!checkJoinCriteria(frame.getFirstChild(), virtualGroup, parentJoin)) {
        return root;
    }
    // we don't have to check for null dependent with no source without criteria since there must be a row
    if (!checkProjectedSymbols(projectNode, virtualGroup, parentJoin, metadata, sources, !sources.isEmpty() || frame.getParent() != parentJoin, parentProject)) {
        // TODO: propagate constants if just inhibited by subquery/non-deterministic expressions
        return root;
    }
    // Otherwise merge should work
    // Convert parent frame before merge
    Set<GroupSymbol> groups = Collections.emptySet();
    if (!sources.isEmpty()) {
        groups = FrameUtil.findJoinSourceNode(projectNode).getGroups();
    } else if (references != null) {
        // convert from correlated form to regular references
        RuleMergeCriteria.ReferenceReplacementVisitor rrv = new RuleMergeCriteria.ReferenceReplacementVisitor(references);
        for (Map.Entry<ElementSymbol, Expression> entry : symbolMap.asUpdatableMap().entrySet()) {
            if (entry.getValue() instanceof Reference) {
                Expression ex = rrv.replaceExpression(entry.getValue());
                entry.setValue(ex);
            } else {
                PreOrPostOrderNavigator.doVisit(entry.getValue(), rrv, PreOrPostOrderNavigator.PRE_ORDER);
            }
        }
    }
    FrameUtil.convertFrame(frame, virtualGroup, groups, symbolMap.asMap(), metadata);
    PlanNode parentBottom = frame.getParent();
    prepareFrame(frame);
    if (sources.isEmpty() && parentJoin != null) {
        // special handling for no sources
        PlanNode parent = frame;
        List<PlanNode> criteriaNodes = new ArrayList<PlanNode>();
        while (parent.getParent() != parentJoin) {
            parent = parent.getParent();
            if (!parent.hasBooleanProperty(Info.IS_PHANTOM)) {
                criteriaNodes.add(parent);
            }
        }
        PlanNode parentNode = parentJoin.getParent();
        parentJoin.removeChild(parent);
        PlanNode other = parentJoin.getFirstChild();
        NodeEditor.removeChildNode(parentNode, parentJoin);
        JoinType jt = (JoinType) parentJoin.getProperty(Info.JOIN_TYPE);
        if (!jt.isOuter()) {
            // if we are not an outer join then the join/parent criteria is effectively
            // applied to the other side
            List<Criteria> joinCriteria = (List<Criteria>) parentJoin.getProperty(Info.JOIN_CRITERIA);
            if (joinCriteria != null) {
                for (Criteria crit : joinCriteria) {
                    PlanNode critNode = RelationalPlanner.createSelectNode(crit, false);
                    criteriaNodes.add(critNode);
                }
            }
            if (!criteriaNodes.isEmpty()) {
                for (PlanNode selectNode : criteriaNodes) {
                    selectNode.removeAllChildren();
                    selectNode.removeFromParent();
                    other.addAsParent(selectNode);
                }
            }
        }
    } else {
        // Remove top 2 nodes (SOURCE, PROJECT) of virtual group - they're no longer needed
        NodeEditor.removeChildNode(parentBottom, frame);
        NodeEditor.removeChildNode(parentBottom, projectNode);
    }
    return root;
}
Also used : OrderBy(org.teiid.query.sql.lang.OrderBy) ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) Reference(org.teiid.query.sql.symbol.Reference) ArrayList(java.util.ArrayList) JoinType(org.teiid.query.sql.lang.JoinType) SymbolMap(org.teiid.query.sql.util.SymbolMap) Criteria(org.teiid.query.sql.lang.Criteria) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List)

Example 28 with PlanNode

use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.

the class RuleMergeVirtual method distributeDupRemove.

static void distributeDupRemove(QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder, PlanNode unionNode) throws QueryMetadataException, TeiidComponentException {
    PlanNode unionParentSource = NodeEditor.findParent(unionNode, NodeConstants.Types.SOURCE | NodeConstants.Types.SET_OP);
    if (unionNode.hasBooleanProperty(Info.USE_ALL) || unionParentSource == null || unionParentSource.getType() != NodeConstants.Types.SOURCE || !unionParentSource.hasProperty(Info.PARTITION_INFO)) {
        return;
    }
    PlanNode accessNode = NodeEditor.findParent(unionNode, NodeConstants.Types.ACCESS);
    if (accessNode != null) {
        Object mid = RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata);
        if (!CapabilitiesUtil.supports(Capability.QUERY_SELECT_DISTINCT, mid, metadata, capabilitiesFinder)) {
            return;
        }
    }
    // distribute dup remove
    LinkedList<PlanNode> unionChildren = new LinkedList<PlanNode>();
    RulePushAggregates.findUnionChildren(unionChildren, false, unionNode);
    unionNode.setProperty(Info.USE_ALL, true);
    for (PlanNode node : unionChildren) {
        if (node.getType() == NodeConstants.Types.SET_OP) {
            node.setProperty(Info.USE_ALL, false);
        } else {
            PlanNode projectNode = NodeEditor.findNodePreOrder(node, NodeConstants.Types.DUP_REMOVE | NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE);
            if (projectNode != null && projectNode.getType() == NodeConstants.Types.PROJECT) {
                accessNode = NodeEditor.findParent(projectNode, NodeConstants.Types.ACCESS);
                PlanNode dup = NodeFactory.getNewNode(NodeConstants.Types.DUP_REMOVE);
                if (accessNode == null) {
                    projectNode.addAsParent(dup);
                } else {
                    Object mid = RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata);
                    if (CapabilitiesUtil.supports(Capability.QUERY_SELECT_DISTINCT, mid, metadata, capabilitiesFinder)) {
                        projectNode.addAsParent(dup);
                    } else {
                        accessNode.addAsParent(dup);
                    }
                }
            }
        }
    }
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) LinkedList(java.util.LinkedList)

Example 29 with PlanNode

use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.

the class RuleMergeVirtual method checkProjectedSymbols.

/**
 * Check to ensure that we are not projecting a subquery or null dependent expressions
 * @param parentProject2
 */
private static boolean checkProjectedSymbols(PlanNode projectNode, GroupSymbol virtualGroup, PlanNode parentJoin, QueryMetadataInterface metadata, List<PlanNode> sources, boolean checkForNullDependent, PlanNode parentProject) {
    if (projectNode.hasBooleanProperty(Info.HAS_WINDOW_FUNCTIONS)) {
        boolean allow = false;
        PlanNode source = NodeEditor.findParent(parentProject, NodeConstants.Types.SOURCE);
        if (source != null) {
            PlanNode grandparentProject = NodeEditor.findParent(source, NodeConstants.Types.PROJECT);
            if (grandparentProject != null && grandparentProject.hasProperty(Info.INTO_GROUP)) {
                allow = true;
            }
        }
        if (!allow) {
            return false;
        }
    }
    List<Expression> selectSymbols = (List<Expression>) projectNode.getProperty(NodeConstants.Info.PROJECT_COLS);
    HashSet<GroupSymbol> groups = new HashSet<GroupSymbol>();
    for (PlanNode sourceNode : sources) {
        groups.addAll(sourceNode.getGroups());
    }
    return checkProjectedSymbols(virtualGroup, parentJoin, metadata, selectSymbols, groups, checkForNullDependent);
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 30 with PlanNode

use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.

the class RulePlaceAccess method addAlias.

/**
 * Ensures that the group is uniquely named within the current optimizer run
 *
 * @param sourceNode
 * @param groups
 * @param metadata
 * @throws QueryMetadataException
 * @throws TeiidComponentException
 * @throws QueryPlannerException
 */
private void addAlias(PlanNode sourceNode, CommandContext cc, Set<String> groups, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    // select with no from
    if (sourceNode.getGroups().isEmpty()) {
        return;
    }
    // insert, update, delete, create, etc.
    if (FrameUtil.getNonQueryCommand(sourceNode.getParent()) != null) {
        return;
    }
    PlanNode parentProject = NodeEditor.findParent(sourceNode, NodeConstants.Types.PROJECT);
    // the source over a project into cannot conflict with any other groups
    if (parentProject.hasProperty(NodeConstants.Info.INTO_GROUP)) {
        return;
    }
    GroupSymbol group = sourceNode.getGroups().iterator().next();
    if (groups.add(group.getName())) {
        if (group.getDefinition() != null) {
            cc.getAliasMapping().put(group.getName(), group.getName());
        }
        // this is the first instance of the group
        return;
    }
    List<PlanNode> childProjects = null;
    if (sourceNode.getChildCount() > 0) {
        childProjects = NodeEditor.findAllNodes(sourceNode.getFirstChild(), NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE);
    }
    GroupSymbol newGroup = recontextSymbol(group, groups);
    if (group.getDefinition() != null) {
        cc.getAliasMapping().put(newGroup.getName(), group.getName());
    }
    // the expressions in the map will all be element symbols
    Map<ElementSymbol, Expression> replacementSymbols = FrameUtil.buildSymbolMap(group, newGroup, metadata);
    FrameUtil.convertFrame(sourceNode, group, new HashSet<GroupSymbol>(Arrays.asList(newGroup)), replacementSymbols, metadata);
    // correct the lower symbol map
    if (childProjects != null) {
        SymbolMap symbolMap = (SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
        SymbolMap replacementMap = new SymbolMap();
        for (Map.Entry<ElementSymbol, Expression> entry : symbolMap.asMap().entrySet()) {
            replacementMap.addMapping((ElementSymbol) replacementSymbols.get(entry.getKey()), entry.getValue());
        }
        sourceNode.setProperty(NodeConstants.Info.SYMBOL_MAP, replacementMap);
    }
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) SymbolMap(org.teiid.query.sql.util.SymbolMap) Map(java.util.Map) SymbolMap(org.teiid.query.sql.util.SymbolMap)

Aggregations

PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)204 Expression (org.teiid.query.sql.symbol.Expression)50 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)50 ArrayList (java.util.ArrayList)47 List (java.util.List)43 SymbolMap (org.teiid.query.sql.util.SymbolMap)42 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)36 Criteria (org.teiid.query.sql.lang.Criteria)35 LinkedList (java.util.LinkedList)24 CompareCriteria (org.teiid.query.sql.lang.CompareCriteria)24 Test (org.junit.Test)22 HashSet (java.util.HashSet)17 JoinType (org.teiid.query.sql.lang.JoinType)17 LinkedHashSet (java.util.LinkedHashSet)16 CompoundCriteria (org.teiid.query.sql.lang.CompoundCriteria)12 DependentSetCriteria (org.teiid.query.sql.lang.DependentSetCriteria)12 QueryPlannerException (org.teiid.api.exception.query.QueryPlannerException)11 LanguageObject (org.teiid.query.sql.LanguageObject)11 OrderBy (org.teiid.query.sql.lang.OrderBy)10 IsNullCriteria (org.teiid.query.sql.lang.IsNullCriteria)9