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); }