use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RuleCopyCriteria method tryToCopy.
/**
* Recursively tries to copy criteria across join nodes. toCopy will contain only the single group criteria
* that has not yet been copied. allCriteria will contain all criteria present at the join that can effect
* copying.
*
* @param node
* @return true if criteria has been created
*/
private boolean tryToCopy(PlanNode node, Set<Criteria>[] criteriaInfo, QueryMetadataInterface metadata, boolean underAccess) {
boolean changedTree = false;
if (node == null) {
return false;
}
// visit join nodes in order
if (node.getType() == NodeConstants.Types.JOIN) {
JoinType jt = (JoinType) node.getProperty(NodeConstants.Info.JOIN_TYPE);
if (jt == JoinType.JOIN_FULL_OUTER) {
return visitChildern(node, criteriaInfo, changedTree, metadata, underAccess);
}
Set<Criteria>[] leftChildCriteria = new Set[2];
Set<Criteria>[] rightChildCriteria = new Set[2];
changedTree |= tryToCopy(node.getFirstChild(), leftChildCriteria, metadata, underAccess);
changedTree |= tryToCopy(node.getLastChild(), rightChildCriteria, metadata, underAccess);
List<Criteria> joinCrits = (List<Criteria>) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
Set<Criteria> combinedCriteria = null;
if (joinCrits != null) {
combinedCriteria = new LinkedHashSet<Criteria>(joinCrits);
combinedCriteria.addAll(leftChildCriteria[1]);
combinedCriteria.addAll(rightChildCriteria[1]);
}
// combine the criteria
leftChildCriteria[0].addAll(rightChildCriteria[0]);
leftChildCriteria[1].addAll(rightChildCriteria[1]);
// set the applicable criteria
criteriaInfo[0] = leftChildCriteria[0];
// set the all criteria
criteriaInfo[1] = leftChildCriteria[1];
// there's no join criteria here, so just let the criteria go up
if (jt == JoinType.JOIN_CROSS) {
return changedTree;
}
Set<Criteria> toCopy = criteriaInfo[0];
Set<Criteria> allCriteria = criteriaInfo[1];
if (joinCrits != null && !joinCrits.isEmpty()) {
List<Criteria> newJoinCrits = new LinkedList<Criteria>();
// we don't want to continue discovery since that could be recursive
Map<Expression, Expression> srcToTgt = buildElementMap(joinCrits, node.hasBooleanProperty(NodeConstants.Info.IS_COPIED) ? null : newJoinCrits, combinedCriteria, metadata, underAccess);
changedTree |= !newJoinCrits.isEmpty();
if (!toCopy.isEmpty()) {
changedTree |= createCriteria(false, toCopy, combinedCriteria, srcToTgt, newJoinCrits, metadata, underAccess);
srcToTgt = buildElementMap(allCriteria, null, null, metadata, underAccess);
changedTree |= createCriteria(true, joinCrits, combinedCriteria, srcToTgt, newJoinCrits, metadata, underAccess);
}
joinCrits.addAll(newJoinCrits);
}
// before returning, filter out criteria that cannot go above the join node
if (jt == JoinType.JOIN_RIGHT_OUTER || jt == JoinType.JOIN_ANTI_SEMI || jt == JoinType.JOIN_SEMI || jt == JoinType.JOIN_UNION) {
// $NON-NLS-1$
throw new AssertionError("Unexpected join type");
} else if (jt == JoinType.JOIN_LEFT_OUTER) {
criteriaInfo[0].removeAll(rightChildCriteria[0]);
criteriaInfo[1].removeAll(rightChildCriteria[1]);
} else if (node.getSubqueryContainers().isEmpty()) {
if (!node.hasBooleanProperty(NodeConstants.Info.IS_COPIED)) {
toCopy.addAll(combinedCriteria);
}
allCriteria.addAll(joinCrits);
}
return changedTree;
}
changedTree = visitChildern(node, criteriaInfo, changedTree, metadata, underAccess);
// visit select nodes on the way back up
switch(node.getType()) {
case NodeConstants.Types.SELECT:
{
if (criteriaInfo[0] != null) {
visitSelectNode(node, criteriaInfo[0], criteriaInfo[1]);
}
break;
}
// clear the criteria when hitting the following
case NodeConstants.Types.NULL:
case NodeConstants.Types.SOURCE:
case NodeConstants.Types.GROUP:
case NodeConstants.Types.SET_OP:
case NodeConstants.Types.PROJECT:
{
if (criteriaInfo[0] == null) {
criteriaInfo[0] = new LinkedHashSet<Criteria>();
criteriaInfo[1] = new LinkedHashSet<Criteria>();
} else {
criteriaInfo[0].clear();
criteriaInfo[1].clear();
}
break;
}
}
return changedTree;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RuleCopyCriteria method buildElementMap.
/**
* Construct a mapping of element symbol to value map based upon equality CompareCriteria in crits
*
* @param crits
* @param newJoinCrits
* @param metadata
* @return
*/
Map<Expression, Expression> buildElementMap(Collection<Criteria> crits, List<Criteria> newJoinCrits, Set<Criteria> allCriteria, QueryMetadataInterface metadata, boolean underAccess) {
Map<Expression, Expression> srcToTgt = null;
for (Iterator<Criteria> iter = crits.iterator(); iter.hasNext(); ) {
Criteria theCrit = iter.next();
if (theCrit instanceof IsNullCriteria) {
IsNullCriteria isNull = (IsNullCriteria) theCrit;
if (!isNull.isNegated() && isNull.getExpression() instanceof ElementSymbol) {
if (srcToTgt == null) {
srcToTgt = new HashMap<Expression, Expression>();
}
srcToTgt.put(isNull.getExpression(), new Constant(null, isNull.getExpression().getType()));
}
continue;
}
if (!(theCrit instanceof CompareCriteria)) {
continue;
}
CompareCriteria crit = (CompareCriteria) theCrit;
if (crit.getOperator() == CompareCriteria.EQ) {
if (srcToTgt == null) {
srcToTgt = new HashMap<Expression, Expression>();
}
Expression oldValue = srcToTgt.put(crit.getLeftExpression(), crit.getRightExpression());
boolean removed = false;
if (checkWithinJoin(crit, newJoinCrits, allCriteria, oldValue, crit.getRightExpression(), metadata, underAccess)) {
iter.remove();
removed = true;
}
oldValue = srcToTgt.put(crit.getRightExpression(), crit.getLeftExpression());
if (checkWithinJoin(crit, newJoinCrits, allCriteria, oldValue, crit.getLeftExpression(), metadata, underAccess) && !removed) {
iter.remove();
}
}
}
if (srcToTgt == null) {
return Collections.emptyMap();
}
return srcToTgt;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RuleDecomposeJoin method buildUnion.
private PlanNode buildUnion(PlanNode unionNode, PlanNode otherSide, List<Criteria> criteria, List<int[]> matches, List<PlanNode> branches, List<PlanNode> otherBranches, JoinType joinType) {
SymbolMap symbolMap = (SymbolMap) unionNode.getParent().getProperty(Info.SYMBOL_MAP);
SymbolMap otherSymbolMap = (SymbolMap) otherSide.getProperty(Info.SYMBOL_MAP);
List<PlanNode> joins = new LinkedList<PlanNode>();
for (int i = 0; i < matches.size(); i++) {
int[] is = matches.get(i);
PlanNode branch = branches.get(is[0]);
PlanNode branchSource = createSource(unionNode.getParent().getGroups().iterator().next(), branch, symbolMap);
PlanNode otherBranch = otherBranches.get(is[1]);
PlanNode otherBranchSource = createSource(otherSide.getGroups().iterator().next(), otherBranch, otherSymbolMap);
PlanNode newJoinNode = NodeFactory.getNewNode(NodeConstants.Types.JOIN);
newJoinNode.addLastChild(branchSource);
newJoinNode.addLastChild(otherBranchSource);
newJoinNode.setProperty(Info.JOIN_STRATEGY, JoinStrategyType.NESTED_LOOP);
newJoinNode.setProperty(Info.JOIN_TYPE, joinType);
newJoinNode.setProperty(Info.JOIN_CRITERIA, LanguageObject.Util.deepClone(criteria, Criteria.class));
newJoinNode.addGroups(branchSource.getGroups());
newJoinNode.addGroups(otherBranchSource.getGroups());
PlanNode projectPlanNode = NodeFactory.getNewNode(NodeConstants.Types.PROJECT);
newJoinNode.addAsParent(projectPlanNode);
Select allSymbols = new Select(symbolMap.getKeys());
allSymbols.addSymbols(otherSymbolMap.getKeys());
if (i == 0) {
QueryRewriter.makeSelectUnique(allSymbols, false);
}
projectPlanNode.setProperty(NodeConstants.Info.PROJECT_COLS, allSymbols.getSymbols());
projectPlanNode.addGroups(newJoinNode.getGroups());
joins.add(projectPlanNode);
}
PlanNode newUnion = RulePlanUnions.buildUnionTree(unionNode, joins);
return newUnion;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RuleDecomposeJoin method decomposeJoin.
public PlanNode decomposeJoin(PlanNode joinNode, PlanNode root, QueryMetadataInterface metadata, CommandContext context) throws TeiidComponentException, QueryPlannerException {
if (joinNode.getParent() == null) {
// already processed
return root;
}
JoinType joinType = (JoinType) joinNode.getProperty(Info.JOIN_TYPE);
if (joinType == JoinType.JOIN_ANTI_SEMI || joinType == JoinType.JOIN_CROSS) {
return root;
}
PlanNode left = joinNode.getFirstChild();
while (left.getType() != NodeConstants.Types.SOURCE) {
if (left.getType() == NodeConstants.Types.SELECT && left.hasBooleanProperty(Info.IS_PHANTOM)) {
left = left.getFirstChild();
} else {
return root;
}
}
Map<ElementSymbol, List<Set<Constant>>> partitionInfo = (Map<ElementSymbol, List<Set<Constant>>>) left.getProperty(Info.PARTITION_INFO);
if (partitionInfo == null) {
return root;
}
PlanNode unionNode = left.getFirstChild();
if (unionNode.getType() != NodeConstants.Types.SET_OP) {
return root;
}
PlanNode right = joinNode.getLastChild();
while (right.getType() != NodeConstants.Types.SOURCE) {
if (right.getType() == NodeConstants.Types.SELECT && right.hasBooleanProperty(Info.IS_PHANTOM)) {
right = right.getFirstChild();
} else {
return root;
}
}
Map<ElementSymbol, List<Set<Constant>>> rightPartionInfo = (Map<ElementSymbol, List<Set<Constant>>>) right.getProperty(Info.PARTITION_INFO);
if (rightPartionInfo == null) {
return root;
}
List<Criteria> criteria = (List<Criteria>) joinNode.getProperty(Info.JOIN_CRITERIA);
List<Expression> expr = new ArrayList<Expression>();
List<Expression> exprOther = new ArrayList<Expression>();
RuleChooseJoinStrategy.separateCriteria(unionNode.getParent().getGroups(), right.getGroups(), expr, exprOther, criteria, new LinkedList<Criteria>());
// if implicit, we assume that partitions match
ElementSymbol es = getImplicitPartitionColumn(metadata, left);
ElementSymbol esOther = getImplicitPartitionColumn(metadata, right);
if (es != null && esOther != null && getEffectiveModelId(metadata, es.getGroupSymbol()) == getEffectiveModelId(metadata, esOther.getGroupSymbol())) {
expr.add(es);
exprOther.add(esOther);
}
if (expr.isEmpty()) {
// no equi-join
return root;
}
List<int[]> matches = findMatches(partitionInfo, rightPartionInfo, expr, exprOther);
if (matches == null) {
// no non-overlapping partitions
return root;
}
int branchSize = partitionInfo.values().iterator().next().size();
int otherBranchSize = rightPartionInfo.values().iterator().next().size();
if (matches.isEmpty()) {
if (joinType == JoinType.JOIN_INNER || joinType == JoinType.JOIN_SEMI) {
// no matches mean that we can just insert a null node (false criteria) and be done with it
PlanNode critNode = NodeFactory.getNewNode(NodeConstants.Types.SELECT);
critNode.setProperty(Info.SELECT_CRITERIA, QueryRewriter.FALSE_CRITERIA);
unionNode.addAsParent(critNode);
} else if (joinType == JoinType.JOIN_LEFT_OUTER) {
joinNode.getParent().replaceChild(joinNode, left);
} else if (joinType == JoinType.JOIN_FULL_OUTER) {
joinNode.setProperty(Info.JOIN_CRITERIA, QueryRewriter.FALSE_CRITERIA);
}
return root;
}
List<PlanNode> branches = new ArrayList<PlanNode>();
// TODO: find union children from RulePushAggregates
RulePushSelectCriteria.collectUnionChildren(unionNode, branches);
if (branches.size() != branchSize) {
// sanity check
return root;
}
List<PlanNode> otherBranches = new ArrayList<PlanNode>();
RulePushSelectCriteria.collectUnionChildren(right.getFirstChild(), otherBranches);
if (otherBranches.size() != otherBranchSize) {
// sanity check
return root;
}
PlanNode newUnion = buildUnion(unionNode, right, criteria, matches, branches, otherBranches, joinType);
GroupSymbol leftGroup = left.getGroups().iterator().next();
PlanNode view = rebuild(leftGroup, joinNode, newUnion, metadata, context, left, right);
// preserve the model of the virtual group as we'll look for this when checking for implicit behavior
((TempMetadataID) (view.getGroups().iterator().next().getMetadataID())).getTableData().setModel(getEffectiveModelId(metadata, leftGroup));
SymbolMap symbolmap = (SymbolMap) view.getProperty(Info.SYMBOL_MAP);
HashMap<ElementSymbol, List<Set<Constant>>> newPartitionInfo = new LinkedHashMap<ElementSymbol, List<Set<Constant>>>();
Map<Expression, ElementSymbol> inverse = symbolmap.inserseMapping();
for (int[] match : matches) {
updatePartitionInfo(partitionInfo, matches, inverse, newPartitionInfo, match[0]);
updatePartitionInfo(rightPartionInfo, matches, inverse, newPartitionInfo, match[1]);
}
view.setProperty(Info.PARTITION_INFO, newPartitionInfo);
// since we've created a new union node, there's a chance we can decompose again
if (view.getParent().getType() == NodeConstants.Types.JOIN) {
return decomposeJoin(view.getParent(), root, metadata, context);
}
return root;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class PartitionAnalyzer method extractPartitionInfo.
private static Map<ElementSymbol, Set<Constant>> extractPartitionInfo(Query query, List<ElementSymbol> projectedSymbols) {
List<Expression> projected = query.getSelect().getProjectedSymbols();
List<Criteria> crits = Criteria.separateCriteriaByAnd(query.getCriteria());
Map<Expression, Set<Constant>> inMap = new HashMap<Expression, Set<Constant>>();
for (Criteria criteria : crits) {
if (criteria instanceof CompareCriteria) {
CompareCriteria cc = (CompareCriteria) criteria;
if (cc.getOperator() != CompareCriteria.EQ) {
continue;
}
if (cc.getLeftExpression() instanceof Constant) {
inMap.put(cc.getRightExpression(), new HashSet<Constant>(Arrays.asList((Constant) cc.getLeftExpression())));
} else if (cc.getRightExpression() instanceof Constant) {
inMap.put(cc.getLeftExpression(), new HashSet<Constant>(Arrays.asList((Constant) cc.getRightExpression())));
}
continue;
}
if (!(criteria instanceof SetCriteria)) {
continue;
}
SetCriteria sc = (SetCriteria) criteria;
HashSet<Constant> values = new HashSet<Constant>();
boolean allConstants = true;
for (Expression exp : (Collection<Expression>) sc.getValues()) {
if (exp instanceof Constant) {
values.add((Constant) exp);
} else {
allConstants = false;
break;
}
}
if (allConstants) {
inMap.put(sc.getExpression(), values);
}
}
Map<ElementSymbol, Set<Constant>> result = new HashMap<ElementSymbol, Set<Constant>>();
for (int i = 0; i < projected.size(); i++) {
Expression ex = SymbolMap.getExpression(projected.get(i));
if (DataTypeManager.isNonComparable(DataTypeManager.getDataTypeName(ex.getType()))) {
continue;
}
if (ex instanceof Constant) {
result.put(projectedSymbols.get(i), Collections.singleton((Constant) ex));
} else {
Set<Constant> values = inMap.get(ex);
if (values != null) {
result.put(projectedSymbols.get(i), values);
}
}
}
return result;
}
Aggregations