use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RulePushSelectCriteria method pushAcrossSetOp.
boolean pushAcrossSetOp(PlanNode critNode, PlanNode setOp, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
// Find source node above union and grab the symbol map
PlanNode sourceNode = NodeEditor.findParent(setOp, NodeConstants.Types.SOURCE);
GroupSymbol virtualGroup = sourceNode.getGroups().iterator().next();
if (createdNodes == null) {
satisfyConditions(critNode, sourceNode, metadata);
}
SymbolMap symbolMap = (SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
SymbolMap childMap = symbolMap;
// Move criteria to first child of union - names are the same, so no symbol mapping
LinkedList<PlanNode> unionChildren = new LinkedList<PlanNode>();
collectUnionChildren(setOp, unionChildren);
int movedCount = 0;
for (PlanNode planNode : unionChildren) {
// Find first project node
PlanNode projectNode = NodeEditor.findNodePreOrder(planNode, NodeConstants.Types.PROJECT);
if (childMap == null) {
childMap = SymbolMap.createSymbolMap(symbolMap.getKeys(), (List) projectNode.getProperty(NodeConstants.Info.PROJECT_COLS));
}
// we cannot simply move the node in the case where placing above or below the access would be invalid
boolean handleSetOp = false;
PlanNode accessNode = NodeEditor.findNodePreOrder(planNode, NodeConstants.Types.ACCESS, NodeConstants.Types.PROJECT);
if (accessNode != null && NodeEditor.findParent(projectNode, NodeConstants.Types.SET_OP, NodeConstants.Types.ACCESS) != null) {
handleSetOp = true;
}
// Move the node
if (placeConvertedSelectNode(critNode, virtualGroup, projectNode, childMap, metadata)) {
if (handleSetOp) {
PlanNode newSelect = projectNode.getFirstChild();
projectNode.replaceChild(newSelect, newSelect.getFirstChild());
Object modelID = RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata);
Criteria crit = (Criteria) newSelect.getProperty(NodeConstants.Info.SELECT_CRITERIA);
if (newSelect.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET) && context != null && CapabilitiesUtil.supportsInlineView(modelID, metadata, capFinder) && CriteriaCapabilityValidatorVisitor.canPushLanguageObject(crit, modelID, metadata, capFinder, null)) {
accessNode.getFirstChild().addAsParent(newSelect);
List<Expression> old = (List<Expression>) projectNode.getProperty(NodeConstants.Info.PROJECT_COLS);
// create a project node based upon the created group and add it as the parent of the select
PlanNode project = RelationalPlanner.createProjectNode(LanguageObject.Util.deepClone(old, Expression.class));
newSelect.addAsParent(project);
// $NON-NLS-1$
PlanNode newSourceNode = RuleDecomposeJoin.rebuild(new GroupSymbol("intermediate"), null, newSelect.getFirstChild(), metadata, context, projectNode);
newSourceNode.setProperty(NodeConstants.Info.INLINE_VIEW, true);
accessNode.addGroups(newSourceNode.getGroups());
markDependent(newSelect, accessNode, metadata, capFinder);
} else {
// or an inline view could be used similar to the above
if (createdNodes != null) {
createdNodes.remove(newSelect);
}
childMap = null;
continue;
}
}
movedCount++;
}
// create a new symbol map for the other children
childMap = null;
}
// TODO - the logic here could be made more intelligent about EXCEPT and INTERSECT.
if (movedCount == unionChildren.size()) {
critNode.setProperty(NodeConstants.Info.IS_PHANTOM, Boolean.TRUE);
return true;
}
// otherwise mark it as pushed so we don't consider it again
critNode.setProperty(NodeConstants.Info.IS_PUSHED, Boolean.TRUE);
// if any moved, then we need to continue
return movedCount != 0;
}
use of org.teiid.query.sql.lang.Criteria 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;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RuleRemoveOptionalJoins method removeJoin.
/**
* remove the optional node if possible
* @throws QueryPlannerException
* @throws TeiidComponentException
* @throws QueryMetadataException
*/
private List<PlanNode> removeJoin(Set<GroupSymbol> required, Set<GroupSymbol> requiredForOptional, PlanNode joinNode, PlanNode optionalNode, AnalysisRecord record, QueryMetadataInterface metadata) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
boolean correctFrame = false;
boolean isOptional = optionalNode.hasBooleanProperty(NodeConstants.Info.IS_OPTIONAL);
if (isOptional) {
required = requiredForOptional;
correctFrame = true;
}
if (!Collections.disjoint(optionalNode.getGroups(), required)) {
return null;
}
if (isOptional) {
// prevent bridge table removal
HashSet<GroupSymbol> joinGroups = new HashSet<GroupSymbol>();
PlanNode parentNode = joinNode;
while (parentNode.getType() != NodeConstants.Types.PROJECT) {
PlanNode current = parentNode;
parentNode = parentNode.getParent();
if (current.getType() != NodeConstants.Types.SELECT && current.getType() != NodeConstants.Types.JOIN) {
continue;
}
Set<GroupSymbol> currentGroups = current.getGroups();
if (current.getType() == NodeConstants.Types.JOIN) {
currentGroups = GroupsUsedByElementsVisitor.getGroups((List<Criteria>) current.getProperty(NodeConstants.Info.JOIN_CRITERIA));
}
if (!Collections.disjoint(currentGroups, optionalNode.getGroups()) && !optionalNode.getGroups().containsAll(currentGroups)) {
// we're performing a join
boolean wasEmpty = joinGroups.isEmpty();
boolean modified = joinGroups.addAll(current.getGroups());
if (!wasEmpty && modified) {
return null;
}
}
}
}
JoinType jt = (JoinType) joinNode.getProperty(NodeConstants.Info.JOIN_TYPE);
boolean usesKey = false;
boolean isRight = optionalNode == joinNode.getLastChild();
if (!isOptional && (jt == JoinType.JOIN_INNER || (jt == JoinType.JOIN_LEFT_OUTER && isRight))) {
usesKey = isOptionalUsingKey(joinNode, optionalNode, metadata, isRight);
}
if (!isOptional && !usesKey && (jt != JoinType.JOIN_LEFT_OUTER || !isRight || useNonDistinctRows(joinNode.getParent()))) {
return null;
}
// remove the parent node and move the sibling node upward
PlanNode parentNode = joinNode.getParent();
joinNode.removeChild(optionalNode);
joinNode.getFirstChild().setProperty(NodeConstants.Info.OUTPUT_COLS, joinNode.getProperty(NodeConstants.Info.OUTPUT_COLS));
NodeEditor.removeChildNode(parentNode, joinNode);
// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
joinNode.recordDebugAnnotation((isOptional ? "node was marked as optional " : "node will not affect the results"), null, "Removing join node", record, null);
while (parentNode.getType() != NodeConstants.Types.PROJECT) {
PlanNode current = parentNode;
parentNode = parentNode.getParent();
if (correctFrame) {
if (current.getType() == NodeConstants.Types.SELECT) {
if (!Collections.disjoint(current.getGroups(), optionalNode.getGroups())) {
current.getFirstChild().setProperty(NodeConstants.Info.OUTPUT_COLS, current.getProperty(NodeConstants.Info.OUTPUT_COLS));
NodeEditor.removeChildNode(parentNode, current);
}
} else if (current.getType() == NodeConstants.Types.JOIN) {
if (!Collections.disjoint(current.getGroups(), optionalNode.getGroups())) {
List<Criteria> crits = (List<Criteria>) current.getProperty(NodeConstants.Info.JOIN_CRITERIA);
if (crits != null && !crits.isEmpty()) {
for (Iterator<Criteria> iterator = crits.iterator(); iterator.hasNext(); ) {
Criteria criteria = iterator.next();
if (!Collections.disjoint(GroupsUsedByElementsVisitor.getGroups(criteria), optionalNode.getGroups())) {
iterator.remove();
}
}
if (crits.isEmpty()) {
JoinType joinType = (JoinType) current.getProperty(NodeConstants.Info.JOIN_TYPE);
if (joinType == JoinType.JOIN_INNER) {
current.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_CROSS);
}
}
}
}
}
} else if (current.getType() != NodeConstants.Types.JOIN) {
break;
}
if (current.getType() == NodeConstants.Types.JOIN) {
current.getGroups().removeAll(optionalNode.getGroups());
}
}
return NodeEditor.findAllNodes(optionalNode, NodeConstants.Types.JOIN);
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RuleChooseJoinStrategy method separateCriteria.
public static void separateCriteria(Collection<GroupSymbol> leftGroups, Collection<GroupSymbol> rightGroups, List<Expression> leftExpressions, List<Expression> rightExpressions, List<Criteria> crits, Collection<Criteria> nonEquiJoinCriteria) {
for (Criteria theCrit : crits) {
Set<GroupSymbol> critGroups = GroupsUsedByElementsVisitor.getGroups(theCrit);
if (leftGroups.containsAll(critGroups) || rightGroups.containsAll(critGroups)) {
nonEquiJoinCriteria.add(theCrit);
continue;
}
if (!(theCrit instanceof CompareCriteria)) {
nonEquiJoinCriteria.add(theCrit);
continue;
}
CompareCriteria crit = (CompareCriteria) theCrit;
if (crit.getOperator() != CompareCriteria.EQ) {
nonEquiJoinCriteria.add(theCrit);
continue;
}
Expression leftExpr = crit.getLeftExpression();
Expression rightExpr = crit.getRightExpression();
Set<GroupSymbol> leftExprGroups = GroupsUsedByElementsVisitor.getGroups(leftExpr);
Set<GroupSymbol> rightExprGroups = GroupsUsedByElementsVisitor.getGroups(rightExpr);
if (leftGroups.isEmpty() || rightGroups.isEmpty()) {
nonEquiJoinCriteria.add(theCrit);
} else if (leftGroups.containsAll(leftExprGroups) && rightGroups.containsAll(rightExprGroups)) {
leftExpressions.add(leftExpr);
rightExpressions.add(rightExpr);
} else if (rightGroups.containsAll(leftExprGroups) && leftGroups.containsAll(rightExprGroups)) {
leftExpressions.add(rightExpr);
rightExpressions.add(leftExpr);
} else {
nonEquiJoinCriteria.add(theCrit);
}
}
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RuleCopyCriteria method copyCriteria.
/**
* Given a criteria and a map of elements to values try to create a new single group criteria
*
* If the new criteria does not have exactly one group or already exists in the combined criteria,
* it will not be added.
*
* @param crit
* @param tgtMap
* @param joinCriteria
* @param combinedCriteria
* @return number of remaining groups if the copy was successful
*/
private Integer copyCriteria(Criteria crit, Map<Expression, Expression> tgtMap, List<Criteria> joinCriteria, Set<Criteria> combinedCriteria, boolean checkForGroupReduction, QueryMetadataInterface metadata, boolean underAccess) {
int startGroups = GroupsUsedByElementsVisitor.getGroups(crit).size();
Criteria tgtCrit = (Criteria) crit.clone();
try {
tgtCrit = FrameUtil.convertCriteria(tgtCrit, tgtMap, metadata, true);
} catch (QueryPlannerException err) {
// $NON-NLS-1$
LogManager.logDetail(LogConstants.CTX_QUERY_PLANNER, err, "Could not remap target criteria in RuleCopyCriteria");
return null;
}
if (tgtCrit instanceof IsNullCriteria && ((IsNullCriteria) tgtCrit).isNegated()) {
return null;
}
int endGroups = GroupsUsedByElementsVisitor.getGroups(tgtCrit).size();
if (checkForGroupReduction) {
if (endGroups >= startGroups) {
return null;
}
} else if (endGroups > startGroups) {
return null;
}
boolean isNew = combinedCriteria.add(tgtCrit);
if (underAccess) {
if (!isNew || checkForGroupReduction || endGroups > 1) {
return null;
}
if (!COPY_ALL) {
boolean use = false;
Collection<ElementSymbol> cols = ElementCollectorVisitor.getElements(tgtCrit, true);
// use only if it could be used to further rewrite predicates
for (Criteria existing : combinedCriteria) {
if (existing.equals(tgtCrit)) {
continue;
}
Collection<ElementSymbol> elements = ElementCollectorVisitor.getElements(existing, true);
if (GroupsUsedByElementsVisitor.getGroups(elements).size() > 1) {
continue;
}
if (elements.containsAll(cols)) {
use = true;
break;
}
}
if (!use) {
return null;
}
}
}
// if this is unique or it a duplicate but reduced a current join conjunct, return true
if (isNew) {
joinCriteria.add(tgtCrit);
if (tgtCrit instanceof CompareCriteria) {
CompareCriteria cc = (CompareCriteria) tgtCrit;
if (!EvaluatableVisitor.willBecomeConstant(cc.getRightExpression()) && !EvaluatableVisitor.willBecomeConstant(cc.getRightExpression())) {
((CompareCriteria) tgtCrit).setOptional(true);
}
}
return endGroups;
} else if (checkForGroupReduction && endGroups < 2) {
return endGroups;
}
return null;
}
Aggregations