Search in sources :

Example 16 with QueryPlannerException

use of org.teiid.api.exception.query.QueryPlannerException in project teiid by teiid.

the class RulePushAggregates method stageAggregates.

Set<AggregateSymbol> stageAggregates(PlanNode groupNode, QueryMetadataInterface metadata, Set<Expression> stagedGroupingSymbols, Collection<AggregateSymbol> aggregates, boolean join) throws TeiidComponentException, QueryPlannerException {
    // remove any aggregates that are computed over a group by column
    for (final Iterator<AggregateSymbol> iterator = aggregates.iterator(); iterator.hasNext(); ) {
        final AggregateSymbol symbol = iterator.next();
        if (symbol.getArgs().length != 1 || symbol.isCardinalityDependent()) {
            continue;
        }
        Expression expr = symbol.getArg(0);
        if (stagedGroupingSymbols.contains(expr)) {
            iterator.remove();
        }
    }
    if (aggregates.isEmpty()) {
        return Collections.emptySet();
    }
    // Fix any aggregate expressions so they correctly recombine the staged aggregates
    Set<AggregateSymbol> newAggs = new HashSet<AggregateSymbol>();
    Map<AggregateSymbol, Expression> aggMap;
    try {
        aggMap = buildAggregateMap(aggregates, metadata, newAggs, join);
    } catch (QueryResolverException e) {
        throw new QueryPlannerException(QueryPlugin.Event.TEIID30266, e);
    }
    updateParentAggs(groupNode, aggMap, metadata);
    return newAggs;
}
Also used : QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) QueryResolverException(org.teiid.api.exception.query.QueryResolverException)

Example 17 with QueryPlannerException

use of org.teiid.api.exception.query.QueryPlannerException 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 18 with QueryPlannerException

use of org.teiid.api.exception.query.QueryPlannerException in project teiid by teiid.

the class RelationalPlanner method addNestedProcedure.

private boolean addNestedProcedure(PlanNode sourceNode, ProcedureContainer container, Object metadataId) throws TeiidComponentException, QueryMetadataException, TeiidProcessingException {
    if (container instanceof StoredProcedure) {
        StoredProcedure sp = (StoredProcedure) container;
        if (sp.getProcedureID() instanceof Procedure) {
            context.accessedPlanningObject(sp.getProcedureID());
        }
    }
    for (SubqueryContainer<?> subqueryContainer : ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(container)) {
        if (subqueryContainer.getCommand().getCorrelatedReferences() != null) {
            continue;
        }
        List<Reference> correlatedReferences = new ArrayList<Reference>();
        CorrelatedReferenceCollectorVisitor.collectReferences(subqueryContainer.getCommand(), Arrays.asList(container.getGroup()), correlatedReferences, metadata);
        setCorrelatedReferences(subqueryContainer, correlatedReferences);
    }
    // $NON-NLS-1$
    String cacheString = "transformation/" + container.getClass().getSimpleName().toUpperCase();
    Command c = (Command) metadata.getFromMetadataCache(metadataId, cacheString);
    if (c == null) {
        c = QueryResolver.expandCommand(container, metadata, analysisRecord);
        if (c != null) {
            if (c instanceof CreateProcedureCommand) {
                // TODO: find a better way to do this
                ((CreateProcedureCommand) c).setProjectedSymbols(container.getProjectedSymbols());
            }
            Request.validateWithVisitor(new ValidationVisitor(), metadata, c);
            metadata.addToMetadataCache(metadataId, cacheString, c.clone());
        }
    } else {
        c = (Command) c.clone();
        if (c instanceof CreateProcedureCommand) {
            // TODO: find a better way to do this
            ((CreateProcedureCommand) c).setProjectedSymbols(container.getProjectedSymbols());
        }
    }
    boolean checkRowBasedSecurity = true;
    if (!container.getGroup().isProcedure() && !metadata.isVirtualGroup(metadataId)) {
        Set<PlanningStackEntry> entries = planningStack.get();
        if (entries.contains(new PlanningStackEntry(container, container.getGroup()))) {
            checkRowBasedSecurity = false;
        }
    }
    if (checkRowBasedSecurity) {
        c = RowBasedSecurityHelper.checkUpdateRowBasedFilters(container, c, this);
    }
    if (c != null) {
        if (c instanceof TriggerAction) {
            TriggerAction ta = (TriggerAction) c;
            ProcessorPlan plan = new TriggerActionPlanner().optimize((ProcedureContainer) container.clone(), ta, idGenerator, metadata, capFinder, analysisRecord, context);
            sourceNode.setProperty(NodeConstants.Info.PROCESSOR_PLAN, plan);
            return true;
        }
        if (c.getCacheHint() != null) {
            if (container instanceof StoredProcedure) {
                StoredProcedure sp = (StoredProcedure) container;
                boolean noCache = isNoCacheGroup(metadata, sp.getProcedureID(), option);
                if (!noCache) {
                    if (!context.isResultSetCacheEnabled()) {
                        // $NON-NLS-1$ //$NON-NLS-2$
                        recordAnnotation(analysisRecord, Annotation.CACHED_PROCEDURE, Priority.MEDIUM, "SimpleQueryResolver.procedure_cache_not_usable", container.getGroup(), "result set cache disabled");
                    } else if (!container.areResultsCachable()) {
                        // $NON-NLS-1$ //$NON-NLS-2$
                        recordAnnotation(analysisRecord, Annotation.CACHED_PROCEDURE, Priority.MEDIUM, "SimpleQueryResolver.procedure_cache_not_usable", container.getGroup(), "procedure performs updates");
                    } else if (LobManager.getLobIndexes(new ArrayList<ElementSymbol>(sp.getProcedureParameters().keySet())) != null) {
                        // $NON-NLS-1$ //$NON-NLS-2$
                        recordAnnotation(analysisRecord, Annotation.CACHED_PROCEDURE, Priority.MEDIUM, "SimpleQueryResolver.procedure_cache_not_usable", container.getGroup(), "lob parameters");
                    }
                    container.getGroup().setGlobalTable(true);
                    container.setCacheHint(c.getCacheHint());
                    // $NON-NLS-1$*/
                    recordAnnotation(analysisRecord, Annotation.CACHED_PROCEDURE, Priority.LOW, "SimpleQueryResolver.procedure_cache_used", container.getGroup());
                    return false;
                }
                // $NON-NLS-1$
                recordAnnotation(analysisRecord, Annotation.CACHED_PROCEDURE, Priority.LOW, "SimpleQueryResolver.procedure_cache_not_used", container.getGroup());
            }
        }
        // skip the rewrite here, we'll do that in the optimizer
        // so that we know what the determinism level is.
        addNestedCommand(sourceNode, container.getGroup(), container, c, false, true);
    }
    List<SubqueryContainer<?>> subqueries = ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(container);
    if (c == null && container instanceof FilteredCommand) {
        // we force the evaluation of procedure params - TODO: inserts are fine except for nonpushdown functions on columns
        // for non-temp source queries, we must pre-plan subqueries to know if they can be pushed down
        boolean compensate = false;
        boolean isTemp = container.getGroup().isTempTable() && metadata.getModelID(container.getGroup().getMetadataID()) == TempMetadataAdapter.TEMP_MODEL;
        try {
            planSubqueries(container, c, subqueries, true);
        } catch (QueryPlannerException e) {
            if (!isTemp) {
                throw e;
            }
            compensate = true;
        }
        if (!isTemp && !CriteriaCapabilityValidatorVisitor.canPushLanguageObject(container, metadata.getModelID(container.getGroup().getMetadataID()), metadata, capFinder, analysisRecord)) {
            compensate = true;
        }
        if (compensate) {
            // do a workaround of row-by-row processing for update/delete
            validateRowProcessing(container);
            // treat this as an update procedure
            if (container instanceof Update) {
                c = QueryRewriter.createUpdateProcedure((Update) container, metadata, context);
            } else {
                c = QueryRewriter.createDeleteProcedure((Delete) container, metadata, context);
            }
            addNestedCommand(sourceNode, container.getGroup(), container, c, false, true);
            return false;
        }
    }
    // plan any subqueries in criteria/parameters/values
    planSubqueries(container, c, subqueries, false);
    return false;
}
Also used : ValidationVisitor(org.teiid.query.validator.ValidationVisitor) TriggerAction(org.teiid.query.sql.proc.TriggerAction) CreateProcedureCommand(org.teiid.query.sql.proc.CreateProcedureCommand) CreateProcedureCommand(org.teiid.query.sql.proc.CreateProcedureCommand) Procedure(org.teiid.metadata.Procedure) ProcessorPlan(org.teiid.query.processor.ProcessorPlan) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) TriggerActionPlanner(org.teiid.query.optimizer.TriggerActionPlanner)

Example 19 with QueryPlannerException

use of org.teiid.api.exception.query.QueryPlannerException in project teiid by teiid.

the class RowBasedSecurityHelper method checkUpdateRowBasedFilters.

public static Command checkUpdateRowBasedFilters(ProcedureContainer container, Command procedure, RelationalPlanner planner) throws QueryMetadataException, TeiidComponentException, TeiidProcessingException, QueryResolverException {
    if (container instanceof StoredProcedure) {
        return procedure;
    }
    Criteria filter = RowBasedSecurityHelper.getRowBasedFilters(planner.metadata, container.getGroup(), planner.context, false);
    if (filter == null) {
        return procedure;
    }
    addFilter(container, planner, filter);
    // we won't enforce on the update side through a virtual
    if (procedure != null) {
        return procedure;
    }
    filter = RowBasedSecurityHelper.getRowBasedFilters(planner.metadata, container.getGroup(), planner.context, true);
    if (filter == null) {
        return procedure;
    }
    // TODO: alter the compensation logic in RelationalPlanner to produce an row-by-row check for insert/update
    // check constraints
    Map<ElementSymbol, Expression> values = null;
    boolean compensate = false;
    if (container instanceof Update) {
        Collection<ElementSymbol> elems = ElementCollectorVisitor.getElements(filter, true);
        // check the change set against the filter
        values = new HashMap<ElementSymbol, Expression>();
        Update update = (Update) container;
        boolean constraintApplicable = false;
        for (SetClause clause : update.getChangeList().getClauses()) {
            if (!elems.contains(clause.getSymbol())) {
                continue;
            }
            constraintApplicable = true;
            // TODO: do this is a single eval pass
            if (EvaluatableVisitor.isFullyEvaluatable(clause.getValue(), true)) {
                values.put(clause.getSymbol(), clause.getValue());
            } else if (!compensate && !EvaluatableVisitor.isFullyEvaluatable(clause.getValue(), false)) {
                compensate = true;
            }
        }
        if (!constraintApplicable) {
            return procedure;
        }
    // TOOD: decompose the where clause to see if there are any more static
    // values that can be plugged in
    } else if (container instanceof Insert) {
        Insert insert = (Insert) container;
        if (insert.getQueryExpression() == null) {
            values = new HashMap<ElementSymbol, Expression>();
            Collection<ElementSymbol> insertElmnts = ResolverUtil.resolveElementsInGroup(insert.getGroup(), planner.metadata);
            for (ElementSymbol elementSymbol : insertElmnts) {
                Expression value = null;
                int index = insert.getVariables().indexOf(elementSymbol);
                if (index == -1) {
                    value = ResolverUtil.getDefault(elementSymbol, planner.metadata);
                    values.put(elementSymbol, value);
                } else {
                    value = (Expression) insert.getValues().get(index);
                    if (EvaluatableVisitor.isFullyEvaluatable(value, true)) {
                        values.put(elementSymbol, value);
                    }
                }
            }
        } else {
            validateAndPlanSubqueries(filter, container.getGroup(), planner);
            insert.setConstraint(filter);
        }
    }
    if (values != null) {
        if (!values.isEmpty()) {
            ExpressionMappingVisitor.mapExpressions(filter, values);
            filter = QueryRewriter.rewriteCriteria(filter, planner.context, planner.metadata);
        }
        if (filter != QueryRewriter.TRUE_CRITERIA) {
            if (filter == QueryRewriter.FALSE_CRITERIA || filter == QueryRewriter.UNKNOWN_CRITERIA) {
                throw new TeiidProcessingException(QueryPlugin.Event.TEIID31130, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31130, container));
            }
            if (container instanceof Update) {
                Collection<ElementSymbol> elems = ElementCollectorVisitor.getElements(filter, true);
                Update update = (Update) container;
                if (!Collections.disjoint(elems, update.getChangeList().getClauseMap().keySet())) {
                    validateAndPlanSubqueries(filter, container.getGroup(), planner);
                    update.setConstraint(filter);
                    if (compensate) {
                        try {
                            planner.validateRowProcessing(container);
                        } catch (QueryPlannerException e) {
                            throw new TeiidProcessingException(QueryPlugin.Event.TEIID31131, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31131, container));
                        }
                        return QueryRewriter.createUpdateProcedure((Update) container, planner.metadata, planner.context);
                    }
                }
            } else if (container instanceof Insert) {
                validateAndPlanSubqueries(filter, container.getGroup(), planner);
                ((Insert) container).setConstraint(filter);
            }
        }
    }
    return procedure;
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) HashMap(java.util.HashMap) TeiidProcessingException(org.teiid.core.TeiidProcessingException) Expression(org.teiid.query.sql.symbol.Expression) Collection(java.util.Collection) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException)

Example 20 with QueryPlannerException

use of org.teiid.api.exception.query.QueryPlannerException in project teiid by teiid.

the class RulePushSelectCriteria method examinePath.

/**
 * Examine the path from crit node to source node to determine how far down a node
 * can be pushed.
 * @return destinationChild
 */
PlanNode examinePath(PlanNode critNode, PlanNode sourceNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryPlannerException, TeiidComponentException {
    // Walk from source node up to critNode to build list of intervening nodes
    Stack<PlanNode> path = new Stack<PlanNode>();
    PlanNode currentNode = sourceNode.getParent();
    while (currentNode != critNode) {
        path.push(currentNode);
        currentNode = currentNode.getParent();
    }
    // Examine path in reverse order (by popping stack)
    while (!path.empty()) {
        currentNode = path.pop();
        // Look for situations where we don't allow SELECT to be pushed
        switch(currentNode.getType()) {
            case NodeConstants.Types.ACCESS:
                try {
                    if (!RuleRaiseAccess.canRaiseOverSelect(currentNode, metadata, capFinder, critNode, null)) {
                        return currentNode;
                    }
                    if (!RuleRaiseAccess.checkConformedSubqueries(currentNode, critNode, this.createdNodes == null)) {
                        return currentNode;
                    }
                    if (this.createdNodes == null) {
                        satisfyConditions(critNode, currentNode, metadata);
                    }
                    if (isDependentFinalDestination(critNode, currentNode)) {
                        // once a dependent crit node is pushed, don't bother pushing it further into the command
                        // dependent access node will use this as an assumption for where dependent sets can appear in the command
                        markDependent(critNode, currentNode, metadata, capFinder);
                        return currentNode.getFirstChild();
                    }
                } catch (QueryMetadataException e) {
                    throw new QueryPlannerException(QueryPlugin.Event.TEIID30267, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30267, currentNode.getGroups()));
                }
                break;
            case NodeConstants.Types.JOIN:
                // pushing below a join is not necessary under an access node
                if (this.createdNodes == null && NodeEditor.findParent(currentNode, NodeConstants.Types.ACCESS) != null) {
                    return currentNode;
                }
                // Check whether this criteria is on the inner side of an outer join.
                // If so, can't push past the join
                JoinType jt = JoinUtil.getJoinTypePreventingCriteriaOptimization(currentNode, critNode);
                if (jt != null) {
                    // if we successfully optimized then this should no longer inhibit the criteria from being pushed
                    // since the criteria must then be on the outer side of an outer join or on either side of an inner join
                    JoinType optimized = JoinUtil.optimizeJoinType(critNode, currentNode, metadata, this.createdNodes == null);
                    if (optimized == null || optimized.isOuter()) {
                        return currentNode;
                    }
                }
                if (this.createdNodes == null) {
                    satisfyConditions(critNode, currentNode, metadata);
                }
                break;
            default:
                if (FrameUtil.isOrderedOrStrictLimit(currentNode)) {
                    return currentNode;
                }
        }
    }
    return sourceNode;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) JoinType(org.teiid.query.sql.lang.JoinType) QueryMetadataException(org.teiid.api.exception.query.QueryMetadataException) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) RuleStack(org.teiid.query.optimizer.relational.RuleStack)

Aggregations

QueryPlannerException (org.teiid.api.exception.query.QueryPlannerException)27 TeiidProcessingException (org.teiid.core.TeiidProcessingException)11 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)11 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)11 ProcessorPlan (org.teiid.query.processor.ProcessorPlan)8 Expression (org.teiid.query.sql.symbol.Expression)8 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)8 SymbolMap (org.teiid.query.sql.util.SymbolMap)8 TeiidRuntimeException (org.teiid.core.TeiidRuntimeException)6 QueryMetadataException (org.teiid.api.exception.query.QueryMetadataException)5 TempMetadataID (org.teiid.query.metadata.TempMetadataID)5 CreateProcedureCommand (org.teiid.query.sql.proc.CreateProcedureCommand)5 ArrayList (java.util.ArrayList)4 TeiidComponentException (org.teiid.core.TeiidComponentException)4 Criteria (org.teiid.query.sql.lang.Criteria)4 HashSet (java.util.HashSet)3 List (java.util.List)3 AnalysisRecord (org.teiid.query.analysis.AnalysisRecord)3 RelationalPlan (org.teiid.query.processor.relational.RelationalPlan)3 HashMap (java.util.HashMap)2