Search in sources :

Example 1 with AccessPattern

use of org.teiid.query.resolver.util.AccessPattern in project teiid by teiid.

the class TestAccessPattern method testOrdering.

public void testOrdering() {
    AccessPattern ap1 = new AccessPattern(createElements(1));
    AccessPattern ap2 = new AccessPattern(createElements(2));
    List accessPatterns = new ArrayList();
    accessPatterns.add(ap2);
    accessPatterns.add(ap1);
    Collections.sort(accessPatterns);
    assertEquals(ap1, accessPatterns.get(0));
}
Also used : AccessPattern(org.teiid.query.resolver.util.AccessPattern) ArrayList(java.util.ArrayList) List(java.util.List) ArrayList(java.util.ArrayList)

Example 2 with AccessPattern

use of org.teiid.query.resolver.util.AccessPattern in project teiid by teiid.

the class TestAccessPattern method testClone.

public void testClone() {
    AccessPattern ap2 = new AccessPattern(createElements(2));
    AccessPattern clone = (AccessPattern) ap2.clone();
    assertNotSame(ap2, clone);
    assertEquals(ap2.getUnsatisfied(), clone.getUnsatisfied());
}
Also used : AccessPattern(org.teiid.query.resolver.util.AccessPattern)

Example 3 with AccessPattern

use of org.teiid.query.resolver.util.AccessPattern in project teiid by teiid.

the class RuleChooseDependent method fullyPush.

/**
 * Check for fully pushable dependent joins
 * currently we only look for the simplistic scenario where there are no intervening
 * nodes above the dependent side
 * @param independentExpressions
 */
private boolean fullyPush(PlanNode sourceNode, PlanNode joinNode, QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder, CommandContext context, PlanNode indNode, RuleStack rules, MakeDep makeDep, AnalysisRecord analysisRecord, List independentExpressions) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    if (sourceNode.getType() != NodeConstants.Types.ACCESS) {
        // don't remove as we may raise an access node to make this possible
        return false;
    }
    Object modelID = RuleRaiseAccess.getModelIDFromAccess(sourceNode, metadata);
    boolean hasHint = false;
    if (makeDep != null && makeDep.getJoin() != null) {
        if (!makeDep.getJoin()) {
            // $NON-NLS-1$ //$NON-NLS-2$
            sourceNode.recordDebugAnnotation("cannot pushdown dependent join", modelID, "honoring hint", analysisRecord, null);
            return false;
        }
        hasHint = true;
    }
    if (!CapabilitiesUtil.supports(Capability.FULL_DEPENDENT_JOIN, modelID, metadata, capabilitiesFinder)) {
        if (hasHint) {
            // $NON-NLS-1$ //$NON-NLS-2$
            sourceNode.recordDebugAnnotation("cannot pushdown dependent join", modelID, "dependent join pushdown needs enabled at the source", analysisRecord, null);
        }
        return false;
    }
    List<? extends Expression> projected = (List<? extends Expression>) indNode.getProperty(Info.OUTPUT_COLS);
    if (projected == null) {
        PlanNode plan = sourceNode;
        while (plan.getParent() != null) {
            plan = plan.getParent();
        }
        new RuleAssignOutputElements(false).execute(plan, metadata, capabilitiesFinder, null, AnalysisRecord.createNonRecordingRecord(), context);
        projected = (List<? extends Expression>) indNode.getProperty(Info.OUTPUT_COLS);
    }
    if (!hasHint) {
        // require no lobs
        for (Expression ex : projected) {
            if (DataTypeManager.isLOB(ex.getClass())) {
                return false;
            }
        }
        // old optimizer tests had no buffermanager
        if (context.getBufferManager() == null) {
            return false;
        }
        if (makeDep != null && makeDep.getMax() != null) {
            // if the user specifies a max, it's best to just use a regular dependent join
            return false;
        }
    }
    /*
    	 * check to see how far the access node can be raised 
    	 */
    PlanNode tempAccess = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
    // $NON-NLS-1$
    GroupSymbol gs = RulePlaceAccess.recontextSymbol(new GroupSymbol("TEIID_TEMP"), context.getGroups());
    gs.setDefinition(null);
    tempAccess.addGroup(gs);
    tempAccess.setProperty(Info.MODEL_ID, modelID);
    indNode.addAsParent(tempAccess);
    PlanNode originalSource = sourceNode;
    sourceNode = originalSource.clone();
    // more deeply clone
    if (sourceNode.hasCollectionProperty(Info.ACCESS_PATTERNS)) {
        sourceNode.setProperty(Info.ACCESS_PATTERNS, new ArrayList<AccessPattern>((List) sourceNode.getProperty(Info.ACCESS_PATTERNS)));
    }
    if (sourceNode.hasCollectionProperty(Info.CONFORMED_SOURCES)) {
        sourceNode.setProperty(Info.CONFORMED_SOURCES, new LinkedHashSet<Object>((Set) sourceNode.getProperty(Info.CONFORMED_SOURCES)));
    }
    originalSource.addAsParent(sourceNode);
    boolean raised = false;
    boolean moreProcessing = false;
    boolean first = true;
    while (sourceNode.getParent() != null && RuleRaiseAccess.raiseAccessNode(sourceNode, sourceNode, metadata, capabilitiesFinder, true, null, context) != null) {
        raised = true;
        if (first) {
            // raising over join required
            first = false;
            continue;
        }
        switch(sourceNode.getFirstChild().getType()) {
            case NodeConstants.Types.PROJECT:
                // TODO: check for correlated subqueries
                if (sourceNode.getFirstChild().hasBooleanProperty(Info.HAS_WINDOW_FUNCTIONS)) {
                    moreProcessing = true;
                }
                break;
            case NodeConstants.Types.SORT:
            case NodeConstants.Types.DUP_REMOVE:
            case NodeConstants.Types.GROUP:
            case NodeConstants.Types.SELECT:
            case NodeConstants.Types.TUPLE_LIMIT:
            case NodeConstants.Types.JOIN:
                moreProcessing = true;
                break;
        }
    }
    if (!raised) {
        tempAccess.getParent().replaceChild(tempAccess, tempAccess.getFirstChild());
        sourceNode.getParent().replaceChild(sourceNode, sourceNode.getFirstChild());
        return false;
    }
    if (!moreProcessing && !hasHint) {
        // restore the plan
        if (sourceNode.getParent() != null) {
            sourceNode.getParent().replaceChild(sourceNode, sourceNode.getFirstChild());
        } else {
            sourceNode.removeAllChildren();
        }
        return false;
    }
    originalSource.getParent().replaceChild(originalSource, originalSource.getFirstChild());
    // all the references to any groups from this join have to changed over to the new group
    // and we need to insert a source/project node to turn this into a proper plan
    PlanNode project = NodeFactory.getNewNode(NodeConstants.Types.PROJECT);
    PlanNode source = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
    source.addGroup(gs);
    project.setProperty(Info.OUTPUT_COLS, projected);
    project.setProperty(Info.PROJECT_COLS, projected);
    Set<GroupSymbol> newGroups = Collections.singleton(gs);
    ArrayList<ElementSymbol> virtualSymbols = new ArrayList<ElementSymbol>(projected.size());
    for (int i = 0; i < projected.size(); i++) {
        // $NON-NLS-1$
        ElementSymbol es = new ElementSymbol("col" + (i + 1));
        Expression ex = projected.get(i);
        es.setType(ex.getType());
        virtualSymbols.add(es);
        // TODO: set a metadata id from either side
        if (ex instanceof ElementSymbol) {
            es.setMetadataID(((ElementSymbol) ex).getMetadataID());
        }
    }
    List<ElementSymbol> newCols = RulePushAggregates.defineNewGroup(gs, virtualSymbols, metadata);
    SymbolMap symbolMap = SymbolMap.createSymbolMap(newCols, projected);
    Map<Expression, ElementSymbol> inverse = symbolMap.inserseMapping();
    // TODO: the util logic should handle multiple groups
    for (GroupSymbol group : indNode.getGroups()) {
        FrameUtil.convertFrame(joinNode, group, newGroups, inverse, metadata);
    }
    // add the source a new group for the join
    indNode.addAsParent(source);
    // convert the lower plan into a subplan
    // it needs to be rooted by a project - a view isn't really needed
    indNode.removeFromParent();
    project.addFirstChild(indNode);
    // run the remaining rules against the subplan
    RuleStack ruleCopy = rules.clone();
    RuleChooseDependent ruleChooseDependent = new RuleChooseDependent();
    ruleChooseDependent.traditionalOnly = true;
    ruleCopy.push(ruleChooseDependent);
    if (indNode.getType() == NodeConstants.Types.ACCESS) {
        PlanNode root = RuleRaiseAccess.raiseAccessNode(project, indNode, metadata, capabilitiesFinder, true, null, context);
        if (root != project) {
            project = root;
        }
    }
    // fully plan the sub-plan with the remaining rules
    project = rules.getPlanner().executeRules(ruleCopy, project);
    source.setProperty(Info.SYMBOL_MAP, symbolMap);
    source.setProperty(Info.SUB_PLAN, project);
    return true;
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) LinkedHashSet(java.util.LinkedHashSet) Set(java.util.Set) ArrayList(java.util.ArrayList) SymbolMap(org.teiid.query.sql.util.SymbolMap) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) AccessPattern(org.teiid.query.resolver.util.AccessPattern) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) ArrayList(java.util.ArrayList) List(java.util.List) RuleStack(org.teiid.query.optimizer.relational.RuleStack)

Example 4 with AccessPattern

use of org.teiid.query.resolver.util.AccessPattern in project teiid by teiid.

the class RuleMergeVirtual method prepareFrame.

private static void prepareFrame(PlanNode frame) {
    // find the new root of the frame so that access patterns can be propagated
    PlanNode newRoot = FrameUtil.findJoinSourceNode(frame.getFirstChild());
    if (newRoot != null) {
        Collection<AccessPattern> ap = (Collection) frame.getProperty(NodeConstants.Info.ACCESS_PATTERNS);
        if (ap != null) {
            Collection<AccessPattern> newAp = (Collection) newRoot.getProperty(NodeConstants.Info.ACCESS_PATTERNS);
            if (newAp == null) {
                newRoot.setProperty(NodeConstants.Info.ACCESS_PATTERNS, ap);
            } else {
                newAp.addAll(ap);
            }
        }
        RulePlaceAccess.copyProperties(frame, newRoot);
    }
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) AccessPattern(org.teiid.query.resolver.util.AccessPattern) Collection(java.util.Collection)

Example 5 with AccessPattern

use of org.teiid.query.resolver.util.AccessPattern in project teiid by teiid.

the class RulePlanJoins method planForDependencies.

/**
 * Greedily choose the first set of access patterns that can be satisfied
 * TODO: this is greedy.  the first access pattern that can be satisfied will be
 * TODO: order access patterns by number of dependent groups
 *
 * If we could flatten to a single set of dependencies, then a topological sort would be faster
 *
 * @param joinRegion
 * @throws QueryPlannerException
 */
private void planForDependencies(JoinRegion joinRegion) throws QueryPlannerException {
    if (joinRegion.getJoinSourceNodes().isEmpty()) {
        throw new QueryPlannerException(QueryPlugin.Event.TEIID30275, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30275, joinRegion.getUnsatisfiedAccessPatterns()));
    }
    HashSet<GroupSymbol> currentGroups = new HashSet<GroupSymbol>();
    for (PlanNode joinSource : joinRegion.getJoinSourceNodes().keySet()) {
        currentGroups.addAll(joinSource.getGroups());
    }
    HashMap<PlanNode, PlanNode> dependentNodes = new HashMap<PlanNode, PlanNode>(joinRegion.getDependentJoinSourceNodes());
    boolean satisfiedAP = true;
    while (!dependentNodes.isEmpty() && satisfiedAP) {
        satisfiedAP = false;
        for (Iterator<Map.Entry<PlanNode, PlanNode>> joinSources = dependentNodes.entrySet().iterator(); joinSources.hasNext(); ) {
            Map.Entry<PlanNode, PlanNode> entry = joinSources.next();
            PlanNode joinSource = entry.getKey();
            Collection accessPatterns = (Collection) joinSource.getProperty(NodeConstants.Info.ACCESS_PATTERNS);
            for (Iterator i = accessPatterns.iterator(); i.hasNext(); ) {
                AccessPattern ap = (AccessPattern) i.next();
                boolean foundGroups = true;
                HashSet<GroupSymbol> allRequiredGroups = new HashSet<GroupSymbol>();
                for (ElementSymbol symbol : ap.getUnsatisfied()) {
                    Set<Collection<GroupSymbol>> requiredGroupsSet = joinRegion.getDependentCriteriaElements().get(symbol);
                    boolean elementSatisfied = false;
                    if (requiredGroupsSet != null) {
                        for (Collection<GroupSymbol> requiredGroups : requiredGroupsSet) {
                            if (currentGroups.containsAll(requiredGroups)) {
                                elementSatisfied = true;
                                allRequiredGroups.addAll(requiredGroups);
                                break;
                            }
                        }
                    }
                    if (!elementSatisfied) {
                        foundGroups = false;
                        break;
                    }
                }
                if (!foundGroups) {
                    continue;
                }
                joinSources.remove();
                currentGroups.addAll(joinSource.getGroups());
                satisfiedAP = true;
                joinSource.setProperty(NodeConstants.Info.ACCESS_PATTERN_USED, ap.clone());
                joinSource.setProperty(NodeConstants.Info.REQUIRED_ACCESS_PATTERN_GROUPS, allRequiredGroups);
                break;
            }
        }
    }
    if (!dependentNodes.isEmpty()) {
        throw new QueryPlannerException(QueryPlugin.Event.TEIID30275, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30275, joinRegion.getUnsatisfiedAccessPatterns()));
    }
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) AccessPattern(org.teiid.query.resolver.util.AccessPattern) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) SymbolMap(org.teiid.query.sql.util.SymbolMap)

Aggregations

AccessPattern (org.teiid.query.resolver.util.AccessPattern)8 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)4 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)4 Expression (org.teiid.query.sql.symbol.Expression)3 SymbolMap (org.teiid.query.sql.util.SymbolMap)3 ArrayList (java.util.ArrayList)2 List (java.util.List)2 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)2 Collection (java.util.Collection)1 LinkedHashSet (java.util.LinkedHashSet)1 Set (java.util.Set)1 QueryPlannerException (org.teiid.api.exception.query.QueryPlannerException)1 RuleStack (org.teiid.query.optimizer.relational.RuleStack)1