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;
}
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();
}
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());
}
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));
}
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);
}
Aggregations