use of org.teiid.query.optimizer.relational.RuleStack in project teiid by teiid.
the class TestRuleAccessPatternValidation method helpPlan.
/**
* Parses and resolves the command, creates a canonical relational plan,
* and runs some of the optimizer rules, ending with the
* RuleChooseAccessPattern.
* @param command String command to parse, resolve and use for planning
* @param rules empty RuleStack
* @param groups Collection to add parsed and resolved GroupSymbols to
* @return the root PlanNode of the query plan
*/
private PlanNode helpPlan(String command) throws Exception {
Command query = QueryParser.getQueryParser().parseCommand(command);
QueryResolver.resolveCommand(query, METADATA);
// Generate canonical plan
RelationalPlanner p = new RelationalPlanner();
p.initialize(query, null, METADATA, FINDER, null, new CommandContext());
PlanNode planNode = p.generatePlan(query);
RelationalPlanner planner = new RelationalPlanner();
final RuleStack rules = planner.buildRules();
PlanNode testPlan = helpExecuteRules(rules, planNode, METADATA, DEBUG);
return testPlan;
}
use of org.teiid.query.optimizer.relational.RuleStack in project teiid by teiid.
the class TestRuleChooseDependent method helpTestChooseSiblingAndMarkDependent.
/**
* Tests choosing from two eligible sibling access nodes, and then tests marking
* the chosen one dependent. This method sets up a bogus plan tree using a
* bogus project parent node, a join node using the supplied join criteria, and
* two access nodes using each of the groups and (optional) atomic criteria and
* join criteria. Then
* this method tests that, if an access node is chosen, it is marked dependent,
* and that the chosen one is the one which was expected to be marked dependent.
* @param atomicRequestGroup1 GroupSymbol to select from in atomic request 1
* @param atomicRequestCrit1 optional, may be null
* @param atomicRequestGroup1a optional, may be null
* @param atomicRequestCrit1a optional, may be null
* @param atomicJoinCriteria1 optional, may be null
* @param atomicRequestGroup2 GroupSymbol to select from in atomic request 2
* @param atomicRequestCrit2 optional, may be null
* @param atomicRequestGroup2a optional, may be null
* @param atomicRequestCrit2a optional, may be null
* @param atomicJoinCriteria2 optional, may be null
* @param joinCriteria Collection of Criteria to add to outer join node
* @param expectedMadeDependent one of the three outcome possibility class constants
* @throws TeiidComponentException
* @throws QueryMetadataException
* @throws QueryPlannerException
*/
private void helpTestChooseSiblingAndMarkDependent(GroupSymbol atomicRequestGroup1, // optional
Criteria atomicRequestCrit1, // optional
GroupSymbol atomicRequestGroup1a, // optional
Criteria atomicRequestCrit1a, // optional
Collection atomicJoinCriteria1, GroupSymbol atomicRequestGroup2, // optional
Criteria atomicRequestCrit2, // optional
GroupSymbol atomicRequestGroup2a, // optional
Criteria atomicRequestCrit2a, // optional
Collection atomicJoinCriteria2, Collection joinCriteria, int expectedMadeDependent, Number expectedCost1, Number expectedCost2) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
// EXAMPLE:
// Project(groups=[])
// Join(groups=[], props={21=joinCriteria, 23=true, 22=INNER JOIN})
// Access(groups=[atomicRequestGroup1], props={...})
// Source(groups=[atomicRequestGroup1])
// Access(groups=[atomicRequestGroup2, atomicRequestGroup2a], props={...})
// Join(groups=[atomicRequestGroup2, atomicRequestGroup2a], props={21=[atomicJoinCriteria2], 23=true, 22=INNER JOIN})
// Select(groups=[atomicRequestGroup2], props={40=atomicRequestCrit2})
// Source(groups=[atomicRequestGroup2])
// Source(groups=[atomicRequestGroup2a])
PlanNode accessNode1 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
accessNode1.addGroup(atomicRequestGroup1);
if (atomicRequestGroup1a != null) {
accessNode1.addGroup(atomicRequestGroup1a);
}
PlanNode accessNode2 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
accessNode2.addGroup(atomicRequestGroup2);
if (atomicRequestGroup2a != null) {
accessNode2.addGroup(atomicRequestGroup2a);
}
PlanNode joinNode = NodeFactory.getNewNode(NodeConstants.Types.JOIN);
joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_INNER);
joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, joinCriteria);
joinNode.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.NESTED_LOOP);
joinNode.addLastChild(accessNode1);
joinNode.addLastChild(accessNode2);
PlanNode bogusParentNode = NodeFactory.getNewNode(NodeConstants.Types.PROJECT);
bogusParentNode.addLastChild(joinNode);
// FIRST (LEFT) BRANCH OF TREE
PlanNode sourceNode1 = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
sourceNode1.addGroup(atomicRequestGroup1);
if (atomicRequestCrit1 != null) {
PlanNode selectNode1 = NodeFactory.getNewNode(NodeConstants.Types.SELECT);
selectNode1.setProperty(NodeConstants.Info.SELECT_CRITERIA, atomicRequestCrit1);
selectNode1.addGroup(atomicRequestGroup1);
selectNode1.addFirstChild(sourceNode1);
if (atomicRequestGroup1a != null) {
PlanNode atomicJoinNode1 = NodeFactory.getNewNode(NodeConstants.Types.JOIN);
if (atomicJoinCriteria1.isEmpty()) {
atomicJoinNode1.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_CROSS);
} else {
atomicJoinNode1.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_INNER);
atomicJoinNode1.setProperty(NodeConstants.Info.JOIN_CRITERIA, atomicJoinCriteria1);
}
atomicJoinNode1.addGroup(atomicRequestGroup1);
atomicJoinNode1.addGroup(atomicRequestGroup1a);
atomicJoinNode1.addLastChild(selectNode1);
PlanNode sourceNode1a = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
sourceNode1a.addGroup(atomicRequestGroup1a);
if (atomicRequestCrit1a != null) {
PlanNode selectNode1a = NodeFactory.getNewNode(NodeConstants.Types.SELECT);
selectNode1a.setProperty(NodeConstants.Info.SELECT_CRITERIA, atomicRequestCrit1a);
selectNode1a.addGroup(atomicRequestGroup1a);
selectNode1a.addFirstChild(sourceNode1a);
atomicJoinNode1.addLastChild(selectNode1a);
} else {
atomicJoinNode1.addLastChild(sourceNode1a);
}
accessNode1.addLastChild(atomicJoinNode1);
} else {
accessNode1.addFirstChild(selectNode1);
}
} else {
accessNode1.addFirstChild(sourceNode1);
}
// SECOND (RIGHT) BRANCH OF TREE
PlanNode sourceNode2 = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
sourceNode2.addGroup(atomicRequestGroup2);
if (atomicRequestCrit2 != null) {
PlanNode selectNode2 = NodeFactory.getNewNode(NodeConstants.Types.SELECT);
selectNode2.setProperty(NodeConstants.Info.SELECT_CRITERIA, atomicRequestCrit2);
selectNode2.addGroup(atomicRequestGroup2);
selectNode2.addFirstChild(sourceNode2);
if (atomicRequestGroup2a != null) {
PlanNode atomicJoinNode2 = NodeFactory.getNewNode(NodeConstants.Types.JOIN);
if (atomicJoinCriteria2.isEmpty()) {
atomicJoinNode2.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_CROSS);
} else {
atomicJoinNode2.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_INNER);
atomicJoinNode2.setProperty(NodeConstants.Info.JOIN_CRITERIA, atomicJoinCriteria2);
}
atomicJoinNode2.addGroup(atomicRequestGroup2);
atomicJoinNode2.addGroup(atomicRequestGroup2a);
atomicJoinNode2.addLastChild(selectNode2);
PlanNode sourceNode2a = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
sourceNode2a.addGroup(atomicRequestGroup2a);
if (atomicRequestCrit2a != null) {
PlanNode selectNode2a = NodeFactory.getNewNode(NodeConstants.Types.SELECT);
selectNode2a.setProperty(NodeConstants.Info.SELECT_CRITERIA, atomicRequestCrit2a);
selectNode2a.addGroup(atomicRequestGroup2a);
selectNode2a.addFirstChild(sourceNode2a);
atomicJoinNode2.addLastChild(selectNode2a);
} else {
atomicJoinNode2.addLastChild(sourceNode2a);
}
accessNode2.addLastChild(atomicJoinNode2);
} else {
accessNode2.addFirstChild(selectNode2);
}
} else {
accessNode2.addFirstChild(sourceNode2);
}
// Add access pattern(s)
RulePlaceAccess.addAccessPatternsProperty(accessNode1, metadata);
RulePlaceAccess.addAccessPatternsProperty(accessNode2, metadata);
if (DEBUG) {
// $NON-NLS-1$
System.out.println("Before.");
System.out.println(bogusParentNode);
}
RuleChooseDependent rule = new RuleChooseDependent();
RuleChooseJoinStrategy.chooseJoinStrategy(joinNode, metadata);
FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
// $NON-NLS-1$
capFinder.addCapabilities("pm1", TestOptimizer.getTypicalCapabilities());
// $NON-NLS-1$
capFinder.addCapabilities("pm2", TestOptimizer.getTypicalCapabilities());
// $NON-NLS-1$
capFinder.addCapabilities("pm3", TestOptimizer.getTypicalCapabilities());
// $NON-NLS-1$
capFinder.addCapabilities("pm4", TestOptimizer.getTypicalCapabilities());
rule.execute(bogusParentNode, metadata, capFinder, new RuleStack(), null, new CommandContext());
if (DEBUG) {
// $NON-NLS-1$
System.out.println("Done.");
System.out.println(bogusParentNode);
}
Object prop1 = joinNode.getProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE);
if (expectedMadeDependent == LEFT_SIDE) {
// $NON-NLS-1$
assertNotNull("Expected one side to be made dependent", prop1);
assertEquals(accessNode1, FrameUtil.findJoinSourceNode(joinNode.getLastChild()));
} else if (expectedMadeDependent == RIGHT_SIDE) {
// $NON-NLS-1$
assertNotNull("Expected one side to be made dependent", prop1);
assertEquals(accessNode2, FrameUtil.findJoinSourceNode(joinNode.getLastChild()));
} else if (expectedMadeDependent == NEITHER_SIDE) {
// $NON-NLS-1$
assertNull("Neither side should be dependent", prop1);
} else {
// $NON-NLS-1$
fail("Invalid test constant " + expectedMadeDependent);
}
Float cost1 = (Float) accessNode1.getProperty(NodeConstants.Info.EST_CARDINALITY);
Float cost2 = (Float) accessNode2.getProperty(NodeConstants.Info.EST_CARDINALITY);
assertNotNull(cost2);
assertNotNull(cost1);
if (expectedCost1 != null) {
assertEquals(expectedCost1.longValue(), cost1.longValue());
assertEquals(expectedCost2.longValue(), cost2.longValue());
}
}
use of org.teiid.query.optimizer.relational.RuleStack in project teiid by teiid.
the class TestRulePushSelectCriteria method testPushAcrossFrameWithAccessNode.
@Test
public void testPushAcrossFrameWithAccessNode() throws Exception {
QueryMetadataInterface metadata = new TempMetadataAdapter(RealMetadataFactory.example1Cached(), new TempMetadataStore());
// $NON-NLS-1$
Command command = TestOptimizer.helpGetCommand("select * from (select * from pm1.g1 union select * from pm1.g2) x where e1 = 1", metadata, null);
// $NON-NLS-1$
Command subCommand = TestOptimizer.helpGetCommand("select * from pm1.g1 union select * from pm1.g2", metadata, null);
RelationalPlanner p = new RelationalPlanner();
CommandContext cc = new CommandContext();
p.initialize(command, null, metadata, null, null, cc);
PlanNode root = p.generatePlan(command);
PlanNode child = p.generatePlan(subCommand);
PlanNode sourceNode = NodeEditor.findNodePreOrder(root, NodeConstants.Types.SOURCE);
sourceNode.addFirstChild(child);
sourceNode.setProperty(NodeConstants.Info.SYMBOL_MAP, SymbolMap.createSymbolMap(sourceNode.getGroups().iterator().next(), (List<Expression>) child.getFirstChild().getProperty(Info.PROJECT_COLS), metadata));
// add a dummy access node
PlanNode accessNode = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
accessNode.addGroups(child.getFirstChild().getGroups());
child.getFirstChild().addAsParent(accessNode);
new RulePushSelectCriteria().execute(root, metadata, new DefaultCapabilitiesFinder(), new RuleStack(), AnalysisRecord.createNonRecordingRecord(), cc);
// the select node should still be above the access node
accessNode = NodeEditor.findNodePreOrder(root, NodeConstants.Types.ACCESS);
assertEquals(NodeConstants.Types.SELECT, accessNode.getParent().getType());
assertNull(NodeEditor.findNodePreOrder(accessNode, NodeConstants.Types.SELECT));
}
use of org.teiid.query.optimizer.relational.RuleStack in project teiid by teiid.
the class RuleChooseDependent method fullyPush.
/**
* Check for fully pushable dependent joins
* currently we only look for the simplistic scenario where there are no intervening
* nodes above the dependent side
* @param independentExpressions
*/
private boolean fullyPush(PlanNode sourceNode, PlanNode joinNode, QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder, CommandContext context, PlanNode indNode, RuleStack rules, MakeDep makeDep, AnalysisRecord analysisRecord, List independentExpressions) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
if (sourceNode.getType() != NodeConstants.Types.ACCESS) {
// don't remove as we may raise an access node to make this possible
return false;
}
Object modelID = RuleRaiseAccess.getModelIDFromAccess(sourceNode, metadata);
boolean hasHint = false;
if (makeDep != null && makeDep.getJoin() != null) {
if (!makeDep.getJoin()) {
// $NON-NLS-1$ //$NON-NLS-2$
sourceNode.recordDebugAnnotation("cannot pushdown dependent join", modelID, "honoring hint", analysisRecord, null);
return false;
}
hasHint = true;
}
if (!CapabilitiesUtil.supports(Capability.FULL_DEPENDENT_JOIN, modelID, metadata, capabilitiesFinder)) {
if (hasHint) {
// $NON-NLS-1$ //$NON-NLS-2$
sourceNode.recordDebugAnnotation("cannot pushdown dependent join", modelID, "dependent join pushdown needs enabled at the source", analysisRecord, null);
}
return false;
}
List<? extends Expression> projected = (List<? extends Expression>) indNode.getProperty(Info.OUTPUT_COLS);
if (projected == null) {
PlanNode plan = sourceNode;
while (plan.getParent() != null) {
plan = plan.getParent();
}
new RuleAssignOutputElements(false).execute(plan, metadata, capabilitiesFinder, null, AnalysisRecord.createNonRecordingRecord(), context);
projected = (List<? extends Expression>) indNode.getProperty(Info.OUTPUT_COLS);
}
if (!hasHint) {
// require no lobs
for (Expression ex : projected) {
if (DataTypeManager.isLOB(ex.getClass())) {
return false;
}
}
// old optimizer tests had no buffermanager
if (context.getBufferManager() == null) {
return false;
}
if (makeDep != null && makeDep.getMax() != null) {
// if the user specifies a max, it's best to just use a regular dependent join
return false;
}
}
/*
* check to see how far the access node can be raised
*/
PlanNode tempAccess = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
// $NON-NLS-1$
GroupSymbol gs = RulePlaceAccess.recontextSymbol(new GroupSymbol("TEIID_TEMP"), context.getGroups());
gs.setDefinition(null);
tempAccess.addGroup(gs);
tempAccess.setProperty(Info.MODEL_ID, modelID);
indNode.addAsParent(tempAccess);
PlanNode originalSource = sourceNode;
sourceNode = originalSource.clone();
// more deeply clone
if (sourceNode.hasCollectionProperty(Info.ACCESS_PATTERNS)) {
sourceNode.setProperty(Info.ACCESS_PATTERNS, new ArrayList<AccessPattern>((List) sourceNode.getProperty(Info.ACCESS_PATTERNS)));
}
if (sourceNode.hasCollectionProperty(Info.CONFORMED_SOURCES)) {
sourceNode.setProperty(Info.CONFORMED_SOURCES, new LinkedHashSet<Object>((Set) sourceNode.getProperty(Info.CONFORMED_SOURCES)));
}
originalSource.addAsParent(sourceNode);
boolean raised = false;
boolean moreProcessing = false;
boolean first = true;
while (sourceNode.getParent() != null && RuleRaiseAccess.raiseAccessNode(sourceNode, sourceNode, metadata, capabilitiesFinder, true, null, context) != null) {
raised = true;
if (first) {
// raising over join required
first = false;
continue;
}
switch(sourceNode.getFirstChild().getType()) {
case NodeConstants.Types.PROJECT:
// TODO: check for correlated subqueries
if (sourceNode.getFirstChild().hasBooleanProperty(Info.HAS_WINDOW_FUNCTIONS)) {
moreProcessing = true;
}
break;
case NodeConstants.Types.SORT:
case NodeConstants.Types.DUP_REMOVE:
case NodeConstants.Types.GROUP:
case NodeConstants.Types.SELECT:
case NodeConstants.Types.TUPLE_LIMIT:
case NodeConstants.Types.JOIN:
moreProcessing = true;
break;
}
}
if (!raised) {
tempAccess.getParent().replaceChild(tempAccess, tempAccess.getFirstChild());
sourceNode.getParent().replaceChild(sourceNode, sourceNode.getFirstChild());
return false;
}
if (!moreProcessing && !hasHint) {
// restore the plan
if (sourceNode.getParent() != null) {
sourceNode.getParent().replaceChild(sourceNode, sourceNode.getFirstChild());
} else {
sourceNode.removeAllChildren();
}
return false;
}
originalSource.getParent().replaceChild(originalSource, originalSource.getFirstChild());
// all the references to any groups from this join have to changed over to the new group
// and we need to insert a source/project node to turn this into a proper plan
PlanNode project = NodeFactory.getNewNode(NodeConstants.Types.PROJECT);
PlanNode source = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
source.addGroup(gs);
project.setProperty(Info.OUTPUT_COLS, projected);
project.setProperty(Info.PROJECT_COLS, projected);
Set<GroupSymbol> newGroups = Collections.singleton(gs);
ArrayList<ElementSymbol> virtualSymbols = new ArrayList<ElementSymbol>(projected.size());
for (int i = 0; i < projected.size(); i++) {
// $NON-NLS-1$
ElementSymbol es = new ElementSymbol("col" + (i + 1));
Expression ex = projected.get(i);
es.setType(ex.getType());
virtualSymbols.add(es);
// TODO: set a metadata id from either side
if (ex instanceof ElementSymbol) {
es.setMetadataID(((ElementSymbol) ex).getMetadataID());
}
}
List<ElementSymbol> newCols = RulePushAggregates.defineNewGroup(gs, virtualSymbols, metadata);
SymbolMap symbolMap = SymbolMap.createSymbolMap(newCols, projected);
Map<Expression, ElementSymbol> inverse = symbolMap.inserseMapping();
// TODO: the util logic should handle multiple groups
for (GroupSymbol group : indNode.getGroups()) {
FrameUtil.convertFrame(joinNode, group, newGroups, inverse, metadata);
}
// add the source a new group for the join
indNode.addAsParent(source);
// convert the lower plan into a subplan
// it needs to be rooted by a project - a view isn't really needed
indNode.removeFromParent();
project.addFirstChild(indNode);
// run the remaining rules against the subplan
RuleStack ruleCopy = rules.clone();
RuleChooseDependent ruleChooseDependent = new RuleChooseDependent();
ruleChooseDependent.traditionalOnly = true;
ruleCopy.push(ruleChooseDependent);
if (indNode.getType() == NodeConstants.Types.ACCESS) {
PlanNode root = RuleRaiseAccess.raiseAccessNode(project, indNode, metadata, capabilitiesFinder, true, null, context);
if (root != project) {
project = root;
}
}
// fully plan the sub-plan with the remaining rules
project = rules.getPlanner().executeRules(ruleCopy, project);
source.setProperty(Info.SYMBOL_MAP, symbolMap);
source.setProperty(Info.SUB_PLAN, project);
return true;
}
Aggregations