Exemplo n.º 1
0
        // <summary>
        // Convert Filter(OuterApply(X,Y), p) into
        // Filter(CrossApply(X,Y), p)
        // if "p" is not null-preserving for Y (ie) "p" does not preserve null values from Y
        // </summary>
        // <param name="context"> Rule processing context </param>
        // <param name="filterNode"> Filter node </param>
        // <param name="newNode"> modified subtree </param>
        // <returns> transformation status </returns>
        private static bool ProcessFilterOverOuterApply(RuleProcessingContext context, Node filterNode, out Node newNode)
        {
            newNode = filterNode;
            var applyNode           = filterNode.Child0;
            var applyRightInputNode = applyNode.Child1;
            var trc     = (TransformationRulesContext)context;
            var command = trc.Command;

            //
            // Check to see if the current predicate preserves nulls for the right table.
            // If it doesn't then we can convert the outer apply into a cross-apply,
            //
            var rightTableNodeInfo = command.GetExtendedNodeInfo(applyRightInputNode);
            var predicate          = new Predicate(command, filterNode.Child1);

            if (!predicate.PreservesNulls(rightTableNodeInfo.Definitions, true))
            {
                // Allow the JoinElimination phase to eliminate redundant joins
                // and allow the NullSemantics phase to fully expand the filter
                // predicate before attempting to promote the OuterApply to CrossApply.
                if (trc.PlanCompiler.IsAfterPhase(PlanCompilerPhase.NullSemantics) &&
                    trc.PlanCompiler.IsAfterPhase(PlanCompilerPhase.JoinElimination))
                {
                    var newApplyNode  = command.CreateNode(command.CreateCrossApplyOp(), applyNode.Child0, applyRightInputNode);
                    var newFilterNode = command.CreateNode(command.CreateFilterOp(), newApplyNode, filterNode.Child1);
                    newNode = newFilterNode;
                    return(true);
                }

                trc.PlanCompiler.TransformationsDeferred = true;
            }

            return(false);
        }
        // <summary>
        // Convert Filter(OuterApply(X,Y), p) into
        // Filter(CrossApply(X,Y), p)
        // if "p" is not null-preserving for Y (ie) "p" does not preserve null values from Y
        // </summary>
        // <param name="context"> Rule processing context </param>
        // <param name="filterNode"> Filter node </param>
        // <param name="newNode"> modified subtree </param>
        // <returns> transformation status </returns>
        private static bool ProcessFilterOverOuterApply(RuleProcessingContext context, Node filterNode, out Node newNode)
        {
            newNode = filterNode;
            var applyNode           = filterNode.Child0;
            var applyOp             = applyNode.Op;
            var applyRightInputNode = applyNode.Child1;
            var trc     = (TransformationRulesContext)context;
            var command = trc.Command;

            //
            // Check to see if the current predicate preserves nulls for the right table.
            // If it doesn't then we can convert the outer apply into a cross-apply,
            //
            var rightTableNodeInfo = command.GetExtendedNodeInfo(applyRightInputNode);
            var predicate          = new Predicate(command, filterNode.Child1);

            if (!predicate.PreservesNulls(rightTableNodeInfo.Definitions, true))
            {
                var newApplyNode  = command.CreateNode(command.CreateCrossApplyOp(), applyNode.Child0, applyRightInputNode);
                var newFilterNode = command.CreateNode(command.CreateFilterOp(), newApplyNode, filterNode.Child1);
                newNode = newFilterNode;
                return(true);
            }

            return(false);
        }
Exemplo n.º 3
0
 internal bool PreservesNulls(VarVec tableColumns, bool ansiNullSemantics)
 {
     if (!ansiNullSemantics)
     {
         return(true);
     }
     foreach (System.Data.Entity.Core.Query.InternalTrees.Node part in this.m_parts)
     {
         if (!Predicate.PreservesNulls(part, tableColumns))
         {
             return(false);
         }
     }
     return(true);
 }
Exemplo n.º 4
0
        /// <summary>
        ///     Convert Filter(OuterApply(X,Y), p) into
        ///     Filter(CrossApply(X,Y), p)
        ///     if "p" is not null-preserving for Y (ie) "p" does not preserve null values from Y
        /// </summary>
        /// <param name="context"> Rule processing context </param>
        /// <param name="filterNode"> Filter node </param>
        /// <param name="newNode"> modified subtree </param>
        /// <returns> transformation status </returns>
        private static bool ProcessFilterOverOuterApply(RuleProcessingContext context, Node filterNode, out Node newNode)
        {
            newNode = filterNode;
            var applyNode = filterNode.Child0;
            var applyOp = applyNode.Op;
            var applyRightInputNode = applyNode.Child1;
            var trc = (TransformationRulesContext)context;
            var command = trc.Command;

            //
            // Check to see if the current predicate preserves nulls for the right table. 
            // If it doesn't then we can convert the outer apply into a cross-apply,
            // 
            var rightTableNodeInfo = command.GetExtendedNodeInfo(applyRightInputNode);
            var predicate = new Predicate(command, filterNode.Child1);
            if (!predicate.PreservesNulls(rightTableNodeInfo.Definitions, true))
            {
                var newApplyNode = command.CreateNode(command.CreateCrossApplyOp(), applyNode.Child0, applyRightInputNode);
                var newFilterNode = command.CreateNode(command.CreateFilterOp(), newApplyNode, filterNode.Child1);
                newNode = newFilterNode;
                return true;
            }

            return false;
        }
Exemplo n.º 5
0
        private static bool ProcessFilterOverJoin(RuleProcessingContext context, Node filterNode, out Node newNode)
        {
            newNode = filterNode;
            var trc = (TransformationRulesContext)context;

            //
            // Have we shut off filter pushdown for this node? Return
            //
            if (trc.IsFilterPushdownSuppressed(filterNode))
            {
                return false;
            }

            var joinNode = filterNode.Child0;
            var joinOp = joinNode.Op;
            var leftInputNode = joinNode.Child0;
            var rightInputNode = joinNode.Child1;
            var command = trc.Command;
            var needsTransformation = false;

            //
            // If we're dealing with an outer-join, first check to see if the current 
            // predicate preserves nulls for the right table. 
            // If it doesn't then we can convert the outer join into an inner join,
            // and then continue with the rest of our processing here
            // 
            var rightTableNodeInfo = command.GetExtendedNodeInfo(rightInputNode);
            var predicate = new Predicate(command, filterNode.Child1);
            if (joinOp.OpType
                == OpType.LeftOuterJoin)
            {
                if (!predicate.PreservesNulls(rightTableNodeInfo.Definitions, true))
                {
                    joinOp = command.CreateInnerJoinOp();
                    needsTransformation = true;
                }
            }
            var leftTableInfo = command.GetExtendedNodeInfo(leftInputNode);

            //
            // Check to see if the predicate contains any "single-table-filters". In those
            // cases, we could simply push that filter down to the child. 
            // We can do this for inner joins and cross joins - for both inputs.
            // For left-outer joins, however, we can only do this for the left-side input
            // Further note that we only want to do the pushdown if it will help us - if 
            // the join input is a ScanTable (or some other cases), then it doesn't help us.
            // 
            Node leftSingleTablePredicateNode = null;
            if (leftInputNode.Op.OpType
                != OpType.ScanTable)
            {
                var leftSingleTablePredicates = predicate.GetSingleTablePredicates(leftTableInfo.Definitions, out predicate);
                leftSingleTablePredicateNode = leftSingleTablePredicates.BuildAndTree();
            }

            Node rightSingleTablePredicateNode = null;
            if ((rightInputNode.Op.OpType != OpType.ScanTable)
                &&
                (joinOp.OpType != OpType.LeftOuterJoin))
            {
                var rightSingleTablePredicates = predicate.GetSingleTablePredicates(rightTableNodeInfo.Definitions, out predicate);
                rightSingleTablePredicateNode = rightSingleTablePredicates.BuildAndTree();
            }

            //
            // Now check to see if the predicate contains some "join predicates". We can
            // add these to the existing join predicate (if any). 
            // We can only do this for inner joins and cross joins - not for LOJs
            //
            Node newJoinPredicateNode = null;
            if (joinOp.OpType == OpType.CrossJoin
                || joinOp.OpType == OpType.InnerJoin)
            {
                var joinPredicate = predicate.GetJoinPredicates(leftTableInfo.Definitions, rightTableNodeInfo.Definitions, out predicate);
                newJoinPredicateNode = joinPredicate.BuildAndTree();
            }

            //
            // Now for the dirty work. We've identified some predicates that could be pushed
            // into the left table, some predicates that could be pushed into the right table
            // and some that could become join predicates. 
            // 
            if (leftSingleTablePredicateNode != null)
            {
                leftInputNode = command.CreateNode(command.CreateFilterOp(), leftInputNode, leftSingleTablePredicateNode);
                needsTransformation = true;
            }
            if (rightSingleTablePredicateNode != null)
            {
                rightInputNode = command.CreateNode(command.CreateFilterOp(), rightInputNode, rightSingleTablePredicateNode);
                needsTransformation = true;
            }

            // Identify the new join predicate
            if (newJoinPredicateNode != null)
            {
                needsTransformation = true;
                if (joinOp.OpType
                    == OpType.CrossJoin)
                {
                    joinOp = command.CreateInnerJoinOp();
                }
                else
                {
                    PlanCompiler.Assert(joinOp.OpType == OpType.InnerJoin, "unexpected non-InnerJoin?");
                    newJoinPredicateNode = PlanCompilerUtil.CombinePredicates(joinNode.Child2, newJoinPredicateNode, command);
                }
            }
            else
            {
                newJoinPredicateNode = (joinOp.OpType == OpType.CrossJoin) ? null : joinNode.Child2;
            }

            // 
            // If nothing has changed, then just return the current node. Otherwise, 
            // we will loop forever
            //
            if (!needsTransformation)
            {
                return false;
            }

            Node newJoinNode;
            // 
            // Finally build up a new join node
            // 
            if (joinOp.OpType
                == OpType.CrossJoin)
            {
                newJoinNode = command.CreateNode(joinOp, leftInputNode, rightInputNode);
            }
            else
            {
                newJoinNode = command.CreateNode(joinOp, leftInputNode, rightInputNode, newJoinPredicateNode);
            }

            //
            // Build up a new filterNode above this join node. But only if we have a filter left
            // 
            var newFilterPredicateNode = predicate.BuildAndTree();
            if (newFilterPredicateNode == null)
            {
                newNode = newJoinNode;
            }
            else
            {
                newNode = command.CreateNode(command.CreateFilterOp(), newJoinNode, newFilterPredicateNode);
            }
            return true;
        }
Exemplo n.º 6
0
        private static bool ProcessFilterOverJoin(RuleProcessingContext context, Node filterNode, out Node newNode)
        {
            newNode = filterNode;
            var trc = (TransformationRulesContext)context;

            //
            // Have we shut off filter pushdown for this node? Return
            //
            if (trc.IsFilterPushdownSuppressed(filterNode))
            {
                return(false);
            }

            var joinNode            = filterNode.Child0;
            var joinOp              = joinNode.Op;
            var leftInputNode       = joinNode.Child0;
            var rightInputNode      = joinNode.Child1;
            var command             = trc.Command;
            var needsTransformation = false;

            //
            // If we're dealing with an outer-join, first check to see if the current
            // predicate preserves nulls for the right table.
            // If it doesn't then we can convert the outer join into an inner join,
            // and then continue with the rest of our processing here
            //
            var rightTableNodeInfo = command.GetExtendedNodeInfo(rightInputNode);
            var predicate          = new Predicate(command, filterNode.Child1);

            if (joinOp.OpType
                == OpType.LeftOuterJoin)
            {
                if (!predicate.PreservesNulls(rightTableNodeInfo.Definitions, true))
                {
                    joinOp = command.CreateInnerJoinOp();
                    needsTransformation = true;
                }
            }
            var leftTableInfo = command.GetExtendedNodeInfo(leftInputNode);

            //
            // Check to see if the predicate contains any "single-table-filters". In those
            // cases, we could simply push that filter down to the child.
            // We can do this for inner joins and cross joins - for both inputs.
            // For left-outer joins, however, we can only do this for the left-side input
            // Further note that we only want to do the pushdown if it will help us - if
            // the join input is a ScanTable (or some other cases), then it doesn't help us.
            //
            Node leftSingleTablePredicateNode = null;

            if (leftInputNode.Op.OpType
                != OpType.ScanTable)
            {
                var leftSingleTablePredicates = predicate.GetSingleTablePredicates(leftTableInfo.Definitions, out predicate);
                leftSingleTablePredicateNode = leftSingleTablePredicates.BuildAndTree();
            }

            Node rightSingleTablePredicateNode = null;

            if ((rightInputNode.Op.OpType != OpType.ScanTable)
                &&
                (joinOp.OpType != OpType.LeftOuterJoin))
            {
                var rightSingleTablePredicates = predicate.GetSingleTablePredicates(rightTableNodeInfo.Definitions, out predicate);
                rightSingleTablePredicateNode = rightSingleTablePredicates.BuildAndTree();
            }

            //
            // Now check to see if the predicate contains some "join predicates". We can
            // add these to the existing join predicate (if any).
            // We can only do this for inner joins and cross joins - not for LOJs
            //
            Node newJoinPredicateNode = null;

            if (joinOp.OpType == OpType.CrossJoin ||
                joinOp.OpType == OpType.InnerJoin)
            {
                var joinPredicate = predicate.GetJoinPredicates(leftTableInfo.Definitions, rightTableNodeInfo.Definitions, out predicate);
                newJoinPredicateNode = joinPredicate.BuildAndTree();
            }

            //
            // Now for the dirty work. We've identified some predicates that could be pushed
            // into the left table, some predicates that could be pushed into the right table
            // and some that could become join predicates.
            //
            if (leftSingleTablePredicateNode != null)
            {
                leftInputNode       = command.CreateNode(command.CreateFilterOp(), leftInputNode, leftSingleTablePredicateNode);
                needsTransformation = true;
            }
            if (rightSingleTablePredicateNode != null)
            {
                rightInputNode      = command.CreateNode(command.CreateFilterOp(), rightInputNode, rightSingleTablePredicateNode);
                needsTransformation = true;
            }

            // Identify the new join predicate
            if (newJoinPredicateNode != null)
            {
                needsTransformation = true;
                if (joinOp.OpType
                    == OpType.CrossJoin)
                {
                    joinOp = command.CreateInnerJoinOp();
                }
                else
                {
                    PlanCompiler.Assert(joinOp.OpType == OpType.InnerJoin, "unexpected non-InnerJoin?");
                    newJoinPredicateNode = PlanCompilerUtil.CombinePredicates(joinNode.Child2, newJoinPredicateNode, command);
                }
            }
            else
            {
                newJoinPredicateNode = (joinOp.OpType == OpType.CrossJoin) ? null : joinNode.Child2;
            }

            //
            // If nothing has changed, then just return the current node. Otherwise,
            // we will loop forever
            //
            if (!needsTransformation)
            {
                return(false);
            }

            Node newJoinNode;

            //
            // Finally build up a new join node
            //
            if (joinOp.OpType
                == OpType.CrossJoin)
            {
                newJoinNode = command.CreateNode(joinOp, leftInputNode, rightInputNode);
            }
            else
            {
                newJoinNode = command.CreateNode(joinOp, leftInputNode, rightInputNode, newJoinPredicateNode);
            }

            //
            // Build up a new filterNode above this join node. But only if we have a filter left
            //
            var newFilterPredicateNode = predicate.BuildAndTree();

            if (newFilterPredicateNode == null)
            {
                newNode = newJoinNode;
            }
            else
            {
                newNode = command.CreateNode(command.CreateFilterOp(), newJoinNode, newFilterPredicateNode);
            }
            return(true);
        }
Exemplo n.º 7
0
        // <summary>
        // Convert Filter(OuterApply(X,Y), p) into
        // Filter(CrossApply(X,Y), p)
        // if "p" is not null-preserving for Y (ie) "p" does not preserve null values from Y
        // </summary>
        // <param name="context"> Rule processing context </param>
        // <param name="filterNode"> Filter node </param>
        // <param name="newNode"> modified subtree </param>
        // <returns> transformation status </returns>
        private static bool ProcessFilterOverOuterApply(RuleProcessingContext context, Node filterNode, out Node newNode)
        {
            newNode = filterNode;
            var applyNode = filterNode.Child0;
            var applyRightInputNode = applyNode.Child1;
            var trc = (TransformationRulesContext)context;
            var command = trc.Command;

            //
            // Check to see if the current predicate preserves nulls for the right table. 
            // If it doesn't then we can convert the outer apply into a cross-apply,
            // 
            var rightTableNodeInfo = command.GetExtendedNodeInfo(applyRightInputNode);
            var predicate = new Predicate(command, filterNode.Child1);
            if (!predicate.PreservesNulls(rightTableNodeInfo.Definitions, true))
            {
                // Allow the JoinElimination phase to eliminate redundant joins
                // and allow the NullSemantics phase to fully expand the filter 
                // predicate before attempting to promote the OuterApply to CrossApply.
                if (trc.PlanCompiler.IsAfterPhase(PlanCompilerPhase.NullSemantics)
                    && trc.PlanCompiler.IsAfterPhase(PlanCompilerPhase.JoinElimination))
                {
                    var newApplyNode = command.CreateNode(command.CreateCrossApplyOp(), applyNode.Child0, applyRightInputNode);
                    var newFilterNode = command.CreateNode(command.CreateFilterOp(), newApplyNode, filterNode.Child1);
                    newNode = newFilterNode;
                    return true;
                }

                trc.PlanCompiler.TransformationsDeferred = true;
            }

            return false;
        }