src/Shared/EntityFramework/Core/Query/PlanCompiler/SetOpRules.cs
// <summary>
// Process a SetOp when one of the inputs is an emptyset.
// An emptyset is represented by a Filter(X, ConstantPredicate)
// where the ConstantPredicate has a value of "false"
// The general rules are
// UnionAll(X, EmptySet) => X
// UnionAll(EmptySet, X) => X
// Intersect(EmptySet, X) => EmptySet
// Intersect(X, EmptySet) => EmptySet
// Except(EmptySet, X) => EmptySet
// Except(X, EmptySet) => X
// These rules then translate into
// UnionAll: return the non-empty input
// Intersect: return the empty input
// Except: return the "left" input
// </summary>
// <param name="context"> Rule processing context </param>
// <param name="setOpNode"> the current setop tree </param>
// <param name="newNode"> transformed subtree </param>
// <returns> transformation status </returns>
Process a SetOp when one of the inputs is an emptyset.
Process a SetOp when one of the inputs is an emptyset .
private static bool ProcessSetOpOverEmptySet(RuleProcessingContext context, Node setOpNode, out Node newNode)
        {
            var leftChildIsEmptySet = context.Command.GetExtendedNodeInfo(setOpNode.Child0).MaxRows == RowCount.Zero;
            var rightChildIsEmptySet = context.Command.GetExtendedNodeInfo(setOpNode.Child1).MaxRows == RowCount.Zero;
            if (!leftChildIsEmptySet
                && !rightChildIsEmptySet)
            {
                newNode = setOpNode;
                return false;
            }
            int indexToReturn;
            var setOp = (SetOp)setOpNode.Op;
            if (!rightChildIsEmptySet && setOp.OpType == OpType.UnionAll
                ||
                !leftChildIsEmptySet && setOp.OpType == OpType.Intersect)
            {
                indexToReturn = 1;
            }
            else
            {
                indexToReturn = 0;
            }
            newNode = setOpNode.Children[indexToReturn];
            var trc = (TransformationRulesContext)context;
            foreach (var kv in setOp.VarMap[indexToReturn])
            {
                trc.AddVarMapping(kv.Key, kv.Value);
            }
            return true;
        }
private static bool ProcessSetOpOverEmptySet ( RuleProcessingContext context , Node setOpNode , out Node newNode ) { var leftChildIsEmptySet = context . Command . GetExtendedNodeInfo ( setOpNode . Child0 ) . MaxRows == RowCount . Zero ; var rightChildIsEmptySet = context . Command . GetExtendedNodeInfo ( setOpNode . Child1 ) . MaxRows == RowCount . Zero ; if ( ! leftChildIsEmptySet && ! rightChildIsEmptySet ) { newNode = setOpNode ; return false ; } int indexToReturn ; var setOp = ( SetOp ) setOpNode . Op ; if ( ! rightChildIsEmptySet && setOp . OpType == OpType . UnionAll || ! leftChildIsEmptySet && setOp . OpType == OpType . Intersect ) { indexToReturn = 1 ; } else { indexToReturn = 0 ; } newNode = setOpNode . Children [ indexToReturn ] ; var trc = ( TransformationRulesContext ) context ; foreach ( var kv in setOp . VarMap [ indexToReturn ] ) { trc . AddVarMapping ( kv . Key , kv . Value ) ; } return true ; }
Process a SetOp when one of the inputs is an emptyset.
Process a SetOp when one of the inputs is an emptyset .
None
context
RuleProcessingContext
Rule processing context
Rule processing context
setOpNode
Node
the current setop tree
the current setop tree
Node
out
newNode
None