Exemple #1
0
        private AlgebraNode PushOverJoin(ComputeScalarAlgebraNode node)
        {
            JoinAlgebraNode joinAlgebraNode = (JoinAlgebraNode)node.Input;

            RowBufferEntry[] leftDefinedValues  = AstUtil.GetDefinedValueEntries(joinAlgebraNode.Left);
            RowBufferEntry[] rightDefinedValues = AstUtil.GetDefinedValueEntries(joinAlgebraNode.Right);

            List <ComputedValueDefinition> remainingValueDefinitions   = new List <ComputedValueDefinition>();
            List <ComputedValueDefinition> leftPushedValueDefinitions  = new List <ComputedValueDefinition>();
            List <ComputedValueDefinition> rightPushedValueDefinitions = new List <ComputedValueDefinition>();

            bool canPushToLeftSide = joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.RightOuterJoin &&
                                     joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin;

            bool canPushToRightSide = joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.LeftOuterJoin &&
                                      joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin;

            foreach (ComputedValueDefinition valueDefinition in node.DefinedValues)
            {
                RowBufferEntry[] referencedValues      = AstUtil.GetRowBufferEntryReferences(valueDefinition.Expression);
                bool             referencesProbeColumn = ArrayHelpers.Contains(referencedValues, joinAlgebraNode.ProbeBufferEntry);

                if (!referencesProbeColumn && canPushToLeftSide && AstUtil.DoesNotReference(referencedValues, rightDefinedValues))
                {
                    leftPushedValueDefinitions.Add(valueDefinition);
                }
                else if (!referencesProbeColumn && canPushToRightSide && AstUtil.DoesNotReference(referencedValues, leftDefinedValues))
                {
                    rightPushedValueDefinitions.Add(valueDefinition);
                }
                else
                {
                    remainingValueDefinitions.Add(valueDefinition);
                }
            }

            if (leftPushedValueDefinitions.Count > 0)
            {
                ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode();
                computeScalarAlgebraNode.DefinedValues = leftPushedValueDefinitions.ToArray();
                computeScalarAlgebraNode.Input         = joinAlgebraNode.Left;
                joinAlgebraNode.Left = VisitAlgebraNode(computeScalarAlgebraNode);
            }

            if (rightPushedValueDefinitions.Count > 0)
            {
                ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode();
                computeScalarAlgebraNode.DefinedValues = rightPushedValueDefinitions.ToArray();
                computeScalarAlgebraNode.Input         = joinAlgebraNode.Right;
                joinAlgebraNode.Right = VisitAlgebraNode(computeScalarAlgebraNode);
            }

            if (remainingValueDefinitions.Count == 0)
            {
                return(joinAlgebraNode);
            }

            node.DefinedValues = remainingValueDefinitions.ToArray();
            return(node);
        }
Exemple #2
0
        ////REVIEW: given that the PlayerConnection will connect to the editor regardless, we end up
        ////        on this path whether input remoting is enabled or not
        private void OnConnected(int id)
        {
            if (m_ConnectedIds != null && ArrayHelpers.Contains(m_ConnectedIds, id))
                return;

            ArrayHelpers.Append(ref m_ConnectedIds, id);

            SendToSubscribers(InputRemoting.MessageType.Connect, new MessageEventArgs {playerId = id});
        }
Exemple #3
0
        private void OnDisconnected(int id)
        {
            if (m_ConnectedIds == null || !ArrayHelpers.Contains(m_ConnectedIds, id))
                return;

            ArrayHelpers.Erase(ref m_ConnectedIds, id);

            SendToSubscribers(InputRemoting.MessageType.Disconnect, new MessageEventArgs {playerId = id});
        }
        public override ExpressionNode VisitColumnExpression(ColumnExpression expression)
        {
            if (!ArrayHelpers.Contains(_groupedTableRefs, expression.Column.TableRefBinding))
            {
                // The column's table does not belong to the grouped table list.
                // Therfore it is an ungrouped column.
                _ungroupedColumnList.Add(expression.Column);
            }

            return(base.VisitColumnExpression(expression));
        }
Exemple #5
0
        public static bool DoesNotReference(RowBufferEntry[] rowBufferEntryReferences, RowBufferEntry[] rowBufferEntries)
        {
            foreach (RowBufferEntry rowBufferColumnDependency in rowBufferEntryReferences)
            {
                if (ArrayHelpers.Contains(rowBufferEntries, rowBufferColumnDependency))
                {
                    return(false);
                }
            }

            return(true);
        }
Exemple #6
0
            private bool IsOuterReference(RowBufferEntry entry)
            {
                foreach (RowBufferEntry[] outerReferences in _outerReferences)
                {
                    if (ArrayHelpers.Contains(outerReferences, entry))
                    {
                        return(true);
                    }
                }

                return(false);
            }
Exemple #7
0
        private static bool AndPartHasOuterReference(ExpressionNode andPart, RowBufferEntry[] definedValues)
        {
            RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(andPart);
            foreach (RowBufferEntry rowBufferEntry in rowBufferEntries)
            {
                if (!ArrayHelpers.Contains(definedValues, rowBufferEntry))
                {
                    return(true);
                }
            }

            return(false);
        }
Exemple #8
0
 private bool CheckIfNodeHasDependenciesToOuterReferences(AlgebraNode node)
 {
     foreach (RowBufferEntry rowBufferEntryReference in AstUtil.GetRowBufferEntryReferences(node))
     {
         foreach (RowBufferEntry[] outerReferences in _outerReferences)
         {
             if (ArrayHelpers.Contains(outerReferences, rowBufferEntryReference))
             {
                 return(true);
             }
         }
     }
     return(false);
 }
Exemple #9
0
        public static bool ConversionNeeded(Type fromType, Type targetType)
        {
            if (fromType == targetType)
            {
                return(false);
            }

            // NULL does not need any conversion.

            if (fromType == typeof(DBNull) || targetType == typeof(DBNull))
            {
                return(false);
            }

            // Check if fromType is derived from targetType. In this
            // case no conversion is needed.

            Type baseType = fromType.BaseType;

            while (baseType != null)
            {
                if (baseType == targetType)
                {
                    return(false);
                }

                baseType = baseType.BaseType;
            }

            if (fromType.IsInterface && targetType == typeof(object))
            {
                // Though interfaces are not derived from System.Object, they are
                // compatible to it.
                return(false);
            }

            if (targetType.IsInterface)
            {
                // Check if fromType implements targetType. In this
                // case no conversion is needed.

                if (ArrayHelpers.Contains(fromType.GetInterfaces(), targetType))
                {
                    return(false);
                }
            }

            return(true);
        }
Exemple #10
0
            public override ExpressionNode VisitBinaryExpression(BinaryExpression expression)
            {
                if (expression.Op == BinaryOperator.LogicalAnd)
                {
                    return(base.VisitBinaryExpression(expression));
                }
                else if (expression.Op == BinaryOperator.Equal)
                {
                    RowBufferEntry[] leftRowBufferEntries  = AstUtil.GetRowBufferEntryReferences(expression.Left);
                    RowBufferEntry[] rightRowBufferEntries = AstUtil.GetRowBufferEntryReferences(expression.Right);

                    if (leftRowBufferEntries.Length == 1 && rightRowBufferEntries.Length == 1)
                    {
                        RowBufferEntry leftRowBufferEntry  = leftRowBufferEntries[0];
                        RowBufferEntry rightRowBufferEntry = rightRowBufferEntries[0];

                        if (leftRowBufferEntry != rightRowBufferEntry)
                        {
                            // Both expressions depend on extactly one row buffer entry but
                            // they are not refering to the same row buffer entry.

                            bool leftDependsOnLeft   = ArrayHelpers.Contains(_leftDefinedEntries, leftRowBufferEntry);
                            bool rightDependsOnRight = ArrayHelpers.Contains(_rightDefinedEntries, rightRowBufferEntry);

                            bool leftDependsOnRight = ArrayHelpers.Contains(_rightDefinedEntries, leftRowBufferEntry);
                            bool rightDependsOnLeft = ArrayHelpers.Contains(_leftDefinedEntries, rightRowBufferEntry);

                            if (leftDependsOnRight && rightDependsOnLeft)
                            {
                                ExpressionNode oldLeft = expression.Left;
                                expression.Left     = expression.Right;
                                expression.Right    = oldLeft;
                                leftDependsOnLeft   = true;
                                rightDependsOnRight = true;
                            }

                            if (leftDependsOnLeft && rightDependsOnRight)
                            {
                                _equalPredicates.Add(expression);
                                return(LiteralExpression.FromBoolean(true));
                            }
                        }
                    }
                }

                return(expression);
            }
Exemple #11
0
        private AlgebraNode PushOverValueDefininingUnary(IEnumerable <ValueDefinition> definedValues, FilterAlgebraNode node)
        {
            UnaryAlgebraNode      inputNode            = (UnaryAlgebraNode)node.Input;
            List <ExpressionNode> nonDependingAndParts = new List <ExpressionNode>();
            List <ExpressionNode> dependingAndParts    = new List <ExpressionNode>();

            foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, node.Predicate))
            {
                RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(andPart);

                bool dependsOnDefinedValue = false;
                foreach (ValueDefinition definedValue in definedValues)
                {
                    if (ArrayHelpers.Contains(rowBufferEntries, definedValue.Target))
                    {
                        dependsOnDefinedValue = true;
                        break;
                    }
                }

                if (dependsOnDefinedValue)
                {
                    dependingAndParts.Add(andPart);
                }
                else
                {
                    nonDependingAndParts.Add(andPart);
                }
            }

            if (nonDependingAndParts.Count > 0)
            {
                node.Predicate  = AstUtil.CombineConditions(LogicalOperator.And, dependingAndParts);
                inputNode.Input = GetFilterFromAndParts(nonDependingAndParts, inputNode.Input);

                if (node.Predicate == null)
                {
                    node.Input      = inputNode.Input;
                    inputNode.Input = VisitAlgebraNode(node);
                    return(inputNode);
                }
            }

            node.Input = VisitAlgebraNode(node.Input);
            return(node);
        }
Exemple #12
0
        private static IteratorOutput[] GetIteratorOutput(int offset, RowBufferEntry[] allEntries, RowBufferEntry[] neededEntries)
        {
            List <IteratorOutput> result = new List <IteratorOutput>(neededEntries.Length);

            for (int i = 0; i < allEntries.Length; i++)
            {
                if (ArrayHelpers.Contains(neededEntries, allEntries[i]))
                {
                    IteratorOutput iteratorOutput = new IteratorOutput();
                    iteratorOutput.SourceIndex = i;
                    iteratorOutput.TargetIndex = offset + result.Count;
                    result.Add(iteratorOutput);
                }
            }

            return(result.ToArray());
        }
Exemple #13
0
        public static RowBufferEntry[] GetOuterReferences(JoinAlgebraNode node)
        {
            RowBufferEntry[] leftDefinedValues = GetDefinedValueEntries(node.Left);

            RowBufferEntry[]      rowBufferEntries   = GetRowBufferEntryReferences(node.Right);
            List <RowBufferEntry> outerReferenceList = new List <RowBufferEntry>();

            foreach (RowBufferEntry rightColumnDependency in rowBufferEntries)
            {
                if (ArrayHelpers.Contains(leftDefinedValues, rightColumnDependency))
                {
                    outerReferenceList.Add(rightColumnDependency);
                }
            }

            return(outerReferenceList.ToArray());
        }
Exemple #14
0
        public static bool JoinDoesNotDependOn(JoinAlgebraNode joinNode, AlgebraNode joinSide)
        {
            RowBufferEntry[] joinSideDefinedValues = GetDefinedValueEntries(joinSide);

            if (joinNode.Predicate != null)
            {
                RowBufferEntry[] referencedRowBufferEntries = GetRowBufferEntryReferences(joinNode.Predicate);

                foreach (RowBufferEntry joinSideDefinedValue in joinSideDefinedValues)
                {
                    if (ArrayHelpers.Contains(referencedRowBufferEntries, joinSideDefinedValue))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
Exemple #15
0
        private void PushOuterReferences(object[] rowBuffer, JoinAlgebraNode node)
        {
            if (node.OuterReferences != null && node.OuterReferences.Length > 0)
            {
                // Important: We cannot use node.OuterReferences as argument for BoundRowBufferEntrySet().
                // The replacment strategy below will replace occurences to the entries by their index
                // within the array. Therefore we need an array with the same layout as the row buffer.

                RowBufferEntry[] outerReferences = new RowBufferEntry[node.Left.OutputList.Length];
                for (int i = 0; i < outerReferences.Length; i++)
                {
                    if (ArrayHelpers.Contains(node.OuterReferences, node.Left.OutputList[i]))
                    {
                        outerReferences[i] = node.Left.OutputList[i];
                    }
                }

                BoundRowBufferEntrySet bufferEntrySet = new BoundRowBufferEntrySet(rowBuffer, outerReferences);
                _outerReferenceStack.Push(bufferEntrySet);
            }
        }
        public override AlgebraNode VisitConcatAlgebraNode(ConcatAlgebraNode node)
        {
            base.VisitConcatAlgebraNode(node);

            List <AlgebraNode> nonEmptyInputs = new List <AlgebraNode>();

            foreach (AlgebraNode input in node.Inputs)
            {
                if (input is NullScanAlgebraNode)
                {
                    // removed by not adding to list.
                }
                else
                {
                    nonEmptyInputs.Add(input);
                }
            }

            if (nonEmptyInputs.Count == 0)
            {
                return(CreateNullScan(node.OutputList));
            }

            if (nonEmptyInputs.Count == 1)
            {
                int inputIndex = Array.IndexOf(node.Inputs, nonEmptyInputs[0]);

                List <ComputedValueDefinition> definedValues            = new List <ComputedValueDefinition>();
                ComputeScalarAlgebraNode       computeScalarAlgebraNode = new ComputeScalarAlgebraNode();
                computeScalarAlgebraNode.Input = nonEmptyInputs[0];
                foreach (UnitedValueDefinition unitedValueDefinition in node.DefinedValues)
                {
                    ComputedValueDefinition computedValueDefinition = new ComputedValueDefinition();
                    computedValueDefinition.Target     = unitedValueDefinition.Target;
                    computedValueDefinition.Expression = new RowBufferEntryExpression(unitedValueDefinition.DependendEntries[inputIndex]);
                    definedValues.Add(computedValueDefinition);
                }
                computeScalarAlgebraNode.DefinedValues = definedValues.ToArray();
                computeScalarAlgebraNode.OutputList    = node.OutputList;
                return(computeScalarAlgebraNode);
            }

            node.Inputs = nonEmptyInputs.ToArray();

            // Update dependend entries

            for (int i = 0; i < node.DefinedValues.Length; i++)
            {
                UnitedValueDefinition definition       = node.DefinedValues[i];
                List <RowBufferEntry> dependendEntries = new List <RowBufferEntry>();

                foreach (RowBufferEntry dependendEntry in definition.DependendEntries)
                {
                    bool entryInAnyInput = false;

                    foreach (AlgebraNode input in node.Inputs)
                    {
                        if (ArrayHelpers.Contains(input.OutputList, dependendEntry))
                        {
                            entryInAnyInput = true;
                            break;
                        }
                    }

                    if (entryInAnyInput)
                    {
                        dependendEntries.Add(dependendEntry);
                    }
                }

                definition.DependendEntries = dependendEntries.ToArray();
            }
            return(node);
        }
        public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node)
        {
            // Get declared tables of left and right

            RowBufferEntry[] leftDefinedValues  = AstUtil.GetDefinedValueEntries(node.Left);
            RowBufferEntry[] rightDefinedValues = AstUtil.GetDefinedValueEntries(node.Right);

            // Replace outer joins by left-/right-/inner joins

            if (node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin ||
                node.Op == JoinAlgebraNode.JoinOperator.FullOuterJoin)
            {
                if (IsAnyNullRejected(leftDefinedValues))
                {
                    if (node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin)
                    {
                        node.Op = JoinAlgebraNode.JoinOperator.InnerJoin;
                    }
                    else
                    {
                        node.Op = JoinAlgebraNode.JoinOperator.LeftOuterJoin;
                    }
                }
            }

            if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin ||
                node.Op == JoinAlgebraNode.JoinOperator.FullOuterJoin)
            {
                if (IsAnyNullRejected(rightDefinedValues))
                {
                    if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin)
                    {
                        node.Op = JoinAlgebraNode.JoinOperator.InnerJoin;
                    }
                    else
                    {
                        node.Op = JoinAlgebraNode.JoinOperator.RightOuterJoin;
                    }
                }
            }

            // After converting an outer join to an inner one we can
            // sometimes eliminate the whole join.

            if (node.Op == JoinAlgebraNode.JoinOperator.InnerJoin)
            {
                // TODO: There is a problem. If the constant scan defines values this does not work. Acutally,
                //       this is currently no problem as the only way to create such a plan is using derived
                //       tables and in this phase the child will be a ResultNode.

                if (node.Left is ConstantScanAlgebraNode)
                {
                    return(VisitAlgebraNode(WrapWithFilter(node.Right, node.Predicate)));
                }

                if (node.Right is ConstantScanAlgebraNode)
                {
                    return(VisitAlgebraNode(WrapWithFilter(node.Left, node.Predicate)));
                }
            }

            // Analyze AND-parts of Condition

            if (node.Predicate == null)
            {
                // TODO: This does not work as the children are not yet rearranged.
                if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin ||
                    node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin)
                {
                    bool hasOuterReferences = AstUtil.GetOuterReferences(node).Length == 0;
                    if (!hasOuterReferences)
                    {
                        if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin && AstUtil.WillProduceAtLeastOneRow(node.Right) ||
                            node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin && AstUtil.WillProduceAtLeastOneRow(node.Left))
                        {
                            node.Op = JoinAlgebraNode.JoinOperator.InnerJoin;
                            return(VisitAlgebraNode(node));
                        }
                    }
                }
            }
            else
            {
                foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, node.Predicate))
                {
                    if (node.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin)
                    {
                        // Check if we can derive from this AND-part that a table it depends on
                        // is null-rejected.

                        RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(andPart);
                        foreach (RowBufferEntry rowBufferEntry in rowBufferEntries)
                        {
                            if (AstUtil.ExpressionYieldsNullOrFalseIfRowBufferEntryNull(andPart, rowBufferEntry))
                            {
                                if (ArrayHelpers.Contains(leftDefinedValues, rowBufferEntry) &&
                                    node.Op != JoinAlgebraNode.JoinOperator.LeftOuterJoin)
                                {
                                    AddNullRejectedTable(rowBufferEntry);
                                }
                                else if (ArrayHelpers.Contains(rightDefinedValues, rowBufferEntry) &&
                                         node.Op != JoinAlgebraNode.JoinOperator.RightOuterJoin)
                                {
                                    AddNullRejectedTable(rowBufferEntry);
                                }
                            }
                        }
                    }
                }
            }

            // Visit children

            node.Left  = VisitAlgebraNode(node.Left);
            node.Right = VisitAlgebraNode(node.Right);

            return(node);
        }
Exemple #18
0
        private AlgebraNode PushOverJoin(FilterAlgebraNode node)
        {
            JoinAlgebraNode inputNode = (JoinAlgebraNode)node.Input;

            // Get declared tables of left and right

            RowBufferEntry[] leftDefinedValues  = AstUtil.GetDefinedValueEntries(inputNode.Left);
            RowBufferEntry[] rightDefinedValues = AstUtil.GetDefinedValueEntries(inputNode.Right);

            // Obviously, we cannot merge the filter with the join if the join is an outer join
            // (since it would change the join's semantics).
            //
            // Another less obvious restriction is that we cannot merge a filter with the join if
            // the join has a passthru predicate. In case the passthru predicte evaluates to true
            // the filter would not be applied. However, we are allowed to push the filter the over
            // join.

            bool canMerge = inputNode.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin &&
                            inputNode.Op != JoinAlgebraNode.JoinOperator.LeftOuterJoin &&
                            inputNode.Op != JoinAlgebraNode.JoinOperator.RightOuterJoin &&
                            inputNode.PassthruPredicate == null;

            if (canMerge)
            {
                // We can merge the filter with the condition of the join.
                //
                // However, we have to make sure that the predicate does not reference the probe column.
                // Since not having a probe column is the most common case, we don't always split the
                // predicate into conjuncts.

                if (inputNode.ProbeBufferEntry == null || !ArrayHelpers.Contains(AstUtil.GetRowBufferEntryReferences(node.Predicate), inputNode.ProbeBufferEntry))
                {
                    // Either there is no probe column defined or the filter does not reference it. That means
                    // no splitting necessary, we can just merge the whole predicate with the join predicate.
                    inputNode.Predicate = AstUtil.CombineConditions(LogicalOperator.And, inputNode.Predicate, node.Predicate);
                    return(VisitAlgebraNode(inputNode));
                }
                else
                {
                    // Unfortunately, the filter references the probe column. Now let's check whether we can merge
                    // conjuncts of the predicate.

                    List <ExpressionNode> remainingAndParts = new List <ExpressionNode>();
                    List <ExpressionNode> mergableAndParts  = new List <ExpressionNode>();

                    foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, node.Predicate))
                    {
                        bool andPartReferencesProbeColumn = ArrayHelpers.Contains(AstUtil.GetRowBufferEntryReferences(andPart), inputNode.ProbeBufferEntry);

                        if (andPartReferencesProbeColumn)
                        {
                            remainingAndParts.Add(andPart);
                        }
                        else
                        {
                            mergableAndParts.Add(andPart);
                        }
                    }

                    if (mergableAndParts.Count > 0)
                    {
                        ExpressionNode combinedMergableAndParts = AstUtil.CombineConditions(LogicalOperator.And, mergableAndParts.ToArray());
                        inputNode.Predicate = AstUtil.CombineConditions(LogicalOperator.And, inputNode.Predicate, combinedMergableAndParts);
                        node.Predicate      = AstUtil.CombineConditions(LogicalOperator.And, remainingAndParts);

                        if (node.Predicate == null)
                        {
                            return(VisitAlgebraNode(inputNode));
                        }
                    }
                }
            }
            else
            {
                // The condition cannot be merged. Now we try to push AND-parts over the join.

                List <ExpressionNode> leftAndParts      = new List <ExpressionNode>();
                List <ExpressionNode> rightAndParts     = new List <ExpressionNode>();
                List <ExpressionNode> remainingAndParts = new List <ExpressionNode>();

                foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, node.Predicate))
                {
                    bool andPartReferencesProbeColumn = inputNode.ProbeBufferEntry != null &&
                                                        ArrayHelpers.Contains(AstUtil.GetRowBufferEntryReferences(andPart), inputNode.ProbeBufferEntry);

                    if (!andPartReferencesProbeColumn && AstUtil.AllowsLeftPushOver(inputNode.Op) && AstUtil.ExpressionDoesNotReference(andPart, rightDefinedValues))
                    {
                        // The AND-part depends only on the LHS and the join is inner/left.
                        // So we are allowed to push this AND-part down.
                        leftAndParts.Add(andPart);
                    }
                    else if (!andPartReferencesProbeColumn && AstUtil.AllowsRightPushOver(inputNode.Op) && AstUtil.ExpressionDoesNotReference(andPart, leftDefinedValues))
                    {
                        // The AND-part depends only on the RHS and the join is inner/right.
                        // So we are allowed to push this AND-part down.
                        rightAndParts.Add(andPart);
                    }
                    else
                    {
                        remainingAndParts.Add(andPart);
                    }
                }

                if (leftAndParts.Count > 0)
                {
                    inputNode.Left = GetFilterFromAndParts(leftAndParts, inputNode.Left);
                }

                if (rightAndParts.Count > 0)
                {
                    inputNode.Right = GetFilterFromAndParts(rightAndParts, inputNode.Right);
                }

                node.Predicate = AstUtil.CombineConditions(LogicalOperator.And, remainingAndParts);
                if (node.Predicate == null)
                {
                    return(VisitAlgebraNode(inputNode));
                }
            }

            node.Input = VisitAlgebraNode(node.Input);
            return(node);
        }