protected override BoundRelation RewriteJoinRelation(BoundJoinRelation node) { if (node.JoinType == BoundJoinType.RightOuter) { var newLeft = node.Right; var newRight = node.Left; node = node.Update(BoundJoinType.LeftOuter, newLeft, newRight, node.Condition, node.Probe, node.PassthruPredicate); } return(base.RewriteJoinRelation(node)); }
protected override BoundRelation RewriteJoinRelation(BoundJoinRelation node) { var left = RewriteRelation(node.Left); var right = RewriteRelation(node.Right); var rewrittenRight = RewriteConjunctions(right, node.Condition); if (rewrittenRight != null) { // We might have residual subqueries that couldn't be // converted to semi joins. return(RewriteRelation(node.Update(node.JoinType, left, rewrittenRight, null, node.Probe, node.PassthruPredicate))); } // There were no subqueries that could be expressed as semi joins. // However, there might still exist subqueries, so we need to visit // the expression that will convert them to probing semi joins. var condition = RewriteExpression(node.Condition); var rightWithProbes = RewriteInputWithSubqueries(right); return(node.Update(node.JoinType, left, rightWithProbes, condition, node.Probe, node.PassthruPredicate)); }
protected override BoundRelation RewriteJoinRelation(BoundJoinRelation node) { var newLeft = RewriteRelation(node.Left); bool semiJoinContext; semiJoinContext = (node.JoinType == BoundJoinType.LeftSemi || node.JoinType == BoundJoinType.LeftAntiSemi); _semiJoinContextFlagStack.Push(semiJoinContext); var newRight = RewriteRelation(node.Right); _semiJoinContextFlagStack.Pop(); return(node.Update(node.JoinType, newLeft, newRight, node.Condition, node.Probe, node.PassthruPredicate)); }
protected override BoundRelation RewriteJoinRelation(BoundJoinRelation node) { if (node.Condition != null && node.Probe == null) { BoundExpression pushedLeft = null; BoundExpression pushedRight = null; BoundExpression remainder = null; foreach (var conjunction in Expression.SplitConjunctions(node.Condition)) { if (AllowsLeftPushDown(node.JoinType) && !conjunction.DependsOnAny(node.Right.GetOutputValues())) { pushedLeft = Expression.And(pushedLeft, conjunction); } else if (AllowsRightPushDown(node.JoinType) && !conjunction.DependsOnAny(node.Left.GetOutputValues())) { pushedRight = Expression.And(pushedRight, conjunction); } else { remainder = Expression.And(remainder, conjunction); } } var newLeft = pushedLeft == null ? node.Left : new BoundFilterRelation(node.Left, pushedLeft); var newRight = pushedRight == null ? node.Right : new BoundFilterRelation(node.Right, pushedRight); var newNode = node.Update(node.JoinType, RewriteRelation(newLeft), RewriteRelation(newRight), remainder, RewriteValueSlot(node.Probe), RewriteExpression(node.PassthruPredicate)); return(newNode); } return(base.RewriteJoinRelation(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)); }
private BoundRelation MergeWithOrPushOverJoin(BoundFilterRelation node, BoundJoinRelation input) { // TODO: Right now, we're not pushing over a join if it has any probing. // // That might be too restristive. It should be OK to push a over // a join to the side that isn't affecting the probe column. // // In other words: // // * pushing to the left is OK if it's a left (anti) semi join // * pushing to the right is OK if it's a right (anti) semi join if (input.Probe != null) { return(node.Update(RewriteRelation(input), node.Condition)); } if (AllowsMerge(input.JoinType)) { var newCondition = Expression.And(input.Condition, node.Condition); var newInput = input.Update(input.JoinType, input.Left, input.Right, newCondition, null, null); return(RewriteRelation(newInput)); } else { BoundExpression pushedLeft = null; BoundExpression pushedRight = null; BoundExpression remainder = null; foreach (var conjunction in Expression.SplitConjunctions(node.Condition)) { if (AllowsLeftPushOver(input.JoinType) && !conjunction.DependsOnAny(input.Right.GetOutputValues())) { pushedLeft = Expression.And(pushedLeft, conjunction); } else if (AllowsRightPushOver(input.JoinType) && !conjunction.DependsOnAny(input.Left.GetOutputValues())) { pushedRight = Expression.And(pushedRight, conjunction); } else { remainder = Expression.And(remainder, conjunction); } } var newLeft = pushedLeft == null ? input.Left : new BoundFilterRelation(input.Left, pushedLeft); var newRight = pushedRight == null ? input.Right : new BoundFilterRelation(input.Right, pushedRight); var newInput = input.Update(input.JoinType, RewriteRelation(newLeft), RewriteRelation(newRight), input.Condition, RewriteValueSlot(input.Probe), RewriteExpression(input.PassthruPredicate)); var newNode = remainder == null ? (BoundRelation)newInput : node.Update(newInput, remainder); return(newNode); } }