Search in sources :

Example 21 with QueryPlannerException

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

the class RuleAccessPatternValidation method validateAccessPatterns.

/**
 * @param node
 * @throws QueryPlannerException
 */
private void validateAccessPatterns(PlanNode node) throws QueryPlannerException {
    if (!node.hasCollectionProperty(NodeConstants.Info.ACCESS_PATTERNS)) {
        return;
    }
    Criteria criteria = null;
    if (node.hasProperty(NodeConstants.Info.ATOMIC_REQUEST)) {
        Object req = node.getProperty(NodeConstants.Info.ATOMIC_REQUEST);
        if (req instanceof Insert) {
            return;
        }
        if (req instanceof Delete) {
            criteria = ((Delete) req).getCriteria();
        } else if (req instanceof Update) {
            criteria = ((Update) req).getCriteria();
        }
    }
    List accessPatterns = (List) node.getProperty(NodeConstants.Info.ACCESS_PATTERNS);
    if (criteria != null) {
        for (Criteria crit : Criteria.separateCriteriaByAnd(criteria)) {
            Collection<ElementSymbol> elements = ElementCollectorVisitor.getElements(crit, true);
            if (RulePushSelectCriteria.satisfyAccessPatterns(accessPatterns, elements)) {
                return;
            }
        }
    }
    Object groups = node.getGroups();
    throw new QueryPlannerException(QueryPlugin.Event.TEIID30278, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30278, new Object[] { groups, accessPatterns }));
}
Also used : Delete(org.teiid.query.sql.lang.Delete) ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) List(java.util.List) Criteria(org.teiid.query.sql.lang.Criteria) Insert(org.teiid.query.sql.lang.Insert) Update(org.teiid.query.sql.lang.Update) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException)

Example 22 with QueryPlannerException

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

the class RuleApplySecurity method execute.

@Override
public PlanNode execute(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
    try {
        for (PlanNode sourceNode : NodeEditor.findAllNodes(plan, NodeConstants.Types.SOURCE)) {
            GroupSymbol group = sourceNode.getGroups().iterator().next();
            if (!RowBasedSecurityHelper.applyRowSecurity(metadata, group, context)) {
                continue;
            }
            List<ElementSymbol> cols = null;
            Command command = (Command) sourceNode.getProperty(Info.VIRTUAL_COMMAND);
            if (group.isProcedure()) {
                if (command == null) {
                    // proc relational, will instead apply at the proc level
                    continue;
                }
                if (cols == null) {
                    cols = (List) command.getProjectedSymbols();
                }
            } else if (command != null && !command.returnsResultSet()) {
                // should be handled in the planner
                continue;
            }
            if (cols == null) {
                cols = ResolverUtil.resolveElementsInGroup(group, metadata);
            }
            // apply masks first
            List<? extends Expression> masked = ColumnMaskingHelper.maskColumns(cols, group, metadata, context);
            Map<ElementSymbol, Expression> mapping = null;
            // TODO: we don't actually allow window function masks yet becuase they won't pass
            // validation.  but if we do, we need to check for them here
            List<WindowFunction> windowFunctions = new ArrayList<WindowFunction>(2);
            for (int i = 0; i < masked.size(); i++) {
                Expression maskedCol = masked.get(i);
                AggregateSymbolCollectorVisitor.getAggregates(maskedCol, null, null, null, windowFunctions, null);
                if (maskedCol.equals(cols.get(i))) {
                    continue;
                }
                if (mapping == null) {
                    mapping = new HashMap<ElementSymbol, Expression>();
                }
                mapping.put(cols.get(i), maskedCol);
            }
            PlanNode parentJoin = NodeEditor.findParent(sourceNode.getParent(), NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE);
            if (mapping != null) {
                // some element symbol has been replaced
                PlanNode project = null;
                if (group.isProcedure()) {
                    project = NodeEditor.findParent(sourceNode, NodeConstants.Types.PROJECT);
                    project.setProperty(NodeConstants.Info.PROJECT_COLS, masked);
                }
                if (windowFunctions.isEmpty() && RuleMergeVirtual.checkProjectedSymbols(group, parentJoin, metadata, masked, Collections.singleton(group), true)) {
                    if (!group.isProcedure()) {
                        // just upwardly project - TODO: we could also handle some subquery simple projection situations here
                        FrameUtil.convertFrame(sourceNode.getParent(), group, Collections.singleton(group), mapping, metadata);
                    }
                } else {
                    if (!group.isProcedure()) {
                        project = RelationalPlanner.createProjectNode(masked);
                    }
                    rules.getPlanner().planSubqueries(sourceNode.getGroups(), project, project.getSubqueryContainers(), true);
                    project.addGroups(GroupsUsedByElementsVisitor.getGroups(project.getCorrelatedReferenceElements()));
                    if (!group.isProcedure()) {
                        // we need to insert a view to give a single place to evaluate the subqueries
                        PlanNode root = sourceNode;
                        if (sourceNode.getParent().getType() == NodeConstants.Types.ACCESS) {
                            root = sourceNode.getParent();
                        }
                        root.addAsParent(project);
                        addView(metadata, context, group, cols, masked, project);
                        parentJoin = null;
                    }
                }
                if (!windowFunctions.isEmpty() && project != null) {
                    project.setProperty(Info.HAS_WINDOW_FUNCTIONS, true);
                }
            }
            // logically filters are applied below masking
            Criteria filter = RowBasedSecurityHelper.getRowBasedFilters(metadata, group, context, false);
            if (filter == null) {
                continue;
            }
            List<Criteria> crits = Criteria.separateCriteriaByAnd(filter);
            PlanNode root = sourceNode;
            if (sourceNode.getParent().getType() == NodeConstants.Types.ACCESS) {
                root = sourceNode.getParent();
            }
            PlanNode parent = null;
            for (Criteria crit : crits) {
                PlanNode critNode = RelationalPlanner.createSelectNode(crit, false);
                if (parent == null) {
                    parent = critNode;
                }
                rules.getPlanner().planSubqueries(sourceNode.getGroups(), critNode, critNode.getSubqueryContainers(), true);
                critNode.addGroups(GroupsUsedByElementsVisitor.getGroups(critNode.getCorrelatedReferenceElements()));
                root.addAsParent(critNode);
            }
            if (!RuleMergeVirtual.checkJoinCriteria(parent, group, parentJoin)) {
                PlanNode project = RelationalPlanner.createProjectNode(cols);
                parent.addAsParent(project);
                // a view is needed to keep the logical placement of the criteria
                addView(metadata, context, group, cols, cols, project);
            }
        }
    } catch (TeiidProcessingException e) {
        throw new QueryPlannerException(e);
    }
    return plan;
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) ArrayList(java.util.ArrayList) Criteria(org.teiid.query.sql.lang.Criteria) TeiidProcessingException(org.teiid.core.TeiidProcessingException) WindowFunction(org.teiid.query.sql.symbol.WindowFunction) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Command(org.teiid.query.sql.lang.Command) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException)

Example 23 with QueryPlannerException

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

the class RuleAssignOutputElements method determineSourceOutput.

/**
 * A special case to consider is when the virtual group is defined by a
 * UNION (no ALL) or a SELECT DISTINCT.  In this case, the dup removal means
 * that all columns need to be used to determine duplicates.  So, filtering the
 * columns at all will alter the number of rows flowing through the frame.
 * So, in this case filtering should not occur.  In fact the output columns
 * that were set on root above are filtered, but we actually want all the
 * virtual elements - so just reset it and proceed as before
 * @throws TeiidComponentException
 * @throws QueryMetadataException
 * @throws QueryPlannerException
 */
static List<? extends Expression> determineSourceOutput(PlanNode root, List<Expression> outputElements, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    PlanNode virtualRoot = root.getLastChild();
    if (hasDupRemoval(virtualRoot)) {
        // Reset the outputColumns for this source node to be all columns for the virtual group
        SymbolMap symbolMap = (SymbolMap) root.getProperty(NodeConstants.Info.SYMBOL_MAP);
        if (!symbolMap.asMap().keySet().containsAll(outputElements)) {
            outputElements.removeAll(symbolMap.asMap().keySet());
            throw new QueryPlannerException(QueryPlugin.Event.TEIID30259, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30259, outputElements));
        }
        return symbolMap.getKeys();
    }
    PlanNode limit = NodeEditor.findNodePreOrder(root, NodeConstants.Types.TUPLE_LIMIT, NodeConstants.Types.PROJECT);
    if (limit == null) {
        return outputElements;
    }
    // reset the output elements to be the output columns + what's required by the sort
    PlanNode sort = NodeEditor.findNodePreOrder(limit, NodeConstants.Types.SORT, NodeConstants.Types.PROJECT);
    if (sort == null) {
        return outputElements;
    }
    PlanNode access = NodeEditor.findParent(sort, NodeConstants.Types.ACCESS);
    if (sort.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT) || (access != null && capFinder != null && CapabilitiesUtil.supports(Capability.QUERY_ORDERBY_UNRELATED, RuleRaiseAccess.getModelIDFromAccess(access, metadata), metadata, capFinder))) {
        return outputElements;
    }
    OrderBy sortOrder = (OrderBy) sort.getProperty(NodeConstants.Info.SORT_ORDER);
    List<Expression> topCols = FrameUtil.findTopCols(sort);
    SymbolMap symbolMap = (SymbolMap) root.getProperty(NodeConstants.Info.SYMBOL_MAP);
    List<ElementSymbol> symbolOrder = symbolMap.getKeys();
    for (OrderByItem item : sortOrder.getOrderByItems()) {
        final Expression expr = item.getSymbol();
        int index = topCols.indexOf(expr);
        if (index < 0) {
            continue;
        }
        ElementSymbol symbol = symbolOrder.get(index);
        if (!outputElements.contains(symbol)) {
            outputElements.add(symbol);
        }
    }
    return outputElements;
}
Also used : OrderBy(org.teiid.query.sql.lang.OrderBy) ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) OrderByItem(org.teiid.query.sql.lang.OrderByItem) Expression(org.teiid.query.sql.symbol.Expression) SymbolMap(org.teiid.query.sql.util.SymbolMap) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException)

Example 24 with QueryPlannerException

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

the class QueryOptimizer method planProcedure.

private static ProcessorPlan planProcedure(Command command, QueryMetadataInterface metadata, IDGenerator idGenerator, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord, CommandContext context) throws TeiidComponentException, QueryPlannerException, QueryMetadataException {
    ProcessorPlan result;
    try {
        command = QueryRewriter.rewrite(command, metadata, context);
    } catch (TeiidProcessingException e) {
        throw new QueryPlannerException(e);
    }
    result = PROCEDURE_PLANNER.optimize(command, idGenerator, metadata, capFinder, analysisRecord, context);
    return result;
}
Also used : ProcessorPlan(org.teiid.query.processor.ProcessorPlan) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) TeiidProcessingException(org.teiid.core.TeiidProcessingException)

Example 25 with QueryPlannerException

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

the class QueryOptimizer method optimizePlan.

public static ProcessorPlan optimizePlan(Command command, QueryMetadataInterface metadata, IDGenerator idGenerator, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    if (analysisRecord == null) {
        analysisRecord = new AnalysisRecord(false, false);
    }
    if (context == null) {
        context = new CommandContext();
    }
    if (!(capFinder instanceof TempCapabilitiesFinder)) {
        capFinder = new TempCapabilitiesFinder(capFinder);
    }
    boolean debug = analysisRecord.recordDebug();
    if (!(metadata instanceof TempMetadataAdapter)) {
        metadata = new TempMetadataAdapter(metadata, new TempMetadataStore());
    }
    if (context.getMetadata() == null) {
        context.setMetadata(metadata);
    }
    // Create an ID generator that can be used for all plans to generate unique data node IDs
    if (idGenerator == null) {
        idGenerator = new IDGenerator();
    }
    if (debug) {
        // $NON-NLS-1$
        analysisRecord.println("\n----------------------------------------------------------------------------");
        // $NON-NLS-1$
        analysisRecord.println("OPTIMIZE: \n" + command);
    }
    if (command instanceof Insert) {
        Insert insert = (Insert) command;
        if (insert.isUpsert()) {
            // if not supported or there are trigger actions, then rewrite as a procedure
            // we do this here since we're changing the command type.
            // TODO: we could push this back into the rewrite, but it will need to be capabilities aware
            GroupSymbol group = insert.getGroup();
            Object modelId = metadata.getModelID(group.getMetadataID());
            boolean supportsUpsert = CapabilitiesUtil.supports(Capability.UPSERT, modelId, metadata, capFinder);
            if (!supportsUpsert) {
                try {
                    command = QueryRewriter.rewriteAsUpsertProcedure(insert, metadata, context);
                } catch (TeiidProcessingException e) {
                    throw new QueryPlannerException(e);
                }
                if (debug) {
                    // $NON-NLS-1$
                    analysisRecord.println("\n----------------------------------------------------------------------------");
                    // $NON-NLS-1$
                    analysisRecord.println("OPTIMIZE UPSERT PROCEDURE: \n" + command);
                }
            }
        }
    }
    ProcessorPlan result = null;
    switch(command.getType()) {
        case Command.TYPE_UPDATE_PROCEDURE:
            CreateProcedureCommand cupc = (CreateProcedureCommand) command;
            if (cupc.getUpdateType() != Command.TYPE_UNKNOWN || cupc.getVirtualGroup() == null) {
                // row update procedure or anon block
                result = planProcedure(command, metadata, idGenerator, capFinder, analysisRecord, context);
            } else {
                Object pid = cupc.getVirtualGroup().getMetadataID();
                if (pid instanceof TempMetadataID) {
                    TempMetadataID tid = (TempMetadataID) pid;
                    if (tid.getOriginalMetadataID() != null) {
                        pid = tid.getOriginalMetadataID();
                    }
                }
                String fullName = metadata.getFullName(pid);
                // $NON-NLS-1$
                fullName = "procedure cache:" + fullName;
                PreparedPlan pp = context.getPlan(fullName);
                if (pp == null) {
                    Determinism determinismLevel = context.resetDeterminismLevel();
                    try {
                        CommandContext clone = context.clone();
                        ProcessorPlan plan = planProcedure(command, metadata, idGenerator, capFinder, analysisRecord, clone);
                        // note that this is not a full prepared plan.  It is not usable by user queries.
                        if (pid instanceof Procedure) {
                            clone.accessedPlanningObject(pid);
                        }
                        pp = new PreparedPlan();
                        pp.setPlan(plan, clone);
                        context.putPlan(fullName, pp, context.getDeterminismLevel());
                    } finally {
                        context.setDeterminismLevel(determinismLevel);
                    }
                }
                result = pp.getPlan().clone();
                for (Object id : pp.getAccessInfo().getObjectsAccessed()) {
                    context.accessedPlanningObject(id);
                }
            }
            break;
        case Command.TYPE_BATCHED_UPDATE:
            result = BATCHED_UPDATE_PLANNER.optimize(command, idGenerator, metadata, capFinder, analysisRecord, context);
            break;
        case Command.TYPE_ALTER_PROC:
        case Command.TYPE_ALTER_TRIGGER:
        case Command.TYPE_ALTER_VIEW:
            result = DDL_PLANNER.optimize(command, idGenerator, metadata, capFinder, analysisRecord, context);
            break;
        case Command.TYPE_SOURCE_EVENT:
            result = SOURCE_EVENT_PLANNER.optimize(command, idGenerator, metadata, capFinder, analysisRecord, context);
            break;
        default:
            try {
                RelationalPlanner planner = new RelationalPlanner();
                planner.initialize(command, idGenerator, metadata, capFinder, analysisRecord, context);
                result = planner.optimize(command);
            } catch (QueryResolverException e) {
                throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30245, e);
            }
    }
    if (debug) {
        // $NON-NLS-1$
        analysisRecord.println("\n----------------------------------------------------------------------------");
        // $NON-NLS-1$
        analysisRecord.println("OPTIMIZATION COMPLETE:");
        // $NON-NLS-1$
        analysisRecord.println("PROCESSOR PLAN:\n" + result);
        // $NON-NLS-1$
        analysisRecord.println("============================================================================");
    }
    return result;
}
Also used : TempMetadataAdapter(org.teiid.query.metadata.TempMetadataAdapter) AnalysisRecord(org.teiid.query.analysis.AnalysisRecord) Determinism(org.teiid.metadata.FunctionMethod.Determinism) CommandContext(org.teiid.query.util.CommandContext) CreateProcedureCommand(org.teiid.query.sql.proc.CreateProcedureCommand) TempMetadataID(org.teiid.query.metadata.TempMetadataID) TempCapabilitiesFinder(org.teiid.query.metadata.TempCapabilitiesFinder) TeiidRuntimeException(org.teiid.core.TeiidRuntimeException) Insert(org.teiid.query.sql.lang.Insert) QueryResolverException(org.teiid.api.exception.query.QueryResolverException) TeiidProcessingException(org.teiid.core.TeiidProcessingException) RelationalPlanner(org.teiid.query.optimizer.relational.RelationalPlanner) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) PreparedPlan(org.teiid.dqp.internal.process.PreparedPlan) Procedure(org.teiid.metadata.Procedure) ProcessorPlan(org.teiid.query.processor.ProcessorPlan) IDGenerator(org.teiid.core.id.IDGenerator) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) TempMetadataStore(org.teiid.query.metadata.TempMetadataStore)

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