Search in sources :

Example 6 with ExpressionSymbol

use of org.teiid.query.sql.symbol.ExpressionSymbol in project teiid by teiid.

the class TempMetadataStore method createElementSymbol.

private TempMetadataID createElementSymbol(String tempName, Expression symbol, boolean isTempTable) {
    // Create new element name
    String elementName = tempName + Symbol.SEPARATOR + Symbol.getShortName(symbol);
    Object metadataID = null;
    if (symbol instanceof AliasSymbol) {
        AliasSymbol as = (AliasSymbol) symbol;
        symbol = as.getSymbol();
    }
    // the following allows for original metadata ids to be determined for proc inputs
    if (symbol instanceof ExpressionSymbol) {
        Expression expr = ((ExpressionSymbol) symbol).getExpression();
        if (expr instanceof Reference) {
            expr = ((Reference) expr).getExpression();
        }
        if (expr instanceof ElementSymbol) {
            symbol = expr;
        }
    }
    if (symbol instanceof ElementSymbol) {
        metadataID = ((ElementSymbol) symbol).getMetadataID();
    }
    while (metadataID != null && metadataID instanceof TempMetadataID) {
        metadataID = ((TempMetadataID) metadataID).getOriginalMetadataID();
    }
    TempMetadataID elementID = new TempMetadataID(elementName, symbol.getType(), metadataID);
    elementID.setTempTable(isTempTable);
    return elementID;
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) AliasSymbol(org.teiid.query.sql.symbol.AliasSymbol) Expression(org.teiid.query.sql.symbol.Expression) Reference(org.teiid.query.sql.symbol.Reference) ExpressionSymbol(org.teiid.query.sql.symbol.ExpressionSymbol)

Example 7 with ExpressionSymbol

use of org.teiid.query.sql.symbol.ExpressionSymbol in project teiid by teiid.

the class RuleMergeVirtual method checkForSimpleProjection.

/**
 * Removes source layers that only do a simple projection of the elements below.
 * @param capFinder
 * @throws TeiidComponentException
 * @throws QueryMetadataException
 * @throws QueryPlannerException
 */
private static PlanNode checkForSimpleProjection(PlanNode frame, PlanNode root, PlanNode parentProject, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    // check that the parent only performs projection
    PlanNode nodeToCheck = parentProject.getFirstChild();
    while (nodeToCheck != frame) {
        if (nodeToCheck.getType() != NodeConstants.Types.SELECT || !nodeToCheck.hasBooleanProperty(NodeConstants.Info.IS_PHANTOM)) {
            return root;
        }
        nodeToCheck = nodeToCheck.getFirstChild();
    }
    if (frame.getFirstChild().getType() == NodeConstants.Types.TUPLE_LIMIT && NodeEditor.findParent(parentProject, NodeConstants.Types.SORT | NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.SOURCE | NodeConstants.Types.SET_OP) != null) {
        return root;
    }
    List<? extends Expression> requiredElements = RuleAssignOutputElements.determineSourceOutput(frame, new ArrayList<Expression>(), metadata, null);
    List<Expression> selectSymbols = (List<Expression>) parentProject.getProperty(NodeConstants.Info.PROJECT_COLS);
    // check that it only performs simple projection and that all required symbols are projected
    // ensuring there are no duplicates prevents problems with subqueries
    LinkedHashSet<Expression> symbols = new LinkedHashSet<Expression>();
    for (Expression symbol : selectSymbols) {
        Expression expr = SymbolMap.getExpression(symbol);
        if (expr instanceof Constant) {
            if (!symbols.add(new ExpressionSymbol("const" + symbols.size(), expr))) {
                // $NON-NLS-1$
                return root;
            }
            continue;
        }
        if (!(expr instanceof ElementSymbol)) {
            return root;
        }
        requiredElements.remove(expr);
        if (!symbols.add(expr)) {
            return root;
        }
    }
    if (!requiredElements.isEmpty()) {
        return root;
    }
    PlanNode sort = NodeEditor.findParent(parentProject, NodeConstants.Types.SORT, NodeConstants.Types.SOURCE);
    if (sort != null && sort.hasBooleanProperty(Info.UNRELATED_SORT)) {
        return root;
    }
    // re-order the lower projects
    RuleAssignOutputElements.filterVirtualElements(frame, new ArrayList<Expression>(symbols), metadata);
    // remove phantom select nodes
    nodeToCheck = parentProject.getFirstChild();
    while (nodeToCheck != frame) {
        PlanNode current = nodeToCheck;
        nodeToCheck = nodeToCheck.getFirstChild();
        NodeEditor.removeChildNode(current.getParent(), current);
    }
    if (NodeEditor.findParent(parentProject, NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.SOURCE) != null) {
        PlanNode lowerDup = NodeEditor.findNodePreOrder(frame.getFirstChild(), NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.PROJECT);
        if (lowerDup != null) {
            NodeEditor.removeChildNode(lowerDup.getParent(), lowerDup);
        }
        PlanNode setOp = NodeEditor.findNodePreOrder(frame.getFirstChild(), NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE);
        if (setOp != null) {
            setOp.setProperty(NodeConstants.Info.USE_ALL, Boolean.FALSE);
            distributeDupRemove(metadata, capFinder, setOp);
            if (parentProject.getParent().getParent() != null) {
                NodeEditor.removeChildNode(parentProject.getParent().getParent(), parentProject.getParent());
            } else {
                parentProject.removeFromParent();
                root = parentProject;
            }
        }
    }
    correctOrderBy(frame, sort, selectSymbols, parentProject);
    PlanNode parentSource = NodeEditor.findParent(frame, NodeConstants.Types.SOURCE);
    if (parentSource != null && NodeEditor.findNodePreOrder(parentSource, NodeConstants.Types.PROJECT) == parentProject) {
        FrameUtil.correctSymbolMap(((SymbolMap) frame.getProperty(NodeConstants.Info.SYMBOL_MAP)).asMap(), parentSource);
    }
    prepareFrame(frame);
    // remove the parent project and the source node
    NodeEditor.removeChildNode(parentProject, frame);
    if (parentProject.getParent() == null) {
        root = parentProject.getFirstChild();
        parentProject.removeChild(root);
        return root;
    }
    NodeEditor.removeChildNode(parentProject.getParent(), parentProject);
    return root;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Expression(org.teiid.query.sql.symbol.Expression) Constant(org.teiid.query.sql.symbol.Constant) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) ExpressionSymbol(org.teiid.query.sql.symbol.ExpressionSymbol)

Example 8 with ExpressionSymbol

use of org.teiid.query.sql.symbol.ExpressionSymbol in project teiid by teiid.

the class RulePlanSorts method checkForProjectOptimization.

static PlanNode checkForProjectOptimization(PlanNode node, PlanNode root, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    PlanNode projectNode = node.getFirstChild();
    PlanNode parent = node.getParent();
    boolean raiseAccess = false;
    // special check for unrelated order by compensation
    if (projectNode.getType() == NodeConstants.Types.ACCESS && RuleRaiseAccess.canRaiseOverSort(projectNode, metadata, capFinder, node, record, true, context)) {
        projectNode = NodeEditor.findNodePreOrder(projectNode, NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE | NodeConstants.Types.SET_OP);
        if (projectNode == null) {
            // no interviening project
            return root;
        }
        raiseAccess = true;
    } else if (projectNode.getType() == NodeConstants.Types.PROJECT && projectNode.getFirstChild() != null) {
        raiseAccess = projectNode.getFirstChild().getType() == NodeConstants.Types.ACCESS && RuleRaiseAccess.canRaiseOverSort(projectNode.getFirstChild(), metadata, capFinder, node, record, false, context);
        // if we can't raise the access node and this doesn't have a limit, there's no point in optimizing
        if (!raiseAccess && (parent == null || parent.getType() != NodeConstants.Types.TUPLE_LIMIT)) {
            return root;
        }
    } else {
        return root;
    }
    List<Expression> childOutputCols = (List<Expression>) projectNode.getFirstChild().getProperty(Info.OUTPUT_COLS);
    OrderBy orderBy = (OrderBy) node.getProperty(Info.SORT_ORDER);
    List<Expression> orderByKeys = orderBy.getSortKeys();
    LinkedHashSet<Expression> toProject = new LinkedHashSet();
    for (Expression ss : orderByKeys) {
        Expression original = ss;
        if (ss instanceof AliasSymbol) {
            ss = ((AliasSymbol) ss).getSymbol();
        }
        if (ss instanceof ExpressionSymbol) {
            if (!raiseAccess) {
                // TODO: insert a new project node to handle this case
                return root;
            }
        }
        if (!childOutputCols.contains(ss)) {
            if (!raiseAccess) {
                return root;
            }
            toProject.add(original);
        }
    }
    PlanNode toRepair = projectNode.getParent();
    if (!toProject.isEmpty()) {
        PlanNode intermediateProject = NodeFactory.getNewNode(NodeConstants.Types.PROJECT);
        toProject.addAll(childOutputCols);
        List<Expression> projectCols = new ArrayList<Expression>(toProject);
        childOutputCols = projectCols;
        intermediateProject.setProperty(NodeConstants.Info.PROJECT_COLS, projectCols);
        intermediateProject.setProperty(NodeConstants.Info.OUTPUT_COLS, new ArrayList<Expression>(projectCols));
        toRepair.getFirstChild().addAsParent(intermediateProject);
    }
    NodeEditor.removeChildNode(projectNode.getParent(), projectNode);
    if (parent != null && parent.getType() == NodeConstants.Types.TUPLE_LIMIT && parent.getParent() != null) {
        parent.addAsParent(projectNode);
    } else {
        if (parent == null) {
            root = projectNode;
        }
        if (parent != null && parent.getType() == NodeConstants.Types.TUPLE_LIMIT) {
            if (root == parent) {
                root = projectNode;
            }
            projectNode.addFirstChild(parent);
        } else {
            projectNode.addFirstChild(node);
        }
    }
    List<Expression> orderByOutputSymbols = (List<Expression>) node.getProperty(Info.OUTPUT_COLS);
    boolean unrelated = false;
    if (node.hasBooleanProperty(Info.UNRELATED_SORT)) {
        node.setProperty(Info.UNRELATED_SORT, false);
        unrelated = true;
    }
    for (OrderByItem item : orderBy.getOrderByItems()) {
        if (unrelated || !toProject.isEmpty()) {
            // update sort order
            int index = childOutputCols.indexOf(item.getSymbol());
            item.setExpressionPosition(index);
        }
        if (toProject.isEmpty()) {
            // strip alias as project was raised
            if (item.getSymbol() instanceof AliasSymbol) {
                item.setSymbol(((AliasSymbol) item.getSymbol()).getSymbol());
            }
        }
    }
    while (toRepair != node) {
        toRepair.setProperty(Info.OUTPUT_COLS, childOutputCols);
        toRepair = toRepair.getParent();
    }
    projectNode.setProperty(Info.OUTPUT_COLS, orderByOutputSymbols);
    projectNode.setProperty(Info.PROJECT_COLS, orderByOutputSymbols);
    node.setProperty(Info.OUTPUT_COLS, childOutputCols);
    if (parent != null) {
        parent.setProperty(Info.OUTPUT_COLS, childOutputCols);
    }
    if (raiseAccess) {
        PlanNode accessNode = NodeEditor.findNodePreOrder(node, NodeConstants.Types.ACCESS);
        // instead of just calling ruleraiseaccess, we're more selective
        // we do not want to raise the access node over a project that is handling an unrelated sort
        PlanNode newRoot = RuleRaiseAccess.raiseAccessNode(root, accessNode, metadata, capFinder, true, record, context);
        if (newRoot != null) {
            accessNode.setProperty(NodeConstants.Info.OUTPUT_COLS, childOutputCols);
            root = newRoot;
            if (!toProject.isEmpty()) {
                newRoot = RuleRaiseAccess.raiseAccessNode(root, accessNode, metadata, capFinder, true, record, context);
            }
            if (newRoot != null) {
                root = newRoot;
                if (accessNode.getParent().getType() == NodeConstants.Types.TUPLE_LIMIT) {
                    newRoot = RulePushLimit.raiseAccessOverLimit(root, accessNode, metadata, capFinder, accessNode.getParent(), record);
                }
                if (newRoot != null) {
                    root = newRoot;
                }
            }
        }
    }
    return root;
}
Also used : OrderBy(org.teiid.query.sql.lang.OrderBy) LinkedHashSet(java.util.LinkedHashSet) ArrayList(java.util.ArrayList) ExpressionSymbol(org.teiid.query.sql.symbol.ExpressionSymbol) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) AliasSymbol(org.teiid.query.sql.symbol.AliasSymbol) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression) ArrayList(java.util.ArrayList) List(java.util.List)

Example 9 with ExpressionSymbol

use of org.teiid.query.sql.symbol.ExpressionSymbol 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 10 with ExpressionSymbol

use of org.teiid.query.sql.symbol.ExpressionSymbol in project teiid by teiid.

the class TempTable method createTupleSource.

public TupleSource createTupleSource(final List<? extends Expression> projectedCols, final Criteria condition, OrderBy orderBy) throws TeiidComponentException, TeiidProcessingException {
    // special handling for count(*)
    boolean agg = false;
    for (Expression singleElementSymbol : projectedCols) {
        if (singleElementSymbol instanceof ExpressionSymbol && ((ExpressionSymbol) singleElementSymbol).getExpression() instanceof AggregateSymbol) {
            agg = true;
            break;
        }
    }
    if (agg) {
        if (condition == null) {
            long count = this.getRowCount();
            return new CollectionTupleSource(Arrays.asList(Collections.nCopies(projectedCols.size(), (int) Math.min(Integer.MAX_VALUE, count))).iterator());
        }
        orderBy = null;
    }
    IndexInfo primary = new IndexInfo(this, projectedCols, condition, orderBy, true);
    IndexInfo ii = primary;
    if ((indexTables != null || (!this.updatable && allowImplicitIndexing && condition != null && this.getRowCount() > 2 * this.getTree().getPageSize(true))) && (condition != null || orderBy != null) && ii.valueSet.size() != 1) {
        // $NON-NLS-1$ //$NON-NLS-2$
        LogManager.logDetail(LogConstants.CTX_DQP, "Considering indexes on table", this, "for query", projectedCols, condition, orderBy);
        long rowCost = this.tree.getRowCount();
        long bestCost = estimateCost(orderBy, ii, rowCost);
        if (this.indexTables != null) {
            for (TempTable table : this.indexTables.values()) {
                IndexInfo secondary = new IndexInfo(table, projectedCols, condition, orderBy, false);
                long cost = estimateCost(orderBy, secondary, rowCost);
                if (cost < bestCost) {
                    ii = secondary;
                    bestCost = cost;
                }
            }
        }
        if (ii == primary && allowImplicitIndexing) {
            // TODO: detect if it should be covering
            if (createImplicitIndexIfNeeded(condition)) {
                IndexInfo secondary = new IndexInfo(this.indexTables.values().iterator().next(), projectedCols, condition, orderBy, false);
                // $NON-NLS-1$
                LogManager.logDetail(LogConstants.CTX_DQP, "Created an implicit index ", secondary.table);
                long cost = estimateCost(orderBy, secondary, rowCost);
                if (cost < bestCost) {
                    ii = secondary;
                    bestCost = cost;
                } else {
                    // $NON-NLS-1$ //$NON-NLS-2$
                    LogManager.logDetail(LogConstants.CTX_DQP, "Did not utilize the implicit index");
                }
            }
        }
        // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        LogManager.logDetail(LogConstants.CTX_DQP, "Choose index", ii.table, "covering:", ii.coveredCriteria, "ordering:", ii.ordering);
        if (ii.covering) {
            return ii.table.createTupleSource(projectedCols, condition, orderBy, ii, agg);
        }
        List<ElementSymbol> pkColumns = this.columns.subList(0, this.tree.getKeyLength());
        if (ii.ordering != null) {
            // use order and join
            primary.valueTs = ii.table.createTupleSource(pkColumns, ii.coveredCriteria, orderBy, ii, agg);
            primary.ordering = null;
            return createTupleSource(projectedCols, ii.nonCoveredCriteria, null, primary, agg);
        }
        // order by pk to localize lookup costs, then join
        OrderBy pkOrderBy = new OrderBy();
        for (ElementSymbol elementSymbol : pkColumns) {
            pkOrderBy.addVariable(elementSymbol);
        }
        primary.valueTs = ii.table.createTupleSource(pkColumns, ii.coveredCriteria, pkOrderBy, ii, agg);
        return createTupleSource(projectedCols, ii.nonCoveredCriteria, orderBy, primary, agg);
    }
    return createTupleSource(projectedCols, condition, orderBy, ii, agg);
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) OrderBy(org.teiid.query.sql.lang.OrderBy) AggregateSymbol(org.teiid.query.sql.symbol.AggregateSymbol) Expression(org.teiid.query.sql.symbol.Expression) CollectionTupleSource(org.teiid.query.processor.CollectionTupleSource) ExpressionSymbol(org.teiid.query.sql.symbol.ExpressionSymbol)

Aggregations

ExpressionSymbol (org.teiid.query.sql.symbol.ExpressionSymbol)16 Constant (org.teiid.query.sql.symbol.Constant)10 Expression (org.teiid.query.sql.symbol.Expression)9 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)8 ArrayList (java.util.ArrayList)7 List (java.util.List)7 Test (org.junit.Test)6 AliasSymbol (org.teiid.query.sql.symbol.AliasSymbol)5 Function (org.teiid.query.sql.symbol.Function)5 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)4 LinkedHashSet (java.util.LinkedHashSet)3 FunctionDescriptor (org.teiid.query.function.FunctionDescriptor)3 OrderBy (org.teiid.query.sql.lang.OrderBy)3 AggregateSymbol (org.teiid.query.sql.symbol.AggregateSymbol)3 Map (java.util.Map)2 WindowFunction (org.teiid.query.sql.symbol.WindowFunction)2 SymbolMap (org.teiid.query.sql.util.SymbolMap)2 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 LinkedList (java.util.LinkedList)1