public static bool DependsOnAny(this BoundExpression condition, IEnumerable <ValueSlot> valueSlots) { var finder = new ValueSlotDependencyFinder(); finder.VisitExpression(condition); return(finder.ValueSlots.Overlaps(valueSlots)); }
private bool ConjunctionHasOuterReference(HashSet <ValueSlot> definedValueSet, BoundExpression conjunction) { var valueSlotFinder = new ValueSlotDependencyFinder(); valueSlotFinder.VisitExpression(conjunction); return(!valueSlotFinder.ValueSlots.All(definedValueSet.Contains)); }
private static void BuildGraph(List <BoundRelation> relations, List <BoundExpression> predicates, out ICollection <JoinNode> nodes, out ICollection <JoinEdge> edges) { var nodeByRelation = relations.Select(r => new JoinNode(r)).ToDictionary(n => n.Relation); nodes = nodeByRelation.Values; edges = new List <JoinEdge>(); var edgeByNodes = new Dictionary <ValueTuple <JoinNode, JoinNode>, JoinEdge>(); var relationByValueSlot = relations.SelectMany(r => r.GetDefinedValues(), ValueTuple.Create) .ToDictionary(t => t.Item2, t => t.Item1); var dependencyFinder = new ValueSlotDependencyFinder(); foreach (var predicate in predicates) { dependencyFinder.ValueSlots.Clear(); dependencyFinder.VisitExpression(predicate); var referencedSlots = dependencyFinder.ValueSlots; var referencedRelations = referencedSlots.Where(v => relationByValueSlot.ContainsKey(v)) .Select(v => relationByValueSlot[v]) .ToImmutableArray(); if (referencedRelations.Length == 2) { var left = nodeByRelation[referencedRelations[0]]; var right = nodeByRelation[referencedRelations[1]]; var leftRight = ValueTuple.Create(left, right); var rightLeft = ValueTuple.Create(right, left); JoinEdge edge; if (!edgeByNodes.TryGetValue(leftRight, out edge)) { if (!edgeByNodes.TryGetValue(rightLeft, out edge)) { edge = new JoinEdge(left, right); left.Edges.Add(edge); right.Edges.Add(edge); edges.Add(edge); edgeByNodes.Add(leftRight, edge); } } edge.Conditions.Add(predicate); } } }
protected override BoundRelation RewriteFilterRelation(BoundFilterRelation node) { // Check for null rejecting conditions. var dependencyFinder = new ValueSlotDependencyFinder(); foreach (var conjunction in Expression.SplitConjunctions(node.Condition)) { dependencyFinder.ValueSlots.Clear(); dependencyFinder.VisitExpression(conjunction); var slots = dependencyFinder.ValueSlots; var nullRejectedSlots = slots.Where(v => NullRejection.IsRejectingNull(conjunction, v)); foreach (var valueSlot in nullRejectedSlots) { AddNullRejectedTable(valueSlot); } } return(base.RewriteFilterRelation(node)); }
protected override BoundRelation RewriteJoinRelation(BoundJoinRelation node) { // Get declared tables of left and right var leftDefinedValues = node.Left.GetDefinedValues().ToImmutableArray(); var rightDefinedValues = node.Right.GetDefinedValues().ToImmutableArray(); // Replace outer joins by left-/right-/inner joins if (node.JoinType == BoundJoinType.RightOuter || node.JoinType == BoundJoinType.FullOuter) { if (IsAnyNullRejected(leftDefinedValues)) { var newType = node.JoinType == BoundJoinType.RightOuter ? BoundJoinType.Inner : BoundJoinType.LeftOuter; node = node.Update(newType, node.Left, node.Right, node.Condition, node.Probe, node.PassthruPredicate); } } if (node.JoinType == BoundJoinType.LeftOuter || node.JoinType == BoundJoinType.FullOuter) { if (IsAnyNullRejected(rightDefinedValues)) { var newType = node.JoinType == BoundJoinType.LeftOuter ? BoundJoinType.Inner : BoundJoinType.RightOuter; node = node.Update(newType, node.Left, node.Right, node.Condition, node.Probe, node.PassthruPredicate); } } // After converting an outer join to an inner one we can // sometimes eliminate the whole join. if (node.JoinType == BoundJoinType.Inner) { if (node.Left is BoundConstantRelation && !node.Left.GetDefinedValues().Any()) { return(RewriteRelation(WrapWithFilter(node.Right, node.Condition))); } if (node.Right is BoundConstantRelation && !node.Right.GetDefinedValues().Any()) { return(RewriteRelation(WrapWithFilter(node.Left, node.Condition))); } } // Analyze AND-parts of Condition if (node.JoinType != BoundJoinType.FullOuter) { var dependencyFinder = new ValueSlotDependencyFinder(); foreach (var conjunction in Expression.SplitConjunctions(node.Condition)) { // Check if we can derive from this conjunction that a table it depends on // is null-rejected. dependencyFinder.ValueSlots.Clear(); dependencyFinder.VisitExpression(conjunction); var slots = dependencyFinder.ValueSlots; var nullRejectedSlots = slots.Where(v => NullRejection.IsRejectingNull(conjunction, v)); foreach (var valueSlot in nullRejectedSlots) { if (node.JoinType != BoundJoinType.LeftOuter && leftDefinedValues.Contains(valueSlot)) { AddNullRejectedTable(valueSlot); } else if (node.JoinType != BoundJoinType.RightOuter && rightDefinedValues.Contains(valueSlot)) { AddNullRejectedTable(valueSlot); } } } } // Visit children return(base.RewriteJoinRelation(node)); }
public void Record(BoundExpression expression) { _finder.VisitExpression(expression); }