Search in sources :

Example 1 with Operation

use of org.teiid.query.sql.lang.SetQuery.Operation in project teiid by teiid.

the class NewCalculateCostUtil method setColStatEstimates.

private static void setColStatEstimates(PlanNode node, float cardinality, QueryMetadataInterface metadata, float leftPercent, float rightPercent) throws QueryMetadataException, TeiidComponentException {
    if (cardinality == UNKNOWN_VALUE) {
        return;
    }
    ColStats colStats = null;
    ColStats colStatsOther = null;
    float childCardinality = UNKNOWN_VALUE;
    if (node.getChildCount() > 0) {
        childCardinality = node.getFirstChild().getCardinality();
        colStats = (ColStats) node.getFirstChild().getProperty(Info.EST_COL_STATS);
    }
    float otherChildCardinality = UNKNOWN_VALUE;
    List<? extends Expression> outputColsOther = null;
    if (node.getChildCount() > 1) {
        otherChildCardinality = node.getLastChild().getCardinality();
        colStatsOther = (ColStats) node.getLastChild().getProperty(Info.EST_COL_STATS);
        outputColsOther = getOutputCols(node.getLastChild(), metadata);
    }
    SetQuery.Operation setOp = (Operation) node.getProperty(Info.SET_OPERATION);
    List<? extends Expression> outputCols = getOutputCols(node, metadata);
    ColStats newColStats = new ColStats();
    for (int i = 0; i < outputCols.size(); i++) {
        Expression expr = outputCols.get(i);
        float[] newStats = new float[3];
        Arrays.fill(newStats, UNKNOWN_VALUE);
        if (childCardinality == UNKNOWN_VALUE || (setOp != null && (colStats == null || colStatsOther == null))) {
            // base case - cannot determine, just assume unique rows
            newStats[Stat.NDV.ordinal()] = cardinality;
            newStats[Stat.NDV_HIGH.ordinal()] = cardinality;
            newStats[Stat.NNV.ordinal()] = 0;
        } else if (setOp != null) {
            // set op
            float[] stats = colStats.get(expr);
            float[] statsOther = colStatsOther.get(outputColsOther.get(i));
            newStats[Stat.NDV.ordinal()] = Math.min(cardinality, getCombinedSetEstimate(setOp, stats[Stat.NDV.ordinal()], statsOther[Stat.NDV.ordinal()], true));
            newStats[Stat.NDV_HIGH.ordinal()] = Math.min(cardinality, getCombinedSetEstimate(setOp, stats[Stat.NDV_HIGH.ordinal()], statsOther[Stat.NDV_HIGH.ordinal()], true));
            newStats[Stat.NNV.ordinal()] = Math.min(cardinality, getCombinedSetEstimate(setOp, stats[Stat.NNV.ordinal()], statsOther[Stat.NNV.ordinal()], !node.hasBooleanProperty(NodeConstants.Info.USE_ALL)));
        } else {
            // all other cases - join is the only multi-node case here
            float[] stats = null;
            float origCardinality = childCardinality;
            boolean left = true;
            if (colStats != null) {
                stats = colStats.get(expr);
            }
            if (stats == null && colStatsOther != null) {
                origCardinality = otherChildCardinality;
                stats = colStatsOther.get(expr);
                left = false;
            }
            origCardinality = Math.max(1, origCardinality);
            if (stats == null) {
                if (node.getType() == NodeConstants.Types.PROJECT) {
                    Collection<Expression> elems = new HashSet<Expression>();
                    ElementCollectorVisitor.getElements(expr, elems);
                    newStats[Stat.NDV.ordinal()] = getStat(Stat.NDV, elems, node, childCardinality, metadata);
                    newStats[Stat.NDV_HIGH.ordinal()] = getStat(Stat.NDV_HIGH, elems, node, childCardinality, metadata);
                    newStats[Stat.NNV.ordinal()] = getStat(Stat.NNV, elems, node, childCardinality, metadata);
                } else {
                    // TODO: use a better estimate for new aggs
                    if (node.hasProperty(Info.GROUP_COLS)) {
                        newStats[Stat.NDV.ordinal()] = cardinality / 3;
                        newStats[Stat.NDV_HIGH.ordinal()] = cardinality / 3;
                    } else {
                        newStats[Stat.NDV.ordinal()] = cardinality;
                        newStats[Stat.NDV_HIGH.ordinal()] = cardinality;
                    }
                    newStats[Stat.NNV.ordinal()] = UNKNOWN_VALUE;
                }
            } else {
                if (node.getType() == NodeConstants.Types.DUP_REMOVE || node.getType() == NodeConstants.Types.GROUP || node.getType() == NodeConstants.Types.PROJECT || node.getType() == NodeConstants.Types.ACCESS) {
                    // don't scale down
                    newStats[Stat.NDV.ordinal()] = Math.min(cardinality, stats[Stat.NDV.ordinal()]);
                    newStats[Stat.NDV_HIGH.ordinal()] = Math.min(cardinality, stats[Stat.NDV_HIGH.ordinal()]);
                } else if (stats[Stat.NDV.ordinal()] != UNKNOWN_VALUE) {
                    if (stats[Stat.NDV.ordinal()] == stats[Stat.NDV_HIGH.ordinal()]) {
                        newStats[Stat.NDV.ordinal()] = stats[Stat.NDV.ordinal()] * Math.min(left ? leftPercent : rightPercent, cardinality / origCardinality);
                        newStats[Stat.NDV_HIGH.ordinal()] = newStats[Stat.NDV.ordinal()];
                    } else {
                        newStats[Stat.NDV.ordinal()] = (float) Math.min(stats[Stat.NDV.ordinal()], Math.sqrt(cardinality));
                        newStats[Stat.NDV_HIGH.ordinal()] = Math.min(stats[Stat.NDV_HIGH.ordinal()], cardinality / 2);
                    }
                    newStats[Stat.NDV.ordinal()] = Math.max(1, newStats[Stat.NDV.ordinal()]);
                    newStats[Stat.NDV_HIGH.ordinal()] = Math.max(1, newStats[Stat.NDV_HIGH.ordinal()]);
                }
                if (stats[Stat.NNV.ordinal()] != UNKNOWN_VALUE) {
                    // TODO: this is an under estimate for the inner side of outer joins
                    newStats[Stat.NNV.ordinal()] = stats[Stat.NNV.ordinal()] * Math.min(1, cardinality / origCardinality);
                    newStats[Stat.NNV.ordinal()] = Math.max(0, newStats[Stat.NNV.ordinal()]);
                }
            }
        }
        newColStats.put(expr, newStats);
    }
    node.setProperty(Info.EST_COL_STATS, newColStats);
}
Also used : Expression(org.teiid.query.sql.symbol.Expression) Operation(org.teiid.query.sql.lang.SetQuery.Operation) Operation(org.teiid.query.sql.lang.SetQuery.Operation)

Example 2 with Operation

use of org.teiid.query.sql.lang.SetQuery.Operation in project teiid by teiid.

the class RuleRaiseAccess method canRaiseOverSetQuery.

private static boolean canRaiseOverSetQuery(PlanNode setOpNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException {
    Object modelID = null;
    String sourceName = null;
    boolean multiSource = false;
    for (PlanNode childNode : setOpNode.getChildren()) {
        if (childNode.getType() != NodeConstants.Types.ACCESS) {
            return false;
        }
        if (FrameUtil.getNonQueryCommand(childNode) != null || FrameUtil.getNestedPlan(childNode) != null) {
            return false;
        }
        // Get model and check that it exists
        Object accessModelID = getModelIDFromAccess(childNode, metadata);
        if (accessModelID == null) {
            return false;
        }
        // TODO: see if the children are actually multiSourced
        multiSource |= childNode.hasBooleanProperty(Info.IS_MULTI_SOURCE);
        String name = (String) childNode.getProperty(Info.SOURCE_NAME);
        // Reconcile this access node's model ID with existing
        if (modelID == null) {
            modelID = accessModelID;
            Operation op = (Operation) setOpNode.getProperty(NodeConstants.Info.SET_OPERATION);
            if (!CapabilitiesUtil.supportsSetOp(accessModelID, op, metadata, capFinder)) {
                return false;
            }
            if (multiSource && op != Operation.UNION) {
                return false;
            }
        } else if (!CapabilitiesUtil.isSameConnector(modelID, accessModelID, metadata, capFinder)) {
            return false;
        }
        if (!multiSource) {
            if (sourceName == null) {
                sourceName = name;
            } else if (name != null && !sourceName.equals(name)) {
                return false;
            }
        }
        if (!setOpNode.hasBooleanProperty(NodeConstants.Info.USE_ALL) && !supportsDistinct(metadata, childNode, multiSource)) {
            return false;
        }
    }
    return true;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Operation(org.teiid.query.sql.lang.SetQuery.Operation)

Example 3 with Operation

use of org.teiid.query.sql.lang.SetQuery.Operation in project teiid by teiid.

the class RulePlanUnions method optimizeUnions.

/**
 * @param plan
 * @param metadata
 * @param capabilitiesFinder
 * @throws QueryMetadataException
 * @throws TeiidComponentException
 */
private void optimizeUnions(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder) throws QueryMetadataException, TeiidComponentException {
    // look for all union branches and their sources
    for (PlanNode unionNode : NodeEditor.findAllNodes(plan, NodeConstants.Types.SET_OP, NodeConstants.Types.SET_OP | NodeConstants.Types.ACCESS)) {
        List<PlanNode> accessNodes = NodeEditor.findAllNodes(unionNode, NodeConstants.Types.ACCESS);
        Object id = getModelId(metadata, accessNodes, capabilitiesFinder);
        // check to see if this union is already to the same source
        if (id != null) {
            continue;
        }
        // a linked hashmap is used so that the first entry is logically the first branch
        Map<Object, List<PlanNode>> sourceNodes = new LinkedHashMap<Object, List<PlanNode>>();
        boolean all = unionNode.hasBooleanProperty(NodeConstants.Info.USE_ALL);
        Operation op = (Operation) unionNode.getProperty(NodeConstants.Info.SET_OPERATION);
        collectUnionSources(metadata, capabilitiesFinder, unionNode, sourceNodes, all, op);
        if (sourceNodes.size() == 1) {
            continue;
        }
        // rebuild unions based upon the source map
        boolean shouldRebuild = false;
        for (Map.Entry<Object, List<PlanNode>> entry : sourceNodes.entrySet()) {
            if (entry.getKey() != null && entry.getValue().size() > 1 && CapabilitiesUtil.supportsSetOp(entry.getKey(), (Operation) unionNode.getProperty(NodeConstants.Info.SET_OPERATION), metadata, capabilitiesFinder)) {
                shouldRebuild = true;
                break;
            }
        }
        if (!shouldRebuild) {
            continue;
        }
        List<PlanNode> sourceUnions = new LinkedList<PlanNode>();
        for (Map.Entry<Object, List<PlanNode>> entry : sourceNodes.entrySet()) {
            List<PlanNode> sources = entry.getValue();
            sourceUnions.add(buildUnionTree(unionNode, sources));
        }
        PlanNode tempRoot = buildUnionTree(unionNode, sourceUnions);
        unionNode.removeAllChildren();
        unionNode.addChildren(tempRoot.removeAllChildren());
    }
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList) Operation(org.teiid.query.sql.lang.SetQuery.Operation) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) LinkedList(java.util.LinkedList) LinkedHashMap(java.util.LinkedHashMap)

Example 4 with Operation

use of org.teiid.query.sql.lang.SetQuery.Operation in project teiid by teiid.

the class PlanToProcessConverter method convertNode.

protected RelationalNode convertNode(PlanNode node) throws TeiidComponentException, TeiidProcessingException {
    RelationalNode processNode = null;
    switch(node.getType()) {
        case NodeConstants.Types.PROJECT:
            GroupSymbol intoGroup = (GroupSymbol) node.getProperty(NodeConstants.Info.INTO_GROUP);
            if (intoGroup != null) {
                try {
                    Insert insert = (Insert) node.getFirstChild().getProperty(Info.VIRTUAL_COMMAND);
                    List<ElementSymbol> allIntoElements = insert.getVariables();
                    Object groupID = intoGroup.getMetadataID();
                    Object modelID = metadata.getModelID(groupID);
                    String modelName = metadata.getFullName(modelID);
                    if (metadata.isVirtualGroup(groupID) && !metadata.isTemporaryTable(groupID)) {
                        InsertPlanExecutionNode ipen = new InsertPlanExecutionNode(getID(), metadata);
                        ProcessorPlan plan = (ProcessorPlan) node.getFirstChild().getProperty(Info.PROCESSOR_PLAN);
                        Assertion.isNotNull(plan);
                        ipen.setProcessorPlan(plan);
                        ipen.setReferences(insert.getValues());
                        processNode = ipen;
                    } else {
                        ProjectIntoNode pinode = new ProjectIntoNode(getID());
                        pinode.setIntoGroup(intoGroup);
                        pinode.setIntoElements(allIntoElements);
                        pinode.setModelName(modelName);
                        pinode.setConstraint((Criteria) node.getProperty(Info.CONSTRAINT));
                        pinode.setSourceHint((SourceHint) node.getProperty(Info.SOURCE_HINT));
                        if (node.hasBooleanProperty(Info.UPSERT)) {
                            pinode.setUpsert(true);
                        }
                        processNode = pinode;
                        SourceCapabilities caps = capFinder.findCapabilities(modelName);
                        if (caps.supportsCapability(Capability.INSERT_WITH_ITERATOR)) {
                            pinode.setMode(org.teiid.query.processor.relational.ProjectIntoNode.Mode.ITERATOR);
                        } else if (caps.supportsCapability(Capability.BATCHED_UPDATES)) {
                            pinode.setMode(org.teiid.query.processor.relational.ProjectIntoNode.Mode.BATCH);
                        } else {
                            pinode.setMode(org.teiid.query.processor.relational.ProjectIntoNode.Mode.SINGLE);
                        }
                        pinode.setTransactionSupport((TransactionSupport) caps.getSourceProperty(Capability.TRANSACTION_SUPPORT));
                    }
                } catch (QueryMetadataException e) {
                    throw new TeiidComponentException(QueryPlugin.Event.TEIID30247, e);
                }
            } else {
                List<Expression> symbols = (List) node.getProperty(NodeConstants.Info.PROJECT_COLS);
                ProjectNode pnode = new ProjectNode(getID());
                pnode.setSelectSymbols(symbols);
                processNode = pnode;
                if (node.hasBooleanProperty(Info.HAS_WINDOW_FUNCTIONS)) {
                    WindowFunctionProjectNode wfpn = new WindowFunctionProjectNode(getID());
                    // with partial projection the window function may already be pushed, we'll check for that here
                    ArrayList<Expression> filtered = new ArrayList<Expression>();
                    List<Expression> childSymbols = (List) node.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS);
                    for (Expression ex : symbols) {
                        ex = SymbolMap.getExpression(ex);
                        if (childSymbols.contains(ex)) {
                            continue;
                        }
                        filtered.add(ex);
                    }
                    Set<WindowFunction> windowFunctions = RuleAssignOutputElements.getWindowFunctions(filtered);
                    if (!windowFunctions.isEmpty()) {
                        // TODO: check for selecting all window functions
                        List<Expression> outputElements = new ArrayList<Expression>(windowFunctions);
                        // collect the other projected expressions
                        for (Expression singleElementSymbol : (List<Expression>) node.getFirstChild().getProperty(Info.OUTPUT_COLS)) {
                            outputElements.add(singleElementSymbol);
                        }
                        wfpn.setElements(outputElements);
                        wfpn.init();
                        pnode.addChild(wfpn);
                        for (WindowFunction wf : windowFunctions) {
                            validateAggregateFunctionEvaluation(wf.getFunction());
                        }
                    }
                }
            }
            break;
        case NodeConstants.Types.JOIN:
            JoinType jtype = (JoinType) node.getProperty(NodeConstants.Info.JOIN_TYPE);
            JoinStrategyType stype = (JoinStrategyType) node.getProperty(NodeConstants.Info.JOIN_STRATEGY);
            JoinNode jnode = new JoinNode(getID());
            jnode.setJoinType(jtype);
            jnode.setLeftDistinct(node.hasBooleanProperty(NodeConstants.Info.IS_LEFT_DISTINCT));
            jnode.setRightDistinct(node.hasBooleanProperty(NodeConstants.Info.IS_RIGHT_DISTINCT));
            List joinCrits = (List) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
            String depValueSource = (String) node.getProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE);
            SortOption leftSort = (SortOption) node.getProperty(NodeConstants.Info.SORT_LEFT);
            if (stype == JoinStrategyType.MERGE || stype == JoinStrategyType.ENHANCED_SORT) {
                MergeJoinStrategy mjStrategy = null;
                if (stype.equals(JoinStrategyType.ENHANCED_SORT)) {
                    EnhancedSortMergeJoinStrategy esmjStrategy = new EnhancedSortMergeJoinStrategy(leftSort, (SortOption) node.getProperty(NodeConstants.Info.SORT_RIGHT));
                    esmjStrategy.setSemiDep(node.hasBooleanProperty(Info.IS_SEMI_DEP));
                    mjStrategy = esmjStrategy;
                } else {
                    mjStrategy = new MergeJoinStrategy(leftSort, (SortOption) node.getProperty(NodeConstants.Info.SORT_RIGHT), false);
                }
                jnode.setJoinStrategy(mjStrategy);
                List leftExpressions = (List) node.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS);
                List rightExpressions = (List) node.getProperty(NodeConstants.Info.RIGHT_EXPRESSIONS);
                jnode.setJoinExpressions(leftExpressions, rightExpressions);
                joinCrits = (List) node.getProperty(NodeConstants.Info.NON_EQUI_JOIN_CRITERIA);
            } else if (stype == JoinStrategyType.NESTED_TABLE) {
                NestedTableJoinStrategy ntjStrategy = new NestedTableJoinStrategy();
                jnode.setJoinStrategy(ntjStrategy);
                SymbolMap references = (SymbolMap) node.getProperty(Info.RIGHT_NESTED_REFERENCES);
                ntjStrategy.setRightMap(references);
            } else {
                NestedLoopJoinStrategy nljStrategy = new NestedLoopJoinStrategy();
                jnode.setJoinStrategy(nljStrategy);
            }
            Criteria joinCrit = Criteria.combineCriteria(joinCrits);
            jnode.setJoinCriteria(joinCrit);
            processNode = jnode;
            jnode.setDependentValueSource(depValueSource);
            break;
        case NodeConstants.Types.ACCESS:
            ProcessorPlan plan = (ProcessorPlan) node.getProperty(NodeConstants.Info.PROCESSOR_PLAN);
            if (plan != null) {
                PlanExecutionNode peNode = null;
                Criteria crit = (Criteria) node.getProperty(NodeConstants.Info.PROCEDURE_CRITERIA);
                if (crit != null) {
                    List references = (List) node.getProperty(NodeConstants.Info.PROCEDURE_INPUTS);
                    List defaults = (List) node.getProperty(NodeConstants.Info.PROCEDURE_DEFAULTS);
                    peNode = new DependentProcedureExecutionNode(getID(), crit, references, defaults);
                } else {
                    peNode = new PlanExecutionNode(getID());
                }
                peNode.setProcessorPlan(plan);
                processNode = peNode;
            } else {
                AccessNode aNode = null;
                Command command = (Command) node.getProperty(NodeConstants.Info.ATOMIC_REQUEST);
                Object modelID = node.getProperty(NodeConstants.Info.MODEL_ID);
                if (modelID != null) {
                    String fullName = metadata.getFullName(modelID);
                    if (!capFinder.isValid(fullName)) {
                        // TODO: we ideally want to handle the partial resutls case here differently
                        // by adding a null node / and a source warning
                        // for now it's just as easy to say that the user needs to take steps to
                        // return static capabilities
                        SourceCapabilities caps = capFinder.findCapabilities(fullName);
                        Exception cause = null;
                        if (caps != null) {
                            cause = (Exception) caps.getSourceProperty(Capability.INVALID_EXCEPTION);
                        }
                        throw new QueryPlannerException(QueryPlugin.Event.TEIID30498, cause, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30498, fullName));
                    }
                }
                EvaluatableVisitor ev = null;
                if (node.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)) {
                    if (command instanceof StoredProcedure) {
                        List references = (List) node.getProperty(NodeConstants.Info.PROCEDURE_INPUTS);
                        List defaults = (List) node.getProperty(NodeConstants.Info.PROCEDURE_DEFAULTS);
                        Criteria crit = (Criteria) node.getProperty(NodeConstants.Info.PROCEDURE_CRITERIA);
                        DependentProcedureAccessNode depAccessNode = new DependentProcedureAccessNode(getID(), crit, references, defaults);
                        processNode = depAccessNode;
                        aNode = depAccessNode;
                    } else {
                        // create dependent access node
                        DependentAccessNode depAccessNode = new DependentAccessNode(getID());
                        if (modelID != null) {
                            depAccessNode.setPushdown(CapabilitiesUtil.supports(Capability.DEPENDENT_JOIN, modelID, metadata, capFinder));
                            depAccessNode.setMaxSetSize(CapabilitiesUtil.getMaxInCriteriaSize(modelID, metadata, capFinder));
                            depAccessNode.setMaxPredicates(CapabilitiesUtil.getMaxDependentPredicates(modelID, metadata, capFinder));
                            depAccessNode.setUseBindings(CapabilitiesUtil.supports(Capability.DEPENDENT_JOIN_BINDINGS, modelID, metadata, capFinder));
                            // TODO: allow the translator to drive this property
                            // simplistic check of whether this query is complex to re-execute
                            Query query = (Query) command;
                            if (query.getGroupBy() != null || query.getFrom().getClauses().size() > 1 || !(query.getFrom().getClauses().get(0) instanceof UnaryFromClause) || query.getWith() != null) {
                                depAccessNode.setComplexQuery(true);
                            } else {
                                // check to see if there in an index on at least one of the dependent sets
                                Set<GroupSymbol> groups = new HashSet<GroupSymbol>(query.getFrom().getGroups());
                                boolean found = false;
                                for (Criteria crit : Criteria.separateCriteriaByAnd(query.getCriteria())) {
                                    if (crit instanceof DependentSetCriteria) {
                                        DependentSetCriteria dsc = (DependentSetCriteria) crit;
                                        if (NewCalculateCostUtil.getKeyUsed(ElementCollectorVisitor.getElements(dsc.getExpression(), true), groups, metadata, null) != null) {
                                            found = true;
                                            break;
                                        }
                                    }
                                }
                                if (!found) {
                                    depAccessNode.setComplexQuery(true);
                                }
                            }
                        }
                        processNode = depAccessNode;
                        aNode = depAccessNode;
                    }
                    aNode.setShouldEvaluateExpressions(true);
                } else {
                    // create access node
                    aNode = new AccessNode(getID());
                    processNode = aNode;
                }
                // -- special handling for system tables. currently they cannot perform projection
                try {
                    if (command instanceof Query) {
                        processNode = correctProjectionInternalTables(node, aNode);
                    }
                } catch (QueryMetadataException err) {
                    throw new TeiidComponentException(QueryPlugin.Event.TEIID30248, err);
                }
                setRoutingName(aNode, node, command);
                boolean shouldEval = false;
                if (command instanceof Insert) {
                    Insert insert = (Insert) command;
                    if (insert.getQueryExpression() != null) {
                        insert.setQueryExpression((QueryCommand) aliasCommand(aNode, insert.getQueryExpression(), modelID));
                    } else {
                        for (int i = 0; i < insert.getValues().size(); i++) {
                            Expression ex = (Expression) insert.getValues().get(i);
                            if (!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(ex, modelID, metadata, capFinder, analysisRecord)) {
                                // replace with an expression symbol to let the rewriter know that it should be replaced
                                insert.getValues().set(i, new ExpressionSymbol("x", ex));
                                shouldEval = true;
                            }
                        }
                    }
                } else if (command instanceof QueryCommand) {
                    command = aliasCommand(aNode, command, modelID);
                }
                ev = EvaluatableVisitor.needsEvaluationVisitor(modelID, metadata, capFinder);
                if (!shouldEval && modelID != null) {
                    // do a capabilities sensitive check for needs eval
                    String modelName = metadata.getFullName(modelID);
                    SourceCapabilities caps = capFinder.findCapabilities(modelName);
                    final CriteriaCapabilityValidatorVisitor capVisitor = new CriteriaCapabilityValidatorVisitor(modelID, metadata, capFinder, caps);
                    capVisitor.setCheckEvaluation(false);
                    DeepPreOrderNavigator nav = new DeepPreOrderNavigator(ev) {

                        protected void visitNode(org.teiid.query.sql.LanguageObject obj) {
                            if (capVisitor.isValid() && obj instanceof Expression) {
                                obj.acceptVisitor(capVisitor);
                            }
                            super.visitNode(obj);
                        }
                    };
                    command.acceptVisitor(nav);
                    if (!capVisitor.isValid()) {
                        // there's a non-supported construct pushed, we should eval
                        ev.evaluationNotPossible(EvaluationLevel.PROCESSING);
                    }
                } else {
                    DeepPreOrderNavigator.doVisit(command, ev);
                }
                aNode.setShouldEvaluateExpressions(ev.requiresEvaluation(EvaluationLevel.PROCESSING) || shouldEval);
                aNode.setCommand(command);
                if (modelID != null) {
                    String fullName = metadata.getFullName(modelID);
                    SourceCapabilities caps = capFinder.findCapabilities(fullName);
                    aNode.setTransactionSupport((TransactionSupport) caps.getSourceProperty(Capability.TRANSACTION_SUPPORT));
                }
                Map<GroupSymbol, PlanNode> subPlans = (Map<GroupSymbol, PlanNode>) node.getProperty(Info.SUB_PLANS);
                // it makes more sense to allow the multisource affect to be elevated above just access nodes
                if (aNode.getModelId() != null && metadata.isMultiSource(aNode.getModelId())) {
                    VDBMetaData vdb = context.getVdb();
                    // forces a rewrite
                    aNode.setShouldEvaluateExpressions(true);
                    aNode.setElements((List) node.getProperty(NodeConstants.Info.OUTPUT_COLS));
                    if (node.hasBooleanProperty(Info.IS_MULTI_SOURCE)) {
                        Expression ex = rewriteMultiSourceCommand(aNode.getCommand());
                        aNode.setConnectorBindingExpression(ex);
                        aNode.setMultiSource(true);
                    } else {
                        String sourceName = (String) node.getProperty(Info.SOURCE_NAME);
                        aNode.setConnectorBindingExpression(new Constant(sourceName));
                    }
                } else if (subPlans == null) {
                    if (!aNode.isShouldEvaluate()) {
                        aNode.minimizeProject(command);
                    }
                    // check if valid to share this with other nodes
                    if (ev != null && ev.getDeterminismLevel().compareTo(Determinism.INSTRUCTION_DETERMINISTIC) >= 0 && command.areResultsCachable()) {
                        checkForSharedSourceCommand(aNode, node);
                    }
                }
                if (subPlans != null) {
                    QueryCommand qc = (QueryCommand) command;
                    if (qc.getWith() == null) {
                        qc.setWith(new ArrayList<WithQueryCommand>(subPlans.size()));
                    }
                    Map<GroupSymbol, RelationalPlan> plans = new LinkedHashMap<GroupSymbol, RelationalPlan>();
                    for (Map.Entry<GroupSymbol, PlanNode> entry : subPlans.entrySet()) {
                        RelationalPlan subPlan = convert(entry.getValue());
                        List<ElementSymbol> elems = ResolverUtil.resolveElementsInGroup(entry.getKey(), metadata);
                        subPlan.setOutputElements(elems);
                        plans.put(entry.getKey(), subPlan);
                        WithQueryCommand withQueryCommand = new WithQueryCommand(entry.getKey(), elems, null);
                        qc.getWith().add(withQueryCommand);
                    }
                    aNode.setSubPlans(plans);
                }
            }
            break;
        case NodeConstants.Types.SELECT:
            Criteria crit = (Criteria) node.getProperty(NodeConstants.Info.SELECT_CRITERIA);
            if (!node.hasCollectionProperty(Info.OUTPUT_COLS)) {
                // the late optimization to create a dependent join from a subquery introduces
                // criteria that have no output elements set
                // TODO that should be cleaner, but the logic currently expects to be run after join implementation
                // and rerunning assign output elements seems excessive
                node.setProperty(Info.OUTPUT_COLS, node.getFirstChild().getProperty(Info.OUTPUT_COLS));
            }
            SelectNode selnode = new SelectNode(getID());
            selnode.setCriteria(crit);
            // in case the parent was a source
            selnode.setProjectedExpressions((List<Expression>) node.getProperty(NodeConstants.Info.PROJECT_COLS));
            processNode = selnode;
            break;
        case NodeConstants.Types.SORT:
        case NodeConstants.Types.DUP_REMOVE:
            if (node.getType() == NodeConstants.Types.DUP_REMOVE) {
                processNode = new DupRemoveNode(getID());
            } else {
                SortNode sortNode = new SortNode(getID());
                OrderBy orderBy = (OrderBy) node.getProperty(NodeConstants.Info.SORT_ORDER);
                if (orderBy != null) {
                    sortNode.setSortElements(orderBy.getOrderByItems());
                }
                if (node.hasBooleanProperty(NodeConstants.Info.IS_DUP_REMOVAL)) {
                    sortNode.setMode(Mode.DUP_REMOVE_SORT);
                }
                processNode = sortNode;
            }
            break;
        case NodeConstants.Types.GROUP:
            GroupingNode gnode = new GroupingNode(getID());
            gnode.setRollup(node.hasBooleanProperty(Info.ROLLUP));
            SymbolMap groupingMap = (SymbolMap) node.getProperty(NodeConstants.Info.SYMBOL_MAP);
            gnode.setOutputMapping(groupingMap);
            gnode.setRemoveDuplicates(node.hasBooleanProperty(NodeConstants.Info.IS_DUP_REMOVAL));
            List<Expression> gCols = (List) node.getProperty(NodeConstants.Info.GROUP_COLS);
            OrderBy orderBy = (OrderBy) node.getProperty(Info.SORT_ORDER);
            if (orderBy == null) {
                if (gCols != null) {
                    LinkedHashSet<Expression> exprs = new LinkedHashSet<Expression>();
                    for (Expression ex : gCols) {
                        exprs.add(SymbolMap.getExpression(ex));
                    }
                    orderBy = new OrderBy(RuleChooseJoinStrategy.createExpressionSymbols(new ArrayList<Expression>(exprs)));
                }
            } else {
                HashSet<Expression> seen = new HashSet<Expression>();
                for (int i = 0; i < gCols.size(); i++) {
                    if (i < orderBy.getOrderByItems().size()) {
                        OrderByItem orderByItem = orderBy.getOrderByItems().get(i);
                        Expression ex = SymbolMap.getExpression(orderByItem.getSymbol());
                        if (!seen.add(ex)) {
                            continue;
                        }
                        if (ex instanceof ElementSymbol) {
                            ex = groupingMap.getMappedExpression((ElementSymbol) ex);
                            // $NON-NLS-1$
                            orderByItem.setSymbol(new ExpressionSymbol("expr", ex));
                        }
                    } else {
                        // $NON-NLS-1$
                        orderBy.addVariable(new ExpressionSymbol("expr", gCols.get(i)), OrderBy.ASC);
                    }
                }
            }
            if (orderBy != null) {
                gnode.setOrderBy(orderBy.getOrderByItems());
            }
            for (Expression ex : groupingMap != null ? groupingMap.getValues() : (List<Expression>) node.getFirstChild().getProperty(NodeConstants.Info.PROJECT_COLS)) {
                if (ex instanceof AggregateSymbol) {
                    validateAggregateFunctionEvaluation((AggregateSymbol) ex);
                }
            }
            processNode = gnode;
            break;
        case NodeConstants.Types.SOURCE:
            Object source = node.getProperty(NodeConstants.Info.TABLE_FUNCTION);
            if (source instanceof XMLTable) {
                XMLTable xt = (XMLTable) source;
                XMLTableNode xtn = new XMLTableNode(getID());
                // we handle the projection filtering once here rather than repeating the
                // path analysis on a per plan basis
                updateGroupName(node, xt);
                Map<Expression, Integer> elementMap = RelationalNode.createLookupMap(xt.getProjectedSymbols());
                List cols = (List) node.getProperty(NodeConstants.Info.OUTPUT_COLS);
                int[] projectionIndexes = RelationalNode.getProjectionIndexes(elementMap, cols);
                ArrayList<XMLColumn> filteredColumns = new ArrayList<XMLColumn>(projectionIndexes.length);
                for (int col : projectionIndexes) {
                    filteredColumns.add(xt.getColumns().get(col));
                }
                xt.getXQueryExpression().useDocumentProjection(filteredColumns, analysisRecord);
                xtn.setProjectedColumns(filteredColumns);
                xtn.setTable(xt);
                processNode = xtn;
                break;
            }
            if (source instanceof ObjectTable) {
                ObjectTable ot = (ObjectTable) source;
                ObjectTableNode otn = new ObjectTableNode(getID());
                // we handle the projection filtering once here rather than repeating the
                // path analysis on a per plan basis
                updateGroupName(node, ot);
                Map<Expression, Integer> elementMap = RelationalNode.createLookupMap(ot.getProjectedSymbols());
                List<Expression> cols = (List<Expression>) node.getProperty(NodeConstants.Info.OUTPUT_COLS);
                int[] projectionIndexes = RelationalNode.getProjectionIndexes(elementMap, cols);
                ArrayList<ObjectColumn> filteredColumns = new ArrayList<ObjectColumn>(projectionIndexes.length);
                for (int col : projectionIndexes) {
                    filteredColumns.add(ot.getColumns().get(col));
                }
                otn.setProjectedColumns(filteredColumns);
                otn.setTable(ot);
                processNode = otn;
                break;
            }
            if (source instanceof TextTable) {
                TextTableNode ttn = new TextTableNode(getID());
                TextTable tt = (TextTable) source;
                updateGroupName(node, tt);
                ttn.setTable(tt);
                processNode = ttn;
                break;
            }
            if (source instanceof ArrayTable) {
                ArrayTableNode atn = new ArrayTableNode(getID());
                ArrayTable at = (ArrayTable) source;
                updateGroupName(node, at);
                atn.setTable(at);
                processNode = atn;
                break;
            }
            SymbolMap symbolMap = (SymbolMap) node.getProperty(NodeConstants.Info.SYMBOL_MAP);
            if (symbolMap != null) {
                PlanNode child = node.getLastChild();
                if (child.getType() == NodeConstants.Types.PROJECT || child.getType() == NodeConstants.Types.SELECT) {
                    // update the project cols based upon the original output
                    child.setProperty(NodeConstants.Info.PROJECT_COLS, child.getProperty(NodeConstants.Info.OUTPUT_COLS));
                }
                if (child.getType() != NodeConstants.Types.SET_OP || child.getProperty(Info.SET_OPERATION) == Operation.UNION) {
                    child.setProperty(NodeConstants.Info.OUTPUT_COLS, node.getProperty(NodeConstants.Info.OUTPUT_COLS));
                } else {
                    // else we cannot directly update the child properties as the child will get converted to a join
                    // create a projection instead for initialization purposes, but won't impact performance
                    ProjectNode pNode = new ProjectNode(getID());
                    pNode.setSelectSymbols((List<? extends Expression>) child.getProperty(NodeConstants.Info.OUTPUT_COLS));
                    return prepareToAdd(node, pNode);
                }
            }
            return null;
        case NodeConstants.Types.SET_OP:
            Operation setOp = (Operation) node.getProperty(NodeConstants.Info.SET_OPERATION);
            boolean useAll = ((Boolean) node.getProperty(NodeConstants.Info.USE_ALL)).booleanValue();
            if (setOp == Operation.UNION) {
                RelationalNode unionAllNode = new UnionAllNode(getID());
                if (useAll) {
                    processNode = unionAllNode;
                } else {
                    boolean onlyDupRemoval = node.hasBooleanProperty(NodeConstants.Info.IS_DUP_REMOVAL);
                    if (onlyDupRemoval) {
                        processNode = new DupRemoveNode(getID());
                    } else {
                        SortNode sNode = new SortNode(getID());
                        sNode.setMode(Mode.DUP_REMOVE_SORT);
                        processNode = sNode;
                    }
                    unionAllNode.setElements((List) node.getProperty(NodeConstants.Info.OUTPUT_COLS));
                    processNode.addChild(unionAllNode);
                }
            } else {
                JoinNode joinAsSet = new JoinNode(getID());
                joinAsSet.setJoinStrategy(new MergeJoinStrategy(SortOption.SORT_DISTINCT, SortOption.SORT_DISTINCT, true));
                // If we push these sorts, we will have to enforce null order, since nulls are equal here
                List leftExpressions = (List) node.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS);
                List rightExpressions = (List) node.getLastChild().getProperty(NodeConstants.Info.OUTPUT_COLS);
                joinAsSet.setJoinType(setOp == Operation.EXCEPT ? JoinType.JOIN_ANTI_SEMI : JoinType.JOIN_SEMI);
                joinAsSet.setJoinExpressions(leftExpressions, rightExpressions);
                processNode = joinAsSet;
            }
            break;
        case NodeConstants.Types.TUPLE_LIMIT:
            Expression rowLimit = (Expression) node.getProperty(NodeConstants.Info.MAX_TUPLE_LIMIT);
            Expression offset = (Expression) node.getProperty(NodeConstants.Info.OFFSET_TUPLE_COUNT);
            LimitNode ln = new LimitNode(getID(), rowLimit, offset);
            ln.setImplicit(node.hasBooleanProperty(Info.IS_IMPLICIT_LIMIT));
            processNode = ln;
            break;
        case NodeConstants.Types.NULL:
            processNode = new NullNode(getID());
            break;
        default:
            throw new QueryPlannerException(QueryPlugin.Event.TEIID30250, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30250, NodeConstants.getNodeTypeString(node.getType())));
    }
    if (processNode != null) {
        processNode = prepareToAdd(node, processNode);
    }
    return processNode;
}
Also used : ExpressionSymbol(org.teiid.query.sql.symbol.ExpressionSymbol) DeepPreOrderNavigator(org.teiid.query.sql.navigator.DeepPreOrderNavigator) XMLColumn(org.teiid.query.sql.lang.XMLTable.XMLColumn) VDBMetaData(org.teiid.adminapi.impl.VDBMetaData) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) TeiidComponentException(org.teiid.core.TeiidComponentException) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) SymbolMap(org.teiid.query.sql.util.SymbolMap) ObjectColumn(org.teiid.query.sql.lang.ObjectTable.ObjectColumn) CriteriaCapabilityValidatorVisitor(org.teiid.query.optimizer.relational.rules.CriteriaCapabilityValidatorVisitor) JoinStrategyType(org.teiid.query.processor.relational.JoinNode.JoinStrategyType) EvaluatableVisitor(org.teiid.query.sql.visitor.EvaluatableVisitor) Expression(org.teiid.query.sql.symbol.Expression) SourceCapabilities(org.teiid.query.optimizer.capabilities.SourceCapabilities) WindowFunction(org.teiid.query.sql.symbol.WindowFunction) SortOption(org.teiid.query.processor.relational.MergeJoinStrategy.SortOption) SymbolMap(org.teiid.query.sql.util.SymbolMap) QueryMetadataException(org.teiid.api.exception.query.QueryMetadataException) ProcessorPlan(org.teiid.query.processor.ProcessorPlan) ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) AggregateSymbol(org.teiid.query.sql.symbol.AggregateSymbol) Constant(org.teiid.query.sql.symbol.Constant) Operation(org.teiid.query.sql.lang.SetQuery.Operation) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) TeiidComponentException(org.teiid.core.TeiidComponentException) QueryMetadataException(org.teiid.api.exception.query.QueryMetadataException) TeiidProcessingException(org.teiid.core.TeiidProcessingException) TeiidRuntimeException(org.teiid.core.TeiidRuntimeException) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) SpecificHint(org.teiid.query.sql.lang.SourceHint.SpecificHint) AtomicInteger(java.util.concurrent.atomic.AtomicInteger)

Example 5 with Operation

use of org.teiid.query.sql.lang.SetQuery.Operation in project teiid by teiid.

the class RuleCollapseSource method createQuery.

private QueryCommand createQuery(CommandContext context, CapabilitiesFinder capFinder, PlanNode accessRoot, PlanNode node) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    QueryMetadataInterface metadata = context.getMetadata();
    PlanNode setOpNode = NodeEditor.findNodePreOrder(node, NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE);
    Object modelID = RuleRaiseAccess.getModelIDFromAccess(accessRoot, metadata);
    if (setOpNode != null) {
        Operation setOp = (Operation) setOpNode.getProperty(NodeConstants.Info.SET_OPERATION);
        SetQuery unionCommand = new SetQuery(setOp);
        boolean unionAll = ((Boolean) setOpNode.getProperty(NodeConstants.Info.USE_ALL)).booleanValue();
        unionCommand.setAll(unionAll);
        int count = 0;
        OrderBy orderBy = null;
        PlanNode sort = NodeEditor.findNodePreOrder(node, NodeConstants.Types.SORT, NodeConstants.Types.SET_OP);
        if (sort != null) {
            processOrderBy(sort, unionCommand, modelID, context, capFinder);
            orderBy = unionCommand.getOrderBy();
            unionCommand.setOrderBy(null);
            // we have to remap if the primary projection is from a grouping
            PlanNode groupNode = NodeEditor.findNodePreOrder(setOpNode.getFirstChild(), NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE);
            if (groupNode != null) {
                SymbolMap symbolMap = (SymbolMap) groupNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
                ExpressionMappingVisitor.mapExpressions(orderBy, symbolMap.asMap(), true);
            }
        }
        for (PlanNode child : setOpNode.getChildren()) {
            QueryCommand command = createQuery(context, capFinder, accessRoot, child);
            if (count == 0) {
                unionCommand.setLeftQuery(command);
            } else if (count == 1) {
                unionCommand.setRightQuery(command);
            } else {
                unionCommand = new SetQuery(setOp, unionAll, unionCommand, command);
            }
            count++;
        }
        PlanNode limit = NodeEditor.findNodePreOrder(node, NodeConstants.Types.TUPLE_LIMIT, NodeConstants.Types.SET_OP);
        if (limit != null) {
            processLimit(limit, unionCommand, metadata);
        }
        unionCommand.setOrderBy(orderBy);
        return unionCommand;
    }
    Query query = new Query();
    Select select = new Select();
    List<Expression> columns = (List<Expression>) node.getProperty(NodeConstants.Info.OUTPUT_COLS);
    prepareSubqueries(ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(columns));
    select.addSymbols(columns);
    query.setSelect(select);
    query.setFrom(new From());
    buildQuery(accessRoot, node, query, context, capFinder);
    if (!CapabilitiesUtil.useAnsiJoin(modelID, metadata, capFinder)) {
        simplifyFromClause(query);
    }
    if (query.getCriteria() instanceof CompoundCriteria) {
        query.setCriteria(QueryRewriter.optimizeCriteria((CompoundCriteria) query.getCriteria(), metadata));
    }
    if (columns.isEmpty()) {
        if (CapabilitiesUtil.supports(Capability.QUERY_SELECT_EXPRESSION, modelID, metadata, capFinder)) {
            // $NON-NLS-1$
            select.addSymbol(new ExpressionSymbol("dummy", new Constant(1)));
        } else {
            // TODO: need to ensure the type is consistent
            // - should be rare as the source would typically support select expression if it supports union
            select.addSymbol(selectOutputElement(query.getFrom().getGroups(), metadata));
        }
    }
    PlanNode groupNode = NodeEditor.findNodePreOrder(node, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE);
    if (groupNode != null) {
        if (query.getOrderBy() != null) {
            query.setOrderBy(query.getOrderBy().clone());
        }
        if (query.getHaving() != null) {
            query.setHaving((Criteria) query.getHaving().clone());
        }
        query.setSelect(query.getSelect().clone());
        SymbolMap symbolMap = (SymbolMap) groupNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
        // map back to expression form
        ExpressionMappingVisitor.mapExpressions(query.getOrderBy(), symbolMap.asMap(), true);
        ExpressionMappingVisitor.mapExpressions(query.getSelect(), symbolMap.asMap(), true);
        ExpressionMappingVisitor.mapExpressions(query.getHaving(), symbolMap.asMap(), true);
        if (query.getHaving() != null && !CapabilitiesUtil.supports(Capability.QUERY_HAVING, modelID, metadata, capFinder)) {
            Select sel = query.getSelect();
            GroupBy groupBy = query.getGroupBy();
            Criteria having = query.getHaving();
            query.setHaving(null);
            OrderBy orderBy = query.getOrderBy();
            query.setOrderBy(null);
            Limit limit = query.getLimit();
            query.setLimit(null);
            Set<AggregateSymbol> aggs = new HashSet<AggregateSymbol>();
            aggs.addAll(AggregateSymbolCollectorVisitor.getAggregates(having, true));
            Set<Expression> expr = new HashSet<Expression>();
            for (Expression ex : sel.getProjectedSymbols()) {
                Expression selectExpression = SymbolMap.getExpression(ex);
                aggs.remove(selectExpression);
                expr.add(selectExpression);
            }
            int originalSelect = sel.getSymbols().size();
            sel.addSymbols(aggs);
            if (groupBy != null) {
                for (Expression ex : groupBy.getSymbols()) {
                    ex = SymbolMap.getExpression(ex);
                    if (expr.add(ex)) {
                        sel.addSymbol(ex);
                    }
                }
            }
            Query outerQuery = null;
            try {
                // $NON-NLS-1$
                outerQuery = QueryRewriter.createInlineViewQuery(new GroupSymbol("X"), query, metadata, query.getSelect().getProjectedSymbols());
            } catch (TeiidException err) {
                throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30257, err);
            }
            Iterator<Expression> iter = outerQuery.getSelect().getProjectedSymbols().iterator();
            HashMap<Expression, Expression> expressionMap = new HashMap<Expression, Expression>();
            for (Expression symbol : query.getSelect().getProjectedSymbols()) {
                // need to unwrap on both sides as the select expression could be aliased
                // TODO: could add an option to createInlineViewQuery to disable alias creation
                expressionMap.put(SymbolMap.getExpression(symbol), SymbolMap.getExpression(iter.next()));
            }
            ExpressionMappingVisitor.mapExpressions(having, expressionMap, true);
            outerQuery.setCriteria(having);
            ExpressionMappingVisitor.mapExpressions(orderBy, expressionMap, true);
            outerQuery.setOrderBy(orderBy);
            outerQuery.setLimit(limit);
            ExpressionMappingVisitor.mapExpressions(select, expressionMap, true);
            outerQuery.getSelect().setSymbols(outerQuery.getSelect().getProjectedSymbols().subList(0, originalSelect));
            outerQuery.setOption(query.getOption());
            query = outerQuery;
        }
        if (query.getGroupBy() != null) {
            // we check for group by expressions here to create an ANSI SQL plan
            boolean hasExpression = false;
            boolean hasLiteral = false;
            for (final Iterator<Expression> iterator = query.getGroupBy().getSymbols().iterator(); iterator.hasNext(); ) {
                Expression ex = iterator.next();
                hasExpression |= !(ex instanceof ElementSymbol);
                hasLiteral |= EvaluatableVisitor.willBecomeConstant(ex, true);
            }
            if ((hasExpression && !CapabilitiesUtil.supports(Capability.QUERY_FUNCTIONS_IN_GROUP_BY, modelID, metadata, capFinder)) || hasLiteral) {
                // if group by expressions are not support, add an inline view to compensate
                query = RuleCollapseSource.rewriteGroupByAsView(query, metadata, false);
                if (query.getHaving() != null) {
                    // dependent sets will have been added a having
                    List<Criteria> crits = Criteria.separateCriteriaByAnd(query.getHaving());
                    for (Iterator<Criteria> iter = crits.iterator(); iter.hasNext(); ) {
                        Criteria crit = iter.next();
                        if (crit instanceof DependentSetCriteria) {
                            query.setCriteria(Criteria.combineCriteria(query.getCriteria(), crit));
                            iter.remove();
                        }
                    }
                    query.setHaving(Criteria.combineCriteria(crits));
                }
            }
            if (query.getOrderBy() != null && groupNode.hasBooleanProperty(Info.ROLLUP) && !CapabilitiesUtil.supports(Capability.QUERY_ORDERBY_EXTENDED_GROUPING, modelID, metadata, capFinder)) {
                // if ordering is not directly supported over extended grouping, add an inline view to compensate
                query = RuleCollapseSource.rewriteGroupByAsView(query, metadata, true);
            }
        }
    }
    return query;
}
Also used : HashMap(java.util.HashMap) Operation(org.teiid.query.sql.lang.SetQuery.Operation) TeiidRuntimeException(org.teiid.core.TeiidRuntimeException) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) List(java.util.List) ArrayList(java.util.ArrayList) QueryMetadataInterface(org.teiid.query.metadata.QueryMetadataInterface) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) SymbolMap(org.teiid.query.sql.util.SymbolMap) TeiidException(org.teiid.core.TeiidException)

Aggregations

Operation (org.teiid.query.sql.lang.SetQuery.Operation)5 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)4 ArrayList (java.util.ArrayList)2 List (java.util.List)2 TeiidRuntimeException (org.teiid.core.TeiidRuntimeException)2 Expression (org.teiid.query.sql.symbol.Expression)2 SymbolMap (org.teiid.query.sql.util.SymbolMap)2 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1 LinkedHashSet (java.util.LinkedHashSet)1 LinkedList (java.util.LinkedList)1 Map (java.util.Map)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 VDBMetaData (org.teiid.adminapi.impl.VDBMetaData)1 QueryMetadataException (org.teiid.api.exception.query.QueryMetadataException)1 QueryPlannerException (org.teiid.api.exception.query.QueryPlannerException)1 TeiidComponentException (org.teiid.core.TeiidComponentException)1 TeiidException (org.teiid.core.TeiidException)1 TeiidProcessingException (org.teiid.core.TeiidProcessingException)1