Пример #1
0
        protected override BoundRelation RewriteJoinRelation(BoundJoinRelation node)
        {
            // First, let's rewrite our inputs

            node = (BoundJoinRelation)base.RewriteJoinRelation(node);

            // Get defined values of left and right

            var leftDefinedValues  = new HashSet <ValueSlot>(node.Left.GetDefinedValues());
            var rightDefinedValues = new HashSet <ValueSlot>(node.Right.GetDefinedValues());

            var extractedConjunctions = new List <BoundExpression>();

            // Try to pull up conjunctions that contain outer references from a left sided filter and combine
            // them with the join predicate.
            //
            // NOTE: This is only possible if the join is not a LEFT OUTER or FULL OUTER JOIN since this
            // operation would change the join's semantic.

            if (node.JoinType != BoundJoinType.LeftOuter &&
                node.JoinType != BoundJoinType.FullOuter)
            {
                if (node.Left is BoundFilterRelation leftAsFilter)
                {
                    var anythingExtracted     = false;
                    var remainingConjunctions = new List <BoundExpression>();

                    foreach (var conjunction in Expression.SplitConjunctions(leftAsFilter.Condition))
                    {
                        if (!ConjunctionHasOuterReference(leftDefinedValues, conjunction))
                        {
                            remainingConjunctions.Add(conjunction);
                        }
                        else
                        {
                            anythingExtracted = true;
                            extractedConjunctions.Add(conjunction);
                        }
                    }

                    if (!anythingExtracted)
                    {
                        // We haven't extracted any conjunctions.
                        //
                        // In order to avoid creating new node, we just do nothing.
                    }
                    else
                    {
                        var newCondition = Expression.And(remainingConjunctions);
                        if (newCondition == null)
                        {
                            node = node.WithLeft(leftAsFilter.Input);
                        }
                        else
                        {
                            leftAsFilter = leftAsFilter.WithCondition(newCondition);
                            node         = node.WithLeft(leftAsFilter);
                        }
                    }
                }
            }

            // Try to pull up conjunctions that contain outer references from a right sided filter and combine
            // them with the join predicate.
            //
            // NOTE: This is only possible if the join is not a RIGHT OUTER or FULL OUTER JOIN since this
            // operation would change the join's semantic.

            if (node.JoinType != BoundJoinType.RightOuter &&
                node.JoinType != BoundJoinType.FullOuter)
            {
                if (node.Right is BoundFilterRelation rightAsFilter)
                {
                    var anythingExtracted     = false;
                    var remainingConjunctions = new List <BoundExpression>();

                    foreach (var conjunction in Expression.SplitConjunctions(rightAsFilter.Condition))
                    {
                        if (!ConjunctionHasOuterReference(rightDefinedValues, conjunction))
                        {
                            remainingConjunctions.Add(conjunction);
                        }
                        else
                        {
                            anythingExtracted = true;
                            extractedConjunctions.Add(conjunction);
                        }
                    }

                    if (!anythingExtracted)
                    {
                        // We haven't extracted any conjunctions.
                        //
                        // In order to avoid creating new node, we just do nothing.
                    }
                    else
                    {
                        var newCondition = Expression.And(remainingConjunctions);
                        if (newCondition == null)
                        {
                            node = node.WithRight(rightAsFilter.Input);
                        }
                        else
                        {
                            rightAsFilter = rightAsFilter.WithCondition(newCondition);
                            node          = node.WithRight(rightAsFilter);
                        }
                    }
                }
            }

            // If we found any conjunctions that could be pulled up, merge them with the join predicate.

            if (extractedConjunctions.Any())
            {
                var newCondition = Expression.And(new[] { node.Condition }.Concat(extractedConjunctions));
                node = node.WithCondition(newCondition);
            }

            // Now we try to extract conjunctions that contain outer references from the join
            // predicate itself.
            //
            // NOTE: This is only possible if the node is not an OUTER JOIN. If the node is a
            // SEMI JOIN the operation is only legal if the conjunction does not reference any
            // columns from the side that is used as filter criteria (i.e. for LSJ this is the
            // right side, for RSJ this is the left side).

            if (node.JoinType != BoundJoinType.LeftOuter &&
                node.JoinType != BoundJoinType.RightOuter &&
                node.JoinType != BoundJoinType.FullOuter &&
                node.Condition != null)
            {
                var conjunctionsAboveJoin = new List <BoundExpression>();
                var remainingConjunctions = new List <BoundExpression>();
                var definedValues         = new HashSet <ValueSlot>(leftDefinedValues.Concat(rightDefinedValues));

                foreach (var conjunction in Expression.SplitConjunctions(node.Condition))
                {
                    if (ConjunctionHasOuterReference(definedValues, conjunction) && SemiJoinDoesNotDependOn(node.JoinType, conjunction, rightDefinedValues))
                    {
                        conjunctionsAboveJoin.Add(conjunction);
                    }
                    else
                    {
                        remainingConjunctions.Add(conjunction);
                    }
                }

                if (conjunctionsAboveJoin.Any())
                {
                    var newCondition = Expression.And(remainingConjunctions);
                    node = node.WithCondition(newCondition);

                    var filterCondition = Expression.And(conjunctionsAboveJoin);
                    var filter          = new BoundFilterRelation(node, filterCondition);
                    return(filter);
                }
            }

            return(node);
        }
Пример #2
0
        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.WithInput(RewriteRelation(input)));
            }

            if (AllowsMerge(input.JoinType))
            {
                var newCondition = Expression.And(input.Condition, node.Condition);
                var newInput     = input.WithCondition(newCondition);
                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);
            }
        }