use of org.teiid.api.exception.query.QueryPlannerException 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;
}
use of org.teiid.api.exception.query.QueryPlannerException in project teiid by teiid.
the class RelationalPlanner method planSubqueries.
private void planSubqueries(ProcedureContainer container, Command c, List<SubqueryContainer<?>> subqueries, boolean initial) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
boolean isSourceTemp = c == null && container.getGroup().isTempTable() && metadata.getModelID(container.getGroup().getMetadataID()) == TempMetadataAdapter.TEMP_MODEL;
for (SubqueryContainer<?> subqueryContainer : subqueries) {
if (isSourceTemp) {
if (subqueryContainer.getCommand().getCorrelatedReferences() == null) {
if (subqueryContainer instanceof ScalarSubquery) {
((ScalarSubquery) subqueryContainer).setShouldEvaluate(true);
} else if (subqueryContainer instanceof ExistsCriteria) {
((ExistsCriteria) subqueryContainer).setShouldEvaluate(true);
} else {
throw new QueryPlannerException(QueryPlugin.Event.TEIID30253, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30253, container));
}
} else {
throw new QueryPlannerException(QueryPlugin.Event.TEIID30253, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30253, container));
}
}
if (subqueryContainer.getCommand().getProcessorPlan() == null) {
Command subCommand = initial ? (Command) subqueryContainer.getCommand().clone() : subqueryContainer.getCommand();
ProcessorPlan plan = QueryOptimizer.optimizePlan(subCommand, metadata, null, capFinder, analysisRecord, context);
subqueryContainer.getCommand().setProcessorPlan(plan);
}
if (c == null && !initial) {
RuleCollapseSource.prepareSubquery(subqueryContainer);
}
}
}
use of org.teiid.api.exception.query.QueryPlannerException in project teiid by teiid.
the class AliasGenerator method recontextGroup.
/**
* @param symbol
*/
private String recontextGroup(GroupSymbol symbol, boolean virtual) {
String newAlias = null;
while (true) {
if (virtual) {
newAlias = view_prefix + viewIndex++;
} else {
newAlias = table_prefix + groupIndex++;
}
if (correlationGroups == null || !correlationGroups.contains(newAlias)) {
break;
}
}
if (this.aliasMapping != null && symbol.getDefinition() != null) {
String oldAlias = this.aliasMapping.get(symbol.getName());
if (oldAlias != null) {
newAlias = oldAlias;
if (newAlias.startsWith(table_prefix) || newAlias.startsWith(view_prefix)) {
try {
Integer.parseInt(newAlias.substring(2, newAlias.length()));
throw new TeiidRuntimeException(new QueryPlannerException(QueryPlugin.Event.TEIID31127, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31127, newAlias)));
} catch (NumberFormatException e) {
}
}
}
}
visitor.namingContext.groupNames.put(symbol.getName(), newAlias);
return newAlias;
}
use of org.teiid.api.exception.query.QueryPlannerException in project teiid by teiid.
the class RulePlanJoins method execute.
/**
* @see org.teiid.query.optimizer.relational.OptimizerRule#execute(org.teiid.query.optimizer.relational.plantree.PlanNode, org.teiid.query.metadata.QueryMetadataInterface, org.teiid.query.optimizer.capabilities.CapabilitiesFinder, org.teiid.query.optimizer.relational.RuleStack, org.teiid.query.analysis.AnalysisRecord, org.teiid.query.util.CommandContext)
*/
public PlanNode execute(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
List<JoinRegion> joinRegions = new LinkedList<JoinRegion>();
findJoinRegions(plan, null, joinRegions);
// dependency phase
List<JoinRegion> leftOuterJoinRegions = new LinkedList<JoinRegion>();
for (Iterator<JoinRegion> joinRegionIter = joinRegions.iterator(); joinRegionIter.hasNext(); ) {
JoinRegion joinRegion = joinRegionIter.next();
// skip regions that have nothing to plan
if (joinRegion.getJoinSourceNodes().size() + joinRegion.getDependentJoinSourceNodes().size() < 2) {
joinRegionIter.remove();
if (joinRegion.getLeft() != null) {
leftOuterJoinRegions.add(joinRegion);
}
continue;
}
joinRegion.initializeJoinInformation();
// account for nested table correlations
for (PlanNode joinSource : joinRegion.getJoinSourceNodes().keySet()) {
SymbolMap map = (SymbolMap) joinSource.getProperty(NodeConstants.Info.CORRELATED_REFERENCES);
if (map != null) {
joinSource.setProperty(NodeConstants.Info.REQUIRED_ACCESS_PATTERN_GROUPS, GroupsUsedByElementsVisitor.getGroups(map.getValues()));
joinRegion.setContainsNestedTable(true);
}
}
// check for unsatisfied dependencies
if (joinRegion.getUnsatisfiedAccessPatterns().isEmpty()) {
continue;
}
// quick check for satisfiability
if (!joinRegion.isSatisfiable()) {
throw new QueryPlannerException(QueryPlugin.Event.TEIID30275, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30275, joinRegion.getUnsatisfiedAccessPatterns()));
}
planForDependencies(joinRegion);
}
// optimization phase
for (JoinRegion joinRegion : joinRegions) {
groupJoinsForPushing(metadata, capabilitiesFinder, joinRegion, context);
}
// check for optimizing across left outer joins
for (JoinRegion joinRegion : leftOuterJoinRegions) {
groupAcrossLeftOuter(metadata, capabilitiesFinder, context, joinRegion);
}
for (Iterator<JoinRegion> joinRegionIter = joinRegions.iterator(); joinRegionIter.hasNext(); ) {
JoinRegion joinRegion = joinRegionIter.next();
// move the dependent nodes back into all joinSources
joinRegion.getJoinSourceNodes().putAll(joinRegion.getDependentJoinSourceNodes());
joinRegion.getCriteriaNodes().addAll(joinRegion.getDependentCriteriaNodes());
joinRegion.getDependentJoinSourceNodes().clear();
joinRegion.getDependentCriteriaNodes().clear();
if (joinRegion.getJoinSourceNodes().size() < 2) {
joinRegion.reconstructJoinRegoin();
joinRegionIter.remove();
continue;
}
joinRegion.initializeCostingInformation(metadata);
Object[] bestOrder = findBestJoinOrder(joinRegion, metadata, capabilitiesFinder, context);
// if no best order was found, just stick with how the user entered the query
if (bestOrder == null) {
continue;
}
joinRegion.changeJoinOrder(bestOrder);
joinRegion.reconstructJoinRegoin();
}
return plan;
}
use of org.teiid.api.exception.query.QueryPlannerException in project teiid by teiid.
the class RulePlanJoins method planForDependencies.
/**
* Greedily choose the first set of access patterns that can be satisfied
* TODO: this is greedy. the first access pattern that can be satisfied will be
* TODO: order access patterns by number of dependent groups
*
* If we could flatten to a single set of dependencies, then a topological sort would be faster
*
* @param joinRegion
* @throws QueryPlannerException
*/
private void planForDependencies(JoinRegion joinRegion) throws QueryPlannerException {
if (joinRegion.getJoinSourceNodes().isEmpty()) {
throw new QueryPlannerException(QueryPlugin.Event.TEIID30275, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30275, joinRegion.getUnsatisfiedAccessPatterns()));
}
HashSet<GroupSymbol> currentGroups = new HashSet<GroupSymbol>();
for (PlanNode joinSource : joinRegion.getJoinSourceNodes().keySet()) {
currentGroups.addAll(joinSource.getGroups());
}
HashMap<PlanNode, PlanNode> dependentNodes = new HashMap<PlanNode, PlanNode>(joinRegion.getDependentJoinSourceNodes());
boolean satisfiedAP = true;
while (!dependentNodes.isEmpty() && satisfiedAP) {
satisfiedAP = false;
for (Iterator<Map.Entry<PlanNode, PlanNode>> joinSources = dependentNodes.entrySet().iterator(); joinSources.hasNext(); ) {
Map.Entry<PlanNode, PlanNode> entry = joinSources.next();
PlanNode joinSource = entry.getKey();
Collection accessPatterns = (Collection) joinSource.getProperty(NodeConstants.Info.ACCESS_PATTERNS);
for (Iterator i = accessPatterns.iterator(); i.hasNext(); ) {
AccessPattern ap = (AccessPattern) i.next();
boolean foundGroups = true;
HashSet<GroupSymbol> allRequiredGroups = new HashSet<GroupSymbol>();
for (ElementSymbol symbol : ap.getUnsatisfied()) {
Set<Collection<GroupSymbol>> requiredGroupsSet = joinRegion.getDependentCriteriaElements().get(symbol);
boolean elementSatisfied = false;
if (requiredGroupsSet != null) {
for (Collection<GroupSymbol> requiredGroups : requiredGroupsSet) {
if (currentGroups.containsAll(requiredGroups)) {
elementSatisfied = true;
allRequiredGroups.addAll(requiredGroups);
break;
}
}
}
if (!elementSatisfied) {
foundGroups = false;
break;
}
}
if (!foundGroups) {
continue;
}
joinSources.remove();
currentGroups.addAll(joinSource.getGroups());
satisfiedAP = true;
joinSource.setProperty(NodeConstants.Info.ACCESS_PATTERN_USED, ap.clone());
joinSource.setProperty(NodeConstants.Info.REQUIRED_ACCESS_PATTERN_GROUPS, allRequiredGroups);
break;
}
}
}
if (!dependentNodes.isEmpty()) {
throw new QueryPlannerException(QueryPlugin.Event.TEIID30275, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30275, joinRegion.getUnsatisfiedAccessPatterns()));
}
}
Aggregations