use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RulePlanOuterJoins method checkLeftOrdering.
/**
* Check if the current join spans inner/left outer joins, such that
* a different tree structure would group the join for pushing
*
* TODO: this is not tolerant to more complex left nesting structures
*
* @param metadata
* @param capabilitiesFinder
* @param analysisRecord
* @param context
* @param join
* @return true if the current join has been restructured
* @throws QueryMetadataException
* @throws TeiidComponentException
*/
private boolean checkLeftOrdering(QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder, AnalysisRecord analysisRecord, CommandContext context, PlanNode join) throws QueryMetadataException, TeiidComponentException {
if (join.getFirstChild().getType() != NodeConstants.Types.JOIN || !(join.getFirstChild().getProperty(Info.JOIN_TYPE) == JoinType.JOIN_LEFT_OUTER || join.getFirstChild().getProperty(Info.JOIN_TYPE) == JoinType.JOIN_INNER)) {
return false;
}
PlanNode childJoin = null;
PlanNode left = join.getFirstChild();
PlanNode right = join.getLastChild();
boolean nested = false;
boolean hasOuter = join.getProperty(Info.JOIN_TYPE) == JoinType.JOIN_LEFT_OUTER;
childJoin = left;
while (childJoin.getFirstChild() != null && childJoin.getFirstChild().getType() != NodeConstants.Types.ACCESS) {
if (childJoin.getType() != NodeConstants.Types.JOIN || !(childJoin.getProperty(Info.JOIN_TYPE) == JoinType.JOIN_LEFT_OUTER || childJoin.getProperty(Info.JOIN_TYPE) == JoinType.JOIN_INNER)) {
return false;
}
hasOuter |= childJoin.getProperty(Info.JOIN_TYPE) == JoinType.JOIN_LEFT_OUTER;
List<Criteria> childJoinCriteria = (List<Criteria>) childJoin.getProperty(Info.JOIN_CRITERIA);
if (!isCriteriaValid(childJoinCriteria, metadata, childJoin)) {
return false;
}
childJoin = childJoin.getFirstChild();
left = childJoin;
nested = true;
}
if (nested && hasOuter && !left.hasBooleanProperty(Info.PRESERVE)) {
if (right.getType() != NodeConstants.Types.ACCESS) {
return false;
}
List<Criteria> joinCriteria = (List<Criteria>) join.getProperty(Info.JOIN_CRITERIA);
if (!isCriteriaValid(joinCriteria, metadata, join)) {
return false;
}
joinCriteria = new ArrayList<>(joinCriteria);
RuleChooseJoinStrategy.filterOptionalCriteria(joinCriteria, false);
Set<GroupSymbol> groups = GroupsUsedByElementsVisitor.getGroups(joinCriteria);
if (groups.containsAll(left.getFirstChild().getGroups()) && groups.containsAll(right.getGroups()) && groups.size() == left.getFirstChild().getGroups().size() + right.getGroups().size()) {
Object modelId = RuleRaiseAccess.canRaiseOverJoin(Arrays.asList(left.getFirstChild(), right), metadata, capabilitiesFinder, joinCriteria, JoinType.JOIN_LEFT_OUTER, analysisRecord, context, false, false);
if (modelId == null) {
return false;
}
PlanNode parent = join.getParent();
parent.replaceChild(join, join.getFirstChild());
join.removeAllChildren();
left.getFirstChild().addAsParent(join);
join.addLastChild(right);
join.getGroups().clear();
updateGroups(join);
parent.getGroups().clear();
updateGroups(parent);
return true;
}
}
return false;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RulePlanOuterJoins method planLeftOuterJoinAssociativity.
private boolean planLeftOuterJoinAssociativity(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder, AnalysisRecord analysisRecord, CommandContext context) throws QueryMetadataException, TeiidComponentException {
boolean changedAny = false;
LinkedHashSet<PlanNode> joins = new LinkedHashSet<PlanNode>(NodeEditor.findAllNodes(plan, NodeConstants.Types.JOIN, NodeConstants.Types.ACCESS));
while (!joins.isEmpty()) {
Iterator<PlanNode> i = joins.iterator();
PlanNode join = i.next();
i.remove();
if (!join.getProperty(Info.JOIN_TYPE).equals(JoinType.JOIN_LEFT_OUTER) || join.hasBooleanProperty(Info.PRESERVE)) {
continue;
}
PlanNode childJoin = null;
PlanNode other = null;
PlanNode left = join.getFirstChild();
PlanNode right = join.getLastChild();
if (left.getType() == NodeConstants.Types.JOIN && left.getProperty(Info.JOIN_TYPE) == JoinType.JOIN_LEFT_OUTER) {
childJoin = left;
other = right;
} else if (right.getType() == NodeConstants.Types.JOIN && (right.getProperty(Info.JOIN_TYPE) == JoinType.JOIN_LEFT_OUTER || right.getProperty(Info.JOIN_TYPE) == JoinType.JOIN_INNER)) {
childJoin = right;
other = left;
} else {
continue;
}
PlanNode cSource = other;
if (cSource.getType() != NodeConstants.Types.ACCESS) {
continue;
}
List<Criteria> joinCriteria = (List<Criteria>) join.getProperty(Info.JOIN_CRITERIA);
if (!isCriteriaValid(joinCriteria, metadata, join)) {
continue;
}
List<Criteria> childJoinCriteria = (List<Criteria>) childJoin.getProperty(Info.JOIN_CRITERIA);
if (!isCriteriaValid(childJoinCriteria, metadata, childJoin) || childJoin.hasBooleanProperty(Info.PRESERVE)) {
continue;
}
// there are 4 forms we can take
// (a b) c -> a (b c) or (a c) b
// c (b a) -> (c b) a or (c a) b
Set<GroupSymbol> groups = GroupsUsedByElementsVisitor.getGroups(joinCriteria);
if (Collections.disjoint(groups, FrameUtil.findJoinSourceNode(childJoin == left ? childJoin.getFirstChild() : childJoin.getLastChild()).getGroups())) {
// case where absolute order remains the same
PlanNode bSource = childJoin == left ? childJoin.getLastChild() : childJoin.getFirstChild();
if (bSource.getType() != NodeConstants.Types.ACCESS) {
continue;
}
Object modelId = RuleRaiseAccess.canRaiseOverJoin(childJoin == left ? Arrays.asList(bSource, cSource) : Arrays.asList(cSource, bSource), metadata, capabilitiesFinder, joinCriteria, JoinType.JOIN_LEFT_OUTER, analysisRecord, context, false, false);
if (modelId == null) {
continue;
}
// rearrange
PlanNode newParent = RulePlanJoins.createJoinNode();
newParent.setProperty(Info.JOIN_TYPE, JoinType.JOIN_LEFT_OUTER);
PlanNode newChild = RulePlanJoins.createJoinNode();
newChild.setProperty(Info.JOIN_TYPE, JoinType.JOIN_LEFT_OUTER);
joins.remove(childJoin);
if (childJoin == left) {
// a (b c)
newChild.addFirstChild(childJoin.getLastChild());
newChild.addLastChild(other);
newChild.setProperty(Info.JOIN_CRITERIA, joinCriteria);
newParent.addFirstChild(childJoin.getFirstChild());
newParent.addLastChild(newChild);
newParent.setProperty(Info.JOIN_CRITERIA, childJoinCriteria);
} else {
// (c b) a
newChild.addFirstChild(other);
newChild.addLastChild(childJoin.getFirstChild());
newChild.setProperty(Info.JOIN_CRITERIA, joinCriteria);
newParent.addFirstChild(newChild);
newParent.addLastChild(childJoin.getLastChild());
newParent.setProperty(Info.JOIN_CRITERIA, childJoinCriteria);
}
updateGroups(newChild);
updateGroups(newParent);
join.getParent().replaceChild(join, newParent);
if (RuleRaiseAccess.checkConformedSubqueries(newChild.getFirstChild(), newChild, true)) {
RuleRaiseAccess.raiseAccessOverJoin(newChild, newChild.getFirstChild(), modelId, capabilitiesFinder, metadata, true);
changedAny = true;
}
} else if (Collections.disjoint(groups, FrameUtil.findJoinSourceNode(childJoin == right ? childJoin.getFirstChild() : childJoin.getLastChild()).getGroups())) {
PlanNode aSource = childJoin == left ? childJoin.getFirstChild() : childJoin.getLastChild();
if (aSource.getType() != NodeConstants.Types.ACCESS) {
continue;
}
if (!join.getExportedCorrelatedReferences().isEmpty()) {
// TODO: we are not really checking that specifically
continue;
}
Object modelId = RuleRaiseAccess.canRaiseOverJoin(childJoin == left ? Arrays.asList(aSource, cSource) : Arrays.asList(cSource, aSource), metadata, capabilitiesFinder, joinCriteria, JoinType.JOIN_LEFT_OUTER, analysisRecord, context, false, false);
if (modelId == null) {
continue;
}
// rearrange
PlanNode newParent = RulePlanJoins.createJoinNode();
newParent.setProperty(Info.JOIN_TYPE, JoinType.JOIN_LEFT_OUTER);
PlanNode newChild = RulePlanJoins.createJoinNode();
newChild.setProperty(Info.JOIN_TYPE, JoinType.JOIN_LEFT_OUTER);
joins.remove(childJoin);
if (childJoin == left) {
newChild.addFirstChild(childJoin.getFirstChild());
newChild.addLastChild(other);
newParent.addLastChild(childJoin.getLastChild());
} else {
newChild.addFirstChild(other);
newChild.addLastChild(childJoin.getLastChild());
newParent.addLastChild(childJoin.getFirstChild());
}
newChild.addGroups(newChild.getFirstChild().getGroups());
newChild.setProperty(Info.JOIN_CRITERIA, joinCriteria);
newParent.addFirstChild(newChild);
newParent.setProperty(Info.JOIN_CRITERIA, childJoinCriteria);
updateGroups(newChild);
updateGroups(newParent);
join.getParent().replaceChild(join, newParent);
if (RuleRaiseAccess.checkConformedSubqueries(newChild.getFirstChild(), newChild, true)) {
RuleRaiseAccess.raiseAccessOverJoin(newChild, newChild.getFirstChild(), modelId, capabilitiesFinder, metadata, true);
changedAny = true;
}
}
}
return changedAny;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RulePlanProcedures method execute.
/**
* @see org.teiid.query.optimizer.relational.OptimizerRule#execute(org.teiid.query.optimizer.relational.plantree.PlanNode, org.teiid.query.metadata.QueryMetadataInterface, org.teiid.query.optimizer.capabilities.CapabilitiesFinder, org.teiid.query.optimizer.relational.RuleStack, org.teiid.query.analysis.AnalysisRecord, org.teiid.query.util.CommandContext)
*/
public PlanNode execute(PlanNode plan, final QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
for (PlanNode node : NodeEditor.findAllNodes(plan, NodeConstants.Types.SOURCE, NodeConstants.Types.ACCESS)) {
if (!FrameUtil.isProcedure(node.getFirstChild())) {
continue;
}
StoredProcedure proc = (StoredProcedure) node.getProperty(NodeConstants.Info.NESTED_COMMAND);
if (!proc.isProcedureRelational()) {
continue;
}
HashSet<ElementSymbol> inputSymbols = new HashSet<ElementSymbol>();
List<Reference> inputReferences = new LinkedList<Reference>();
PlanNode critNode = node.getParent();
List<Criteria> conjuncts = new LinkedList<Criteria>();
HashSet<ElementSymbol> coveredParams = new HashSet<ElementSymbol>();
for (Iterator<SPParameter> params = proc.getInputParameters().iterator(); params.hasNext(); ) {
SPParameter param = params.next();
ElementSymbol symbol = param.getParameterSymbol();
Expression input = param.getExpression();
inputReferences.add((Reference) input);
inputSymbols.add(symbol);
}
findInputNodes(inputSymbols, critNode, conjuncts, coveredParams);
List<Expression> defaults = new LinkedList<Expression>();
for (Reference ref : inputReferences) {
ElementSymbol symbol = ref.getExpression();
Expression defaultValue = null;
/*try {
defaultValue = ResolverUtil.getDefault(symbol, metadata);
} catch (QueryResolverException qre) {
//Just ignore
}*/
defaults.add(defaultValue);
if (defaultValue == null && !coveredParams.contains(symbol)) {
throw new QueryPlannerException(QueryPlugin.Event.TEIID30270, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30270, symbol));
}
}
/*if (conjuncts.isEmpty()) {
for (int j = 0; j < inputReferences.size(); j++) {
Reference ref = (Reference)inputReferences.get(j);
ref.setValue(defaults.get(j));
}
continue;
}*/
PlanNode accessNode = NodeEditor.findNodePreOrder(node, NodeConstants.Types.ACCESS);
Criteria crit = Criteria.combineCriteria(conjuncts);
if (crit != null) {
accessNode.setProperty(NodeConstants.Info.PROCEDURE_CRITERIA, crit);
accessNode.setProperty(NodeConstants.Info.PROCEDURE_INPUTS, inputReferences);
accessNode.setProperty(NodeConstants.Info.PROCEDURE_DEFAULTS, defaults);
accessNode.setProperty(NodeConstants.Info.IS_DEPENDENT_SET, Boolean.TRUE);
}
}
return plan;
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class RulePushAggregates method addEmptyFilter.
private void addEmptyFilter(Collection<AggregateSymbol> aggregates, PlanNode stageGroup, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, Object modelId) throws QueryMetadataException, TeiidComponentException {
PlanNode selectNode = NodeFactory.getNewNode(NodeConstants.Types.SELECT);
AggregateSymbol count = new AggregateSymbol(NonReserved.COUNT, false, null);
// consider the count aggregate for the push down call below
aggregates.add(count);
Criteria crit = new CompareCriteria(count, CompareCriteria.GT, new Constant(new Integer(0)));
selectNode.setProperty(NodeConstants.Info.SELECT_CRITERIA, crit);
selectNode.setProperty(NodeConstants.Info.IS_HAVING, Boolean.TRUE);
stageGroup.addAsParent(selectNode);
}
use of org.teiid.query.sql.lang.Criteria in project teiid by teiid.
the class JoinRegion method scoreRegion.
/**
* Will provide an estimate of cost by summing the estimated tuples flowing through
* each intermediate join.
*
* @param joinOrder
* @param metadata
* @return
* @throws TeiidComponentException
* @throws QueryMetadataException
* @throws QueryPlannerException
*/
public double scoreRegion(Object[] joinOrder, int startIndex, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, CommandContext context, boolean partial) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
List<Map.Entry<PlanNode, PlanNode>> joinSourceEntries = new ArrayList<Map.Entry<PlanNode, PlanNode>>(joinSourceNodes.entrySet());
double totalIntermediatCost = 0;
double cost = 1;
HashSet<PlanNode> criteria = new HashSet<PlanNode>(this.criteriaNodes);
HashSet<GroupSymbol> groups = new HashSet<GroupSymbol>(this.joinSourceNodes.size());
HashSet<GroupSymbol> rightGroups = new HashSet<GroupSymbol>();
List<Expression> leftExpressions = new ArrayList<Expression>();
List<Expression> rightExpressions = new ArrayList<Expression>();
HashSet<Criteria> nonEquiJoinCriteria = new HashSet<Criteria>();
// only calculate up to the second to last as the last is not an intermediate result
for (int i = 0; i < joinOrder.length - (partial ? 0 : 1); i++) {
boolean hasUnknown = false;
boolean shouldFilter = true;
Integer source = (Integer) joinOrder[i];
Map.Entry<PlanNode, PlanNode> entry = joinSourceEntries.get(source.intValue());
PlanNode joinSourceRoot = entry.getValue();
if (i >= startIndex) {
// check to make sure that this group ordering satisfies the access patterns
if (!this.unsatisfiedAccessPatterns.isEmpty() || this.containsNestedTable) {
PlanNode joinSource = entry.getKey();
Collection<GroupSymbol> requiredGroups = (Collection<GroupSymbol>) joinSource.getProperty(NodeConstants.Info.REQUIRED_ACCESS_PATTERN_GROUPS);
if (requiredGroups != null && !groups.containsAll(requiredGroups)) {
return Double.MAX_VALUE;
}
}
}
rightGroups.clear();
rightGroups.addAll(groups);
groups.addAll(joinSourceRoot.getGroups());
if (startIndex > 0 && i < startIndex) {
continue;
}
float sourceCost = joinSourceRoot.getCardinality();
List<PlanNode> applicableCriteria = null;
CompoundCriteria cc = null;
if (!criteria.isEmpty() && i > 0) {
applicableCriteria = getJoinCriteriaForGroups(groups, criteria);
if (applicableCriteria != null && !applicableCriteria.isEmpty()) {
cc = new CompoundCriteria();
for (PlanNode planNode : applicableCriteria) {
cc.addCriteria((Criteria) planNode.getProperty(NodeConstants.Info.SELECT_CRITERIA));
}
}
}
if (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE) {
sourceCost = UNKNOWN_TUPLE_EST;
hasUnknown = true;
if (cc != null) {
shouldFilter = false;
sourceCost = (float) cost;
criteria.removeAll(applicableCriteria);
if (NewCalculateCostUtil.usesKey(cc, metadata) || (i >= 1 && joinSourceRoot.hasProperty(Info.MAKE_DEP) && !joinSourceRoot.hasBooleanProperty(Info.MAKE_NOT_DEP))) {
sourceCost = Math.min(UNKNOWN_TUPLE_EST, sourceCost * Math.min(NewCalculateCostUtil.UNKNOWN_JOIN_SCALING, sourceCost));
} else {
sourceCost = Math.min(UNKNOWN_TUPLE_EST, sourceCost * NewCalculateCostUtil.UNKNOWN_JOIN_SCALING * 8);
}
}
} else if (Double.isInfinite(sourceCost) || Double.isNaN(sourceCost)) {
return Double.MAX_VALUE;
} else if (i == 1 && applicableCriteria != null && !applicableCriteria.isEmpty()) {
List<Object> key = Arrays.asList(joinOrder[0], joinOrder[1]);
Float depJoinCost = null;
if (depCache != null && depCache.containsKey(key)) {
depJoinCost = depCache.get(key);
} else {
Integer indIndex = (Integer) joinOrder[0];
Map.Entry<PlanNode, PlanNode> indEntry = joinSourceEntries.get(indIndex.intValue());
PlanNode possibleInd = indEntry.getValue();
depJoinCost = getDepJoinCost(metadata, capFinder, context, possibleInd, applicableCriteria, joinSourceRoot);
if (depCache == null) {
depCache = new HashMap<List<Object>, Float>();
}
depCache.put(key, depJoinCost);
}
if (depJoinCost != null) {
sourceCost = depJoinCost;
}
}
if (i > 0 && (applicableCriteria == null || applicableCriteria.isEmpty()) && hasUnknown) {
// cross join penalty
sourceCost *= 10;
}
double rightCost = cost;
cost *= sourceCost;
if (cc != null && applicableCriteria != null && shouldFilter) {
// filter based upon notion of join
leftExpressions.clear();
rightExpressions.clear();
nonEquiJoinCriteria.clear();
Collection<GroupSymbol> leftGroups = joinSourceRoot.getGroups();
RuleChooseJoinStrategy.separateCriteria(leftGroups, rightGroups, leftExpressions, rightExpressions, cc.getCriteria(), nonEquiJoinCriteria);
if (!leftExpressions.isEmpty()) {
float leftNdv = NewCalculateCostUtil.getNDVEstimate(joinSourceRoot, metadata, sourceCost, leftExpressions, null);
float rightNdv = NewCalculateCostUtil.UNKNOWN_VALUE;
if (leftNdv != NewCalculateCostUtil.UNKNOWN_VALUE) {
Set<GroupSymbol> usedRight = GroupsUsedByElementsVisitor.getGroups(rightExpressions);
for (int j = 0; j < i; j++) {
Entry<PlanNode, PlanNode> previousEntry = joinSourceEntries.get((int) joinOrder[j]);
if (previousEntry.getValue().getGroups().containsAll(usedRight)) {
rightNdv = NewCalculateCostUtil.getNDVEstimate(previousEntry.getValue(), metadata, sourceCost, rightExpressions, null);
break;
}
}
}
if (leftNdv != NewCalculateCostUtil.UNKNOWN_VALUE && rightNdv != NewCalculateCostUtil.UNKNOWN_VALUE) {
cost = (sourceCost / leftNdv) * (rightCost / rightNdv) * Math.min(leftNdv, rightNdv);
} else {
// check for a key
// just use the default logic
nonEquiJoinCriteria.clear();
}
} else {
// just use the default logic
nonEquiJoinCriteria.clear();
}
for (PlanNode criteriaNode : applicableCriteria) {
Criteria crit = (Criteria) criteriaNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
if (!nonEquiJoinCriteria.contains(crit)) {
continue;
}
float filter = ((Float) criteriaNode.getProperty(NodeConstants.Info.EST_SELECTIVITY)).floatValue();
cost *= filter;
}
criteria.removeAll(applicableCriteria);
}
totalIntermediatCost += cost;
}
return totalIntermediatCost;
}
Aggregations