Search in sources :

Example 11 with SourceCapabilities

use of org.teiid.query.optimizer.capabilities.SourceCapabilities in project teiid by teiid.

the class CapabilitiesUtil method supportsAggregateFunction.

public static boolean supportsAggregateFunction(Object modelID, AggregateSymbol aggregate, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException {
    if (metadata.isVirtualModel(modelID)) {
        return false;
    }
    // Find capabilities
    SourceCapabilities caps = getCapabilities(modelID, metadata, capFinder);
    // Check particular function
    Type func = aggregate.getAggregateFunction();
    switch(func) {
        case COUNT:
            if (aggregate.getArgs().length == 0) {
                if (!caps.supportsCapability(Capability.QUERY_AGGREGATES_COUNT_STAR)) {
                    return false;
                }
            } else {
                if (!caps.supportsCapability(Capability.QUERY_AGGREGATES_COUNT)) {
                    return false;
                }
            }
            break;
        case SUM:
            if (!caps.supportsCapability(Capability.QUERY_AGGREGATES_SUM)) {
                return false;
            }
            break;
        case AVG:
            if (!caps.supportsCapability(Capability.QUERY_AGGREGATES_AVG)) {
                return false;
            }
            break;
        case MIN:
            if (!caps.supportsCapability(Capability.QUERY_AGGREGATES_MIN)) {
                return false;
            }
            break;
        case MAX:
            if (!caps.supportsCapability(Capability.QUERY_AGGREGATES_MAX)) {
                return false;
            }
            break;
        case ARRAY_AGG:
            if (!caps.supportsCapability(Capability.QUERY_AGGREGATES_ARRAY)) {
                return false;
            }
            break;
        case STRING_AGG:
            if (!caps.supportsCapability(Capability.QUERY_AGGREGATES_STRING)) {
                return false;
            }
            break;
        case RANK:
        case DENSE_RANK:
        case ROW_NUMBER:
        case FIRST_VALUE:
        case LAST_VALUE:
        case LEAD:
        case LAG:
            if (!caps.supportsCapability(Capability.ELEMENTARY_OLAP)) {
                return false;
            }
            break;
        case USER_DEFINED:
            if (!supportsScalarFunction(modelID, aggregate, metadata, capFinder)) {
                return false;
            }
            break;
        default:
            if (aggregate.isEnhancedNumeric()) {
                if (!caps.supportsCapability(Capability.QUERY_AGGREGATES_ENHANCED_NUMERIC)) {
                    return false;
                }
            } else {
                return false;
            }
            break;
    }
    // Check DISTINCT if necessary
    if (aggregate.isDistinct() && !caps.supportsCapability(Capability.QUERY_AGGREGATES_DISTINCT)) {
        return false;
    }
    if (aggregate.getCondition() != null && !caps.supportsCapability(Capability.ADVANCED_OLAP)) {
        return false;
    }
    // Passed all the checks!
    return true;
}
Also used : Type(org.teiid.query.sql.symbol.AggregateSymbol.Type) JoinType(org.teiid.query.sql.lang.JoinType) SourceCapabilities(org.teiid.query.optimizer.capabilities.SourceCapabilities)

Example 12 with SourceCapabilities

use of org.teiid.query.optimizer.capabilities.SourceCapabilities in project teiid by teiid.

the class CriteriaCapabilityValidatorVisitor method canPushLanguageObject.

public static boolean canPushLanguageObject(LanguageObject obj, Object modelID, final QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord, boolean isJoin, boolean isSelectClause, final boolean multiValuedReferences) throws QueryMetadataException, TeiidComponentException {
    if (obj == null) {
        return true;
    }
    if (modelID == null || metadata.isVirtualModel(modelID)) {
        // Couldn't determine model ID, so give up
        return false;
    }
    String modelName = metadata.getFullName(modelID);
    SourceCapabilities caps = capFinder.findCapabilities(modelName);
    if (caps == null) {
        // this doesn't seem right, but tests were expecting it...
        return true;
    }
    CriteriaCapabilityValidatorVisitor visitor = new CriteriaCapabilityValidatorVisitor(modelID, metadata, capFinder, caps);
    visitor.setCheckEvaluation(!multiValuedReferences);
    visitor.analysisRecord = analysisRecord;
    visitor.isJoin = isJoin;
    visitor.isSelectClause = isSelectClause;
    // we use an array to represent multiple comparision attributes,
    // but we don't want that to inhibit pushdown as we'll account for that later
    // in criteria processing
    final EvaluatableVisitor ev = new EvaluatableVisitor(modelID, metadata, capFinder);
    PreOrPostOrderNavigator nav = new PreOrPostOrderNavigator(visitor, PreOrPostOrderNavigator.POST_ORDER, false) {

        @Override
        public void visit(DependentSetCriteria obj1) {
            if (obj1.hasMultipleAttributes()) {
                Array array = (Array) obj1.getExpression();
                visitNodes(array.getExpressions());
                super.postVisitVisitor(obj1);
            } else {
                super.visit(obj1);
            }
        }

        @Override
        protected void visitNode(LanguageObject obj) {
            if (obj == null) {
                return;
            }
            Determinism d = ev.getDeterminismLevel();
            boolean pushDown = ev.requiresEvaluation(EvaluationLevel.PUSH_DOWN);
            // decend with clean state, then restore
            ev.reset();
            super.visitNode(obj);
            ev.setDeterminismLevel(d);
            if (pushDown) {
                ev.evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
            }
        }

        @Override
        protected void visitVisitor(LanguageObject obj) {
            if (obj == null) {
                return;
            }
            if (!ev.requiresEvaluation(EvaluationLevel.PUSH_DOWN) && ev.getDeterminismLevel() != Determinism.NONDETERMINISTIC) {
                if (obj instanceof ElementSymbol) {
                    ElementSymbol es = (ElementSymbol) obj;
                    if (es.getMetadataID() != null) {
                        try {
                            if (metadata.isMultiSourceElement(es.getMetadataID())) {
                                // no need to visit
                                return;
                            }
                        } catch (QueryMetadataException e) {
                        } catch (TeiidComponentException e) {
                        }
                    }
                }
                obj.acceptVisitor(ev);
                if (!multiValuedReferences && obj instanceof Expression) {
                    if (obj instanceof Function) {
                        if (!(obj instanceof AggregateSymbol)) {
                            Function f = (Function) obj;
                            if (f.getFunctionDescriptor().getPushdown() != PushDown.MUST_PUSHDOWN && f.getFunctionDescriptor().getDeterministic() != Determinism.NONDETERMINISTIC) {
                                // don't need to consider
                                return;
                            }
                        }
                    } else if (obj instanceof Criteria && !(obj instanceof SubqueryContainer) && !(obj instanceof DependentSetCriteria)) {
                        // don't need to consider
                        return;
                    }
                }
            }
            super.visitVisitor(obj);
        }
    };
    obj.acceptVisitor(nav);
    if (visitor.getException() != null) {
        throw visitor.getException();
    }
    return visitor.isValid();
}
Also used : Determinism(org.teiid.metadata.FunctionMethod.Determinism) QueryMetadataException(org.teiid.api.exception.query.QueryMetadataException) EvaluatableVisitor(org.teiid.query.sql.visitor.EvaluatableVisitor) PreOrPostOrderNavigator(org.teiid.query.sql.navigator.PreOrPostOrderNavigator) TeiidComponentException(org.teiid.core.TeiidComponentException) SourceCapabilities(org.teiid.query.optimizer.capabilities.SourceCapabilities) LanguageObject(org.teiid.query.sql.LanguageObject)

Example 13 with SourceCapabilities

use of org.teiid.query.optimizer.capabilities.SourceCapabilities in project teiid by teiid.

the class BatchedUpdatePlanner method optimize.

/**
 * Optimizes batched updates by batching all contiguous commands that relate to the same physical model.
 * For example, for the following batch of commands:
 * <br/>
 * <ol>
 *      <li>1.  INSERT INTO physicalModel.myPhysical ...</li>
 *      <li>2.  UPDATE physicalModel.myPhysical ... </li>
 *      <li>3.  DELETE FROM virtualmodel.myVirtual ... </li>
 *      <li>4.  UPDATE virtualmodel.myVirtual ... </li>
 *      <li>5.  UPDATE physicalModel.myOtherPhysical ...</li>
 *      <li>6.  INSERT INTO physicalModel.myOtherPhysical ... <li>
 *      <li>7.  DELETE FROM physicalModel.myOtherPhysical ...</li>
 *      <li>8.  INSERT INTO physicalModel.myPhysical ... </li>
 *      <li>9.  INSERT INTO physicalModel.myPhysical ... </li>
 *      <li>10. INSERT INTO physicalModel.myPhysical ... </li>
 *      <li>11. INSERT INTO physicalModel.myPhysical ... </li>
 *      <li>12. INSERT INTO physicalModel.myPhysical ... </li>
 * </ol>
 * <br/> this implementation will batch as follows: (1,2), (5, 6, 7), (8 thru 12).
 * The remaining commands/plans will be executed individually.
 * @see org.teiid.query.optimizer.CommandPlanner#optimize(Command, org.teiid.core.id.IDGenerator, org.teiid.query.metadata.QueryMetadataInterface, org.teiid.query.optimizer.capabilities.CapabilitiesFinder, org.teiid.query.analysis.AnalysisRecord, CommandContext)
 * @since 4.2
 */
public ProcessorPlan optimize(Command command, IDGenerator idGenerator, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
    BatchedUpdateCommand batchedUpdateCommand = (BatchedUpdateCommand) command;
    List<ProcessorPlan> childPlans = new ArrayList<ProcessorPlan>(batchedUpdateCommand.getUpdateCommands().size());
    List<Command> updateCommands = batchedUpdateCommand.getUpdateCommands();
    int numCommands = updateCommands.size();
    List<VariableContext> allContexts = batchedUpdateCommand.getVariableContexts();
    List<VariableContext> planContexts = null;
    if (allContexts != null) {
        planContexts = new ArrayList<VariableContext>(allContexts.size());
    }
    for (int commandIndex = 0; commandIndex < numCommands; commandIndex++) {
        // Potentially the first command of a batch
        Command updateCommand = updateCommands.get(commandIndex);
        boolean commandWasBatched = false;
        // If this command can be placed in a batch
        if (isEligibleForBatching(updateCommand, metadata)) {
            // Get the model ID. Subsequent and contiguous commands that update a group in this model are candidates for this batch
            Object batchModelID = metadata.getModelID(getUpdatedGroup(updateCommand).getMetadataID());
            String modelName = metadata.getFullName(batchModelID);
            SourceCapabilities caps = capFinder.findCapabilities(modelName);
            // Only attempt batching if the source supports batching
            if (caps.supportsCapability(Capability.BATCHED_UPDATES)) {
                // Start a new batch
                List<Command> batch = new ArrayList<Command>();
                List<VariableContext> contexts = new ArrayList<VariableContext>();
                List<Boolean> shouldEvaluate = new ArrayList<Boolean>();
                // This is the first command in a potential batch, so add it to the batch
                batch.add(updateCommand);
                if (allContexts != null) {
                    contexts.add(allContexts.get(commandIndex));
                    shouldEvaluate.add(Boolean.TRUE);
                } else {
                    shouldEvaluate.add(EvaluatableVisitor.needsProcessingEvaluation(updateCommand));
                }
                // immediately and contiguously after this one
                batchLoop: for (int batchIndex = commandIndex + 1; batchIndex < numCommands; batchIndex++) {
                    Command batchingCandidate = updateCommands.get(batchIndex);
                    // If this command updates the same model, and is eligible for batching, add it to the batch
                    if (canBeAddedToBatch(batchingCandidate, batchModelID, metadata, capFinder)) {
                        batch.add(batchingCandidate);
                        if (allContexts != null) {
                            contexts.add(allContexts.get(batchIndex));
                            shouldEvaluate.add(Boolean.TRUE);
                        } else {
                            shouldEvaluate.add(EvaluatableVisitor.needsProcessingEvaluation(batchingCandidate));
                        }
                    } else {
                        // Otherwise, stop batching at this point. The next command may well be the start of a new batch
                        break batchLoop;
                    }
                }
                // If two or more contiguous commands made on the same model were found, then batch them
                if (batch.size() > 1) {
                    ProjectNode projectNode = new ProjectNode(idGenerator.nextInt());
                    // Create a BatchedUpdateNode that creates a batched request for the connector
                    BatchedUpdateNode batchNode = new BatchedUpdateNode(idGenerator.nextInt(), batch, contexts, shouldEvaluate, modelName);
                    List symbols = batchedUpdateCommand.getProjectedSymbols();
                    projectNode.setSelectSymbols(symbols);
                    projectNode.setElements(symbols);
                    batchNode.setElements(symbols);
                    projectNode.addChild(batchNode);
                    // Add a new RelationalPlan that represents the plan for this batch.
                    childPlans.add(new RelationalPlan(projectNode));
                    if (planContexts != null) {
                        planContexts.add(new VariableContext());
                    }
                    // Skip those commands that were added to this batch
                    commandIndex += batch.size() - 1;
                    commandWasBatched = true;
                }
            }
        }
        if (!commandWasBatched) {
            // If the command wasn't batched, just add the plan for this command to the list of plans
            Command cmd = batchedUpdateCommand.getUpdateCommands().get(commandIndex);
            ProcessorPlan plan = cmd.getProcessorPlan();
            if (plan == null) {
                plan = QueryOptimizer.optimizePlan(cmd, metadata, idGenerator, capFinder, analysisRecord, context);
            }
            childPlans.add(plan);
            if (allContexts != null) {
                planContexts.add(allContexts.get(commandIndex));
            }
        }
    }
    return new BatchedUpdatePlan(childPlans, batchedUpdateCommand.getUpdateCommands().size(), planContexts, batchedUpdateCommand.isSingleResult());
}
Also used : ArrayList(java.util.ArrayList) VariableContext(org.teiid.query.sql.util.VariableContext) RelationalPlan(org.teiid.query.processor.relational.RelationalPlan) BatchedUpdateCommand(org.teiid.query.sql.lang.BatchedUpdateCommand) Command(org.teiid.query.sql.lang.Command) BatchedUpdateCommand(org.teiid.query.sql.lang.BatchedUpdateCommand) BatchedUpdateNode(org.teiid.query.processor.relational.BatchedUpdateNode) ProjectNode(org.teiid.query.processor.relational.ProjectNode) ArrayList(java.util.ArrayList) List(java.util.List) SourceCapabilities(org.teiid.query.optimizer.capabilities.SourceCapabilities) ProcessorPlan(org.teiid.query.processor.ProcessorPlan) BatchedUpdatePlan(org.teiid.query.processor.BatchedUpdatePlan)

Example 14 with SourceCapabilities

use of org.teiid.query.optimizer.capabilities.SourceCapabilities in project teiid by teiid.

the class TestConnectorCapabilitiesFinder method testFind.

@Test
public void testFind() throws Exception {
    // $NON-NLS-1$
    String modelName = "model";
    // $NON-NLS-1$
    String functionName = "fakeFunction";
    BasicSourceCapabilities caps = new BasicSourceCapabilities();
    // $NON-NLS-1$
    caps.setFunctionSupport("fakeFunction", true);
    ArrayList<String> bindings = new ArrayList<String>();
    bindings.add(modelName);
    VDBMetaData vdb = Mockito.mock(VDBMetaData.class);
    ModelMetaData model = Mockito.mock(ModelMetaData.class);
    Mockito.stub(vdb.getModel(modelName)).toReturn(model);
    Mockito.stub(model.getSourceNames()).toReturn(bindings);
    BasicSourceCapabilities basicSourceCapabilities = new BasicSourceCapabilities();
    basicSourceCapabilities.setFunctionSupport(functionName, true);
    ConnectorManagerRepository repo = Mockito.mock(ConnectorManagerRepository.class);
    ConnectorManager cm = Mockito.mock(ConnectorManager.class);
    Mockito.stub(cm.getCapabilities()).toReturn(basicSourceCapabilities);
    Mockito.stub(repo.getConnectorManager(Mockito.anyString())).toReturn(cm);
    CachedFinder finder = new CachedFinder(repo, vdb);
    // Test
    SourceCapabilities actual = finder.findCapabilities(modelName);
    // $NON-NLS-1$
    assertEquals("Did not get expected capabilities", true, actual.supportsFunction(functionName));
    assertTrue(finder.isValid(modelName));
}
Also used : BasicSourceCapabilities(org.teiid.query.optimizer.capabilities.BasicSourceCapabilities) ConnectorManagerRepository(org.teiid.dqp.internal.datamgr.ConnectorManagerRepository) VDBMetaData(org.teiid.adminapi.impl.VDBMetaData) ArrayList(java.util.ArrayList) ConnectorManager(org.teiid.dqp.internal.datamgr.ConnectorManager) SourceCapabilities(org.teiid.query.optimizer.capabilities.SourceCapabilities) BasicSourceCapabilities(org.teiid.query.optimizer.capabilities.BasicSourceCapabilities) ModelMetaData(org.teiid.adminapi.impl.ModelMetaData) Test(org.junit.Test)

Example 15 with SourceCapabilities

use of org.teiid.query.optimizer.capabilities.SourceCapabilities in project teiid by teiid.

the class TestDefaultCapabilitiesFinder method testFindCapabilities.

public void testFindCapabilities() throws Exception {
    CapabilitiesFinder capFinder = new DefaultCapabilitiesFinder();
    // $NON-NLS-1$
    SourceCapabilities caps = capFinder.findCapabilities("blah");
    // $NON-NLS-1$
    assertNotNull("Default capabilities should not be null", caps);
}
Also used : CapabilitiesFinder(org.teiid.query.optimizer.capabilities.CapabilitiesFinder) DefaultCapabilitiesFinder(org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder) SourceCapabilities(org.teiid.query.optimizer.capabilities.SourceCapabilities) DefaultCapabilitiesFinder(org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder)

Aggregations

SourceCapabilities (org.teiid.query.optimizer.capabilities.SourceCapabilities)16 ArrayList (java.util.ArrayList)4 ModelMetaData (org.teiid.adminapi.impl.ModelMetaData)4 VDBMetaData (org.teiid.adminapi.impl.VDBMetaData)4 List (java.util.List)3 TeiidComponentException (org.teiid.core.TeiidComponentException)3 ConnectorManager (org.teiid.dqp.internal.datamgr.ConnectorManager)3 BasicSourceCapabilities (org.teiid.query.optimizer.capabilities.BasicSourceCapabilities)3 Constant (org.teiid.query.sql.symbol.Constant)3 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)3 Expression (org.teiid.query.sql.symbol.Expression)3 Test (org.junit.Test)2 QueryMetadataException (org.teiid.api.exception.query.QueryMetadataException)2 TeiidRuntimeException (org.teiid.core.TeiidRuntimeException)2 ConnectorManagerRepository (org.teiid.dqp.internal.datamgr.ConnectorManagerRepository)2 CapabilitiesFinder (org.teiid.query.optimizer.capabilities.CapabilitiesFinder)2 ProcessorPlan (org.teiid.query.processor.ProcessorPlan)2 RelationalPlan (org.teiid.query.processor.relational.RelationalPlan)2 BatchedUpdateCommand (org.teiid.query.sql.lang.BatchedUpdateCommand)2 Command (org.teiid.query.sql.lang.Command)2