use of org.teiid.query.resolver.util.AccessPattern in project teiid by teiid.
the class TestAccessPattern method testOrdering.
public void testOrdering() {
AccessPattern ap1 = new AccessPattern(createElements(1));
AccessPattern ap2 = new AccessPattern(createElements(2));
List accessPatterns = new ArrayList();
accessPatterns.add(ap2);
accessPatterns.add(ap1);
Collections.sort(accessPatterns);
assertEquals(ap1, accessPatterns.get(0));
}
use of org.teiid.query.resolver.util.AccessPattern in project teiid by teiid.
the class TestAccessPattern method testClone.
public void testClone() {
AccessPattern ap2 = new AccessPattern(createElements(2));
AccessPattern clone = (AccessPattern) ap2.clone();
assertNotSame(ap2, clone);
assertEquals(ap2.getUnsatisfied(), clone.getUnsatisfied());
}
use of org.teiid.query.resolver.util.AccessPattern 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;
}
use of org.teiid.query.resolver.util.AccessPattern in project teiid by teiid.
the class RuleMergeVirtual method prepareFrame.
private static void prepareFrame(PlanNode frame) {
// find the new root of the frame so that access patterns can be propagated
PlanNode newRoot = FrameUtil.findJoinSourceNode(frame.getFirstChild());
if (newRoot != null) {
Collection<AccessPattern> ap = (Collection) frame.getProperty(NodeConstants.Info.ACCESS_PATTERNS);
if (ap != null) {
Collection<AccessPattern> newAp = (Collection) newRoot.getProperty(NodeConstants.Info.ACCESS_PATTERNS);
if (newAp == null) {
newRoot.setProperty(NodeConstants.Info.ACCESS_PATTERNS, ap);
} else {
newAp.addAll(ap);
}
}
RulePlaceAccess.copyProperties(frame, newRoot);
}
}
use of org.teiid.query.resolver.util.AccessPattern 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