use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RuleRaiseAccess method raiseAccessOverJoin.
static PlanNode raiseAccessOverJoin(PlanNode joinNode, PlanNode accessNode, Object modelID, CapabilitiesFinder capFinder, QueryMetadataInterface metadata, boolean insert) throws QueryMetadataException, TeiidComponentException {
PlanNode leftAccess = joinNode.getFirstChild();
PlanNode rightAccess = joinNode.getLastChild();
boolean switchChildren = false;
if (leftAccess.getGroups().size() != 1 && joinNode.getProperty(Info.JOIN_TYPE) == JoinType.JOIN_INNER && CapabilitiesUtil.getSupportedJoinCriteria(modelID, metadata, capFinder) == SupportedJoinCriteria.KEY) {
switchChildren = true;
}
PlanNode other = leftAccess == accessNode ? rightAccess : leftAccess;
// Remove old access nodes - this will automatically add children of access nodes to join node
NodeEditor.removeChildNode(joinNode, leftAccess);
if (rightAccess.getType() == NodeConstants.Types.SOURCE) {
rightAccess.setProperty(NodeConstants.Info.INLINE_VIEW, Boolean.TRUE);
// handle lateral join
if (FrameUtil.getNonQueryCommand(rightAccess.getFirstChild()) != null) {
// procedure case
PlanNode access = NodeEditor.findNodePreOrder(rightAccess, NodeConstants.Types.ACCESS);
NodeEditor.removeChildNode(access.getParent(), access);
} else {
Assertion.assertTrue(rightAccess.getFirstChild().getType() == NodeConstants.Types.ACCESS);
NodeEditor.removeChildNode(rightAccess, rightAccess.getFirstChild());
}
} else {
NodeEditor.removeChildNode(joinNode, rightAccess);
}
combineConformedSources(accessNode, other);
// Set for later possible use, even though this isn't an access node
joinNode.setProperty(NodeConstants.Info.MODEL_ID, modelID);
// Insert new access node above join node
accessNode.addGroups(other.getGroups());
// Combine hints if necessary
RulePlaceAccess.copyProperties(other, accessNode);
RulePlaceAccess.copyProperties(joinNode, accessNode);
combineSourceHints(accessNode, other);
if (other.hasBooleanProperty(Info.IS_MULTI_SOURCE)) {
accessNode.setProperty(Info.IS_MULTI_SOURCE, Boolean.TRUE);
}
String sourceName = (String) other.getProperty(Info.SOURCE_NAME);
if (sourceName != null) {
accessNode.setProperty(Info.SOURCE_NAME, sourceName);
}
if (insert) {
joinNode.addAsParent(accessNode);
} else {
accessNode.addFirstChild(joinNode);
}
if (switchChildren) {
JoinUtil.swapJoinChildren(joinNode);
}
return accessNode;
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RuleRaiseAccess method canRaiseOverSelect.
/**
* @param accessNode
* @param metadata
* @param capFinder
* @param parentNode
* @return
* @throws QueryMetadataException
* @throws TeiidComponentException
* @throws QueryPlannerException
*/
static boolean canRaiseOverSelect(PlanNode accessNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, PlanNode parentNode, AnalysisRecord record) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
if (parentNode.hasBooleanProperty(NodeConstants.Info.IS_PHANTOM)) {
return true;
}
// Find the model for this node by getting ACCESS node's model
Object modelID = getModelIDFromAccess(accessNode, metadata);
if (modelID == null) {
// Couldn't determine model ID, so give up
return false;
}
if (parentNode.hasBooleanProperty(NodeConstants.Info.IS_HAVING) && !CapabilitiesUtil.supports(Capability.QUERY_HAVING, modelID, metadata, capFinder) && !CapabilitiesUtil.supports(Capability.QUERY_FROM_INLINE_VIEWS, modelID, metadata, capFinder)) {
// $NON-NLS-1$ //$NON-NLS-2$
parentNode.recordDebugAnnotation("having is not supported by source", modelID, "cannot push having", record, metadata);
return false;
}
// don't push criteria into an invalid location above an ordered limit - shouldn't happen
PlanNode limitNode = NodeEditor.findNodePreOrder(accessNode, NodeConstants.Types.TUPLE_LIMIT, NodeConstants.Types.SOURCE);
if (limitNode != null && FrameUtil.isOrderedOrStrictLimit(limitNode)) {
return false;
}
Criteria crit = (Criteria) parentNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
if (!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(crit, modelID, metadata, capFinder, record)) {
return false;
}
if (accessNode.getFirstChild() != null && accessNode.getFirstChild().getType() == NodeConstants.Types.SET_OP) {
// inconsistent select position - RulePushSelectCriteria is too greedy
return false;
}
return true;
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RuleRaiseAccess method execute.
public PlanNode execute(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
boolean afterJoinPlanning = !rules.contains(RuleConstants.PLAN_JOINS);
for (PlanNode accessNode : NodeEditor.findAllNodes(plan, NodeConstants.Types.ACCESS)) {
while (true) {
PlanNode newRoot = raiseAccessNode(plan, accessNode, metadata, capFinder, afterJoinPlanning, analysisRecord, context);
if (newRoot == null) {
break;
}
plan = newRoot;
}
}
return plan;
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RuleRaiseNull method raiseNullThroughJoin.
/**
* Given a joinNode that should be an outer join and a null node as one of its children, replace elements in
* the current frame from the null node groups with null values
*
* @param metadata
* @param joinNode
* @param nullNode
* @throws QueryPlannerException
* @throws QueryMetadataException
* @throws TeiidComponentException
*/
static void raiseNullThroughJoin(QueryMetadataInterface metadata, PlanNode joinNode, PlanNode nullNode) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
Assertion.assertTrue(joinNode.getType() == NodeConstants.Types.JOIN);
Assertion.assertTrue(nullNode.getType() == NodeConstants.Types.NULL);
Assertion.assertTrue(nullNode.getParent() == joinNode);
PlanNode frameStart = joinNode.getParent();
NodeEditor.removeChildNode(joinNode, nullNode);
NodeEditor.removeChildNode(joinNode.getParent(), joinNode);
for (GroupSymbol group : nullNode.getGroups()) {
Map<ElementSymbol, Expression> nullSymbolMap = FrameUtil.buildSymbolMap(group, null, metadata);
FrameUtil.convertFrame(frameStart, group, null, nullSymbolMap, metadata);
}
}
use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.
the class RuleRemoveOptionalJoins method isOptionalUsingKey.
private boolean isOptionalUsingKey(PlanNode joinNode, PlanNode optionalNode, QueryMetadataInterface metadata, boolean isRight) throws TeiidComponentException, QueryMetadataException {
// for now we just look for a single group
if (optionalNode.getGroups().size() != 1) {
return false;
}
PlanNode left = isRight ? joinNode.getFirstChild() : joinNode.getLastChild();
LinkedList<Expression> leftExpressions = new LinkedList<Expression>();
LinkedList<Expression> rightExpressions = new LinkedList<Expression>();
LinkedList<Criteria> nonEquiJoinCriteria = new LinkedList<Criteria>();
RuleChooseJoinStrategy.separateCriteria(left.getGroups(), optionalNode.getGroups(), leftExpressions, rightExpressions, (List<Criteria>) joinNode.getProperty(NodeConstants.Info.JOIN_CRITERIA), nonEquiJoinCriteria);
if (!nonEquiJoinCriteria.isEmpty()) {
for (Criteria crit : nonEquiJoinCriteria) {
if (!Collections.disjoint(GroupsUsedByElementsVisitor.getGroups(crit), optionalNode.getGroups())) {
// additional predicates still need to be applied, or ignored via hint
return false;
}
}
}
ArrayList<Object> leftIds = new ArrayList<Object>(leftExpressions.size());
ArrayList<Object> rightIds = new ArrayList<Object>(rightExpressions.size());
for (Expression expr : leftExpressions) {
if (expr instanceof ElementSymbol) {
leftIds.add(((ElementSymbol) expr).getMetadataID());
}
}
for (Expression expr : rightExpressions) {
if (expr instanceof ElementSymbol) {
rightIds.add(((ElementSymbol) expr).getMetadataID());
} else {
// only allow a key join
return false;
}
}
outer: for (GroupSymbol group : left.getGroups()) {
Collection fks = metadata.getForeignKeysInGroup(group.getMetadataID());
for (Object fk : fks) {
List fkColumns = metadata.getElementIDsInKey(fk);
if (!leftIds.containsAll(fkColumns)) {
continue;
}
Object pk = metadata.getPrimaryKeyIDForForeignKeyID(fk);
List pkColumns = metadata.getElementIDsInKey(pk);
if ((rightIds.size() != pkColumns.size()) || !rightIds.containsAll(pkColumns)) {
continue;
}
if (!isRight) {
// match up to the replacement logic below
JoinUtil.swapJoinChildren(joinNode);
}
return true;
}
}
return false;
}
Aggregations