Search in sources :

Example 1 with AccessNode

use of org.teiid.query.processor.relational.AccessNode in project teiid by teiid.

the class RuleRaiseAccess method checkConformedSubqueries.

static boolean checkConformedSubqueries(PlanNode accessNode, PlanNode parentNode, boolean updateConformed) {
    Set<Object> conformedSources = (Set<Object>) accessNode.getProperty(Info.CONFORMED_SOURCES);
    if (conformedSources == null) {
        return true;
    }
    conformedSources = new HashSet<Object>(conformedSources);
    for (SubqueryContainer<?> container : parentNode.getSubqueryContainers()) {
        if (container instanceof ExistsCriteria && ((ExistsCriteria) container).shouldEvaluate()) {
            continue;
        }
        if (container instanceof ScalarSubquery && ((ScalarSubquery) container).shouldEvaluate()) {
            continue;
        }
        ProcessorPlan plan = container.getCommand().getProcessorPlan();
        if (plan == null) {
            continue;
        }
        AccessNode aNode = CriteriaCapabilityValidatorVisitor.getAccessNode(plan);
        if (aNode == null) {
            continue;
        }
        Set<Object> conformedTo = aNode.getConformedTo();
        if (conformedTo == null) {
            conformedSources.retainAll(Collections.singletonList(aNode.getModelId()));
        } else {
            conformedSources.retainAll(conformedTo);
        }
        if (conformedSources.isEmpty()) {
            return false;
        }
    }
    if (updateConformed) {
        updateConformed(accessNode, conformedSources);
    }
    return true;
}
Also used : HashSet(java.util.HashSet) Set(java.util.Set) ScalarSubquery(org.teiid.query.sql.symbol.ScalarSubquery) AccessNode(org.teiid.query.processor.relational.AccessNode) ProcessorPlan(org.teiid.query.processor.ProcessorPlan)

Example 2 with AccessNode

use of org.teiid.query.processor.relational.AccessNode in project teiid by teiid.

the class RelationalPlanner method planWith.

private void planWith(PlanNode plan, Command command) throws QueryPlannerException, QueryMetadataException, TeiidComponentException, QueryResolverException {
    if (this.withPlanningState.withList.isEmpty()) {
        return;
    }
    // TODO: merge this logic inline with the main rule execution.
    RuleStack stack = new RuleStack();
    stack.push(new RuleAssignOutputElements(false));
    if (hints.hasRowBasedSecurity) {
        stack.push(new RuleApplySecurity());
    }
    // use a temporary planner to run just the assign output elements
    RelationalPlanner planner = new RelationalPlanner();
    // we don't want to trigger the with processing for just projection
    planner.processWith = false;
    planner.initialize(command, idGenerator, metadata, capFinder, analysisRecord, context);
    planner.executeRules(stack, plan);
    // discover all of the usage
    List<Command> commands = CommandCollectorVisitor.getCommands(command, true);
    while (!commands.isEmpty()) {
        Command cmd = commands.remove(commands.size() - 1);
        commands.addAll(CommandCollectorVisitor.getCommands(cmd, true));
        try {
            PlanNode temp = planner.generatePlan((Command) cmd.clone());
            stack.push(new RuleAssignOutputElements(false));
            planner.executeRules(stack, temp);
        } catch (TeiidProcessingException e) {
            throw new QueryPlannerException(e);
        }
    }
    // plan and minimize projection
    for (WithQueryCommand with : this.withPlanningState.withList.values()) {
        QueryCommand subCommand = with.getCommand();
        TempMetadataID tid = (TempMetadataID) with.getGroupSymbol().getMetadataID();
        if (tid.getTableData().getModel() != TempMetadataAdapter.TEMP_MODEL) {
            tid.getTableData().setModel(null);
        }
        List<TempMetadataID> elements = tid.getElements();
        List<Integer> toRemove = new ArrayList<Integer>();
        for (int i = elements.size() - 1; i >= 0; i--) {
            TempMetadataID elem = elements.get(i);
            if (!elem.isAccessed()) {
                toRemove.add(i);
            }
        }
        // the definition of the with clause consistent
        if (!toRemove.isEmpty()) {
            if (with.isRecursive()) {
                SetQuery setQuery = (SetQuery) subCommand;
                setQuery.setLeftQuery(removeUnusedProjection(with, setQuery.getLeftQuery(), elements, toRemove));
                setQuery.setRightQuery(removeUnusedProjection(with, setQuery.getRightQuery(), elements, toRemove));
            } else {
                subCommand = removeUnusedProjection(with, subCommand, elements, toRemove);
                with.setCommand(subCommand);
            }
        }
        if (with.isRecursive()) {
            SetQuery setQuery = (SetQuery) subCommand;
            QueryCommand qc = setQuery.getLeftQuery();
            final RelationalPlan subPlan = optimize(qc);
            qc.setProcessorPlan(subPlan);
            AccessNode aNode = CriteriaCapabilityValidatorVisitor.getAccessNode(subPlan);
            Object modelID = null;
            QueryCommand withCommand = null;
            if (aNode != null) {
                modelID = CriteriaCapabilityValidatorVisitor.validateCommandPushdown(null, metadata, capFinder, aNode, false);
                if (modelID != null) {
                    if (with.getGroupSymbol().getModelMetadataId() != null || !CapabilitiesUtil.supports(Capability.RECURSIVE_COMMON_TABLE_EXPRESSIONS, modelID, metadata, capFinder) || with.isMaterialize()) {
                        modelID = null;
                    } else {
                        withCommand = CriteriaCapabilityValidatorVisitor.getQueryCommand(aNode);
                        if (withCommand != null) {
                            // provisionally set the source
                            ((TempMetadataID) with.getGroupSymbol().getMetadataID()).getTableData().setModel(modelID);
                        }
                    }
                }
            }
            // now that we possibly have a model id, plan the recursive part
            QueryCommand qc1 = setQuery.getRightQuery();
            RelationalPlan subPlan1 = optimize((Command) qc1.clone());
            qc1.setProcessorPlan(subPlan1);
            if (!isPushdownValid(with, setQuery, modelID, withCommand, subPlan1) && withCommand != null) {
                // reset the source to null and replan
                ((TempMetadataID) with.getGroupSymbol().getMetadataID()).getTableData().setModel(null);
                subPlan1 = optimize(qc1);
                qc1.setProcessorPlan(subPlan1);
            }
            continue;
        }
        RelationalPlan subPlan = optimize(subCommand);
        subCommand.setProcessorPlan(subPlan);
        RelationalPlan procPlan = subPlan;
        RelationalNode root = procPlan.getRootNode();
        Number planCardinality = root.getEstimateNodeCardinality();
        if (planCardinality != null) {
            ((TempMetadataID) with.getGroupSymbol().getMetadataID()).setCardinality(planCardinality.intValue());
        }
        AccessNode aNode = CriteriaCapabilityValidatorVisitor.getAccessNode(procPlan);
        if (aNode == null) {
            continue;
        }
        Object modelID = CriteriaCapabilityValidatorVisitor.validateCommandPushdown(null, metadata, capFinder, aNode, false);
        QueryCommand withCommand = CriteriaCapabilityValidatorVisitor.getQueryCommand(aNode);
        if (modelID == null || withCommand == null) {
            continue;
        }
        if (with.getGroupSymbol().getModelMetadataId() != null || !CapabilitiesUtil.supports(Capability.COMMON_TABLE_EXPRESSIONS, modelID, metadata, capFinder) || with.isMaterialize()) {
            continue;
        }
        WithQueryCommand wqc = new WithQueryCommand(with.getGroupSymbol(), with.getColumns(), withCommand);
        wqc.setNoInline(with.isNoInline());
        ((TempMetadataID) with.getGroupSymbol().getMetadataID()).getTableData().setModel(modelID);
        this.withPlanningState.pushdownWith.put(with.getGroupSymbol().getName(), wqc);
    }
}
Also used : TempMetadataID(org.teiid.query.metadata.TempMetadataID) RelationalPlan(org.teiid.query.processor.relational.RelationalPlan) TeiidProcessingException(org.teiid.core.TeiidProcessingException) SubqueryAwareRelationalNode(org.teiid.query.processor.relational.SubqueryAwareRelationalNode) RelationalNode(org.teiid.query.processor.relational.RelationalNode) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) CreateProcedureCommand(org.teiid.query.sql.proc.CreateProcedureCommand) LanguageObject(org.teiid.query.sql.LanguageObject) AccessNode(org.teiid.query.processor.relational.AccessNode) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException)

Example 3 with AccessNode

use of org.teiid.query.processor.relational.AccessNode in project teiid by teiid.

the class RelationalPlanner method optimize.

public RelationalPlan optimize(Command command) throws QueryPlannerException, QueryMetadataException, TeiidComponentException, QueryResolverException {
    boolean debug = analysisRecord.recordDebug();
    if (debug) {
        // $NON-NLS-1$
        analysisRecord.println("\n----------------------------------------------------------------------------");
        // $NON-NLS-1$
        analysisRecord.println("GENERATE CANONICAL: \n" + command);
    }
    SourceHint previous = this.sourceHint;
    this.sourceHint = SourceHint.combine(previous, command.getSourceHint());
    PlanToProcessConverter planToProcessConverter = new PlanToProcessConverter(metadata, idGenerator, analysisRecord, capFinder, context);
    WithPlanningState saved = this.withPlanningState;
    this.withPlanningState = new WithPlanningState();
    Command original = (Command) command.clone();
    PlanNode plan;
    try {
        plan = generatePlan(command);
    } catch (TeiidProcessingException e) {
        throw new QueryPlannerException(e);
    }
    planWith(plan, command);
    if (plan.getType() == NodeConstants.Types.SOURCE) {
        // this was effectively a rewrite
        return (RelationalPlan) plan.getProperty(Info.PROCESSOR_PLAN);
    }
    if (debug) {
        // $NON-NLS-1$
        analysisRecord.println("\nCANONICAL PLAN: \n" + plan);
    }
    // Connect ProcessorPlan to SubqueryContainer (if any) of SELECT or PROJECT nodes
    // TODO: merge with node creation
    connectSubqueryContainers(plan);
    // Set top column information on top node
    List<Expression> topCols = Util.deepClone(command.getProjectedSymbols(), Expression.class);
    // Build rule set based on hints
    RuleStack rules = buildRules();
    // Run rule-based optimizer
    plan = executeRules(rules, plan);
    RelationalPlan result = planToProcessConverter.convert(plan);
    boolean fullPushdown = false;
    if (!this.withPlanningState.pushdownWith.isEmpty()) {
        AccessNode aNode = CriteriaCapabilityValidatorVisitor.getAccessNode(result);
        if (aNode != null) {
            QueryCommand queryCommand = CriteriaCapabilityValidatorVisitor.getQueryCommand(aNode);
            if (queryCommand != null) {
                fullPushdown = true;
                for (SubqueryContainer<?> container : ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(queryCommand)) {
                    if (container instanceof Evaluatable<?> && ((Evaluatable<?>) container).shouldEvaluate()) {
                        // we could more deeply check, but we'll just assume that the references are needed
                        fullPushdown = false;
                        break;
                    }
                }
            }
        }
        // distribute the appropriate clauses to the pushdowns
        assignWithClause(result.getRootNode(), this.withPlanningState.pushdownWith, false);
        List<String> toReplan = new ArrayList<String>();
        for (Map.Entry<String, Object> entry : this.withPlanningState.pushdownState.entrySet()) {
            if (Boolean.TRUE.equals(entry.getValue())) {
                GroupSymbol gs = this.withPlanningState.pushdownWith.get(entry.getKey()).getGroupSymbol();
                TempMetadataID tmi = (TempMetadataID) gs.getMetadataID();
                tmi.getTableData().setModel(TempMetadataAdapter.TEMP_MODEL);
                toReplan.add(entry.getKey());
            }
        }
        if (!toReplan.isEmpty()) {
            for (WithQueryCommand wqc : this.withPlanningState.withList.values()) {
                this.context.getGroups().remove(wqc.getGroupSymbol().getName());
            }
            this.sourceHint = previous;
            this.withPlanningState = saved;
            if (debug) {
                // $NON-NLS-1$ //$NON-NLS-2$
                analysisRecord.println("\nReplanning due to multiple common table references: " + toReplan + "\n");
            }
            return optimize(original);
        }
    }
    if (!fullPushdown && !this.withPlanningState.withList.isEmpty()) {
        // generally any with item associated with a pushdown will not be needed as we're converting to a source query
        result.setWith(new ArrayList<WithQueryCommand>(this.withPlanningState.withList.values()));
        // assign any with clauses in this subplan
        for (WithQueryCommand wqc : this.withPlanningState.withList.values()) {
            if (wqc.isRecursive()) {
                SetQuery sq = (SetQuery) wqc.getCommand();
                assignWithClause(((RelationalPlan) sq.getLeftQuery().getProcessorPlan()).getRootNode(), this.withPlanningState.pushdownWith, false);
                assignWithClause(((RelationalPlan) sq.getRightQuery().getProcessorPlan()).getRootNode(), this.withPlanningState.pushdownWith, false);
            } else {
                assignWithClause(((RelationalPlan) wqc.getCommand().getProcessorPlan()).getRootNode(), this.withPlanningState.pushdownWith, false);
            }
        }
    }
    result.setOutputElements(topCols);
    this.sourceHint = previous;
    this.withPlanningState = saved;
    return result;
}
Also used : RelationalPlan(org.teiid.query.processor.relational.RelationalPlan) TeiidProcessingException(org.teiid.core.TeiidProcessingException) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) AccessNode(org.teiid.query.processor.relational.AccessNode) TempMetadataID(org.teiid.query.metadata.TempMetadataID) CreateProcedureCommand(org.teiid.query.sql.proc.CreateProcedureCommand) LanguageObject(org.teiid.query.sql.LanguageObject) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException) SymbolMap(org.teiid.query.sql.util.SymbolMap)

Example 4 with AccessNode

use of org.teiid.query.processor.relational.AccessNode in project teiid by teiid.

the class PreparedPlan method setPlan.

/**
 * Set the ProcessorPlan.
 * @param context
 */
public void setPlan(ProcessorPlan planValue, CommandContext context) {
    plan = planValue;
    this.accessInfo.populate(context, false);
    // TODO: expand this logic
    if (planValue instanceof RelationalPlan) {
        RelationalPlan rp = (RelationalPlan) planValue;
        if (rp.getRootNode() instanceof AccessNode) {
            this.accessInfo.setSensitiveToMetadataChanges(false);
        }
    }
}
Also used : AccessNode(org.teiid.query.processor.relational.AccessNode) RelationalPlan(org.teiid.query.processor.relational.RelationalPlan)

Example 5 with AccessNode

use of org.teiid.query.processor.relational.AccessNode in project teiid by teiid.

the class PreparedStatementRequest method handlePreparedBatchUpdate.

/**
 * There are two cases
 *   if
 *     The source supports preparedBatchUpdate -> just let the command and values pass to the source
 *   else
 *     create a batchedupdatecommand that represents the batch operation
 * @param command
 * @throws QueryMetadataException
 * @throws TeiidComponentException
 * @throws QueryResolverException
 * @throws QueryPlannerException
 * @throws QueryValidatorException
 */
private void handlePreparedBatchUpdate() throws QueryMetadataException, TeiidComponentException, QueryResolverException, QueryPlannerException, QueryValidatorException {
    List<List<?>> paramValues = (List<List<?>>) requestMsg.getParameterValues();
    if (paramValues.isEmpty()) {
        throw new QueryValidatorException(QueryPlugin.Event.TEIID30555, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30555));
    }
    boolean supportPreparedBatchUpdate = false;
    Command command = null;
    if (this.processPlan instanceof RelationalPlan) {
        RelationalPlan rPlan = (RelationalPlan) this.processPlan;
        if (rPlan.getRootNode() instanceof AccessNode) {
            AccessNode aNode = (AccessNode) rPlan.getRootNode();
            String modelName = aNode.getModelName();
            command = aNode.getCommand();
            SourceCapabilities caps = capabilitiesFinder.findCapabilities(modelName);
            supportPreparedBatchUpdate = caps.supportsCapability(SourceCapabilities.Capability.BULK_UPDATE);
            if (supportPreparedBatchUpdate && // only allow the plan if the multi-valued references result in expressions that can be pushed
            !CriteriaCapabilityValidatorVisitor.canPushLanguageObject(command, metadata.getModelID(modelName), metadata, capabilitiesFinder, analysisRecord, false, false, true)) {
                supportPreparedBatchUpdate = false;
            }
        }
    }
    List<Command> commands = new LinkedList<Command>();
    List<VariableContext> contexts = new LinkedList<VariableContext>();
    List<List<Object>> multiValues = new ArrayList<List<Object>>(this.prepPlan.getReferences().size());
    for (List<?> values : paramValues) {
        PreparedStatementRequest.resolveParameterValues(this.prepPlan.getReferences(), values, this.context, this.metadata);
        contexts.add(this.context.getVariableContext());
        if (supportPreparedBatchUpdate) {
            if (multiValues.isEmpty()) {
                for (int i = 0; i < values.size(); i++) {
                    multiValues.add(new ArrayList<Object>(paramValues.size()));
                }
            }
            for (int i = 0; i < values.size(); i++) {
                List<Object> multiValue = multiValues.get(i);
                Object value = this.context.getVariableContext().getGlobalValue(this.prepPlan.getReferences().get(i).getContextSymbol());
                multiValue.add(value);
            }
        } else {
            // just accumulate copies of the command/plan - clones are not necessary
            if (command == null) {
                command = this.prepPlan.getCommand();
            }
            command.setProcessorPlan(this.processPlan);
            commands.add(command);
        }
    }
    if (paramValues.size() > 1) {
        this.context.setVariableContext(new VariableContext());
    }
    if (paramValues.size() == 1) {
        // just use the existing plan, and global reference evaluation
        return;
    }
    if (supportPreparedBatchUpdate) {
        for (int i = 0; i < this.prepPlan.getReferences().size(); i++) {
            Constant c = new Constant(null, this.prepPlan.getReferences().get(i).getType());
            c.setMultiValued(multiValues.get(i));
            this.context.getVariableContext().setGlobalValue(this.prepPlan.getReferences().get(i).getContextSymbol(), c);
        }
        return;
    }
    BatchedUpdateCommand buc = new BatchedUpdateCommand(commands);
    buc.setVariableContexts(contexts);
    BatchedUpdatePlanner planner = new BatchedUpdatePlanner();
    this.processPlan = planner.optimize(buc, idGenerator, metadata, capabilitiesFinder, analysisRecord, context);
}
Also used : Constant(org.teiid.query.sql.symbol.Constant) ArrayList(java.util.ArrayList) RelationalPlan(org.teiid.query.processor.relational.RelationalPlan) VariableContext(org.teiid.query.sql.util.VariableContext) BatchedUpdateCommand(org.teiid.query.sql.lang.BatchedUpdateCommand) LinkedList(java.util.LinkedList) QueryValidatorException(org.teiid.api.exception.query.QueryValidatorException) Command(org.teiid.query.sql.lang.Command) BatchedUpdateCommand(org.teiid.query.sql.lang.BatchedUpdateCommand) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) AccessNode(org.teiid.query.processor.relational.AccessNode) SourceCapabilities(org.teiid.query.optimizer.capabilities.SourceCapabilities) BatchedUpdatePlanner(org.teiid.query.optimizer.BatchedUpdatePlanner)

Aggregations

AccessNode (org.teiid.query.processor.relational.AccessNode)12 RelationalPlan (org.teiid.query.processor.relational.RelationalPlan)8 RelationalNode (org.teiid.query.processor.relational.RelationalNode)4 LanguageObject (org.teiid.query.sql.LanguageObject)4 ProcessorPlan (org.teiid.query.processor.ProcessorPlan)3 CreateProcedureCommand (org.teiid.query.sql.proc.CreateProcedureCommand)3 SymbolMap (org.teiid.query.sql.util.SymbolMap)3 QueryPlannerException (org.teiid.api.exception.query.QueryPlannerException)2 TeiidProcessingException (org.teiid.core.TeiidProcessingException)2 TempMetadataID (org.teiid.query.metadata.TempMetadataID)2 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)2 SubqueryAwareRelationalNode (org.teiid.query.processor.relational.SubqueryAwareRelationalNode)2 Command (org.teiid.query.sql.lang.Command)2 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 Set (java.util.Set)1 Test (org.junit.Test)1 QueryMetadataException (org.teiid.api.exception.query.QueryMetadataException)1