1 //---------------------------------------------------------------------
2 // <copyright file="PlanCompilerUtil.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
11 using System.Collections.Generic;
12 using System.Data.Common.Utils;
13 using System.Data.Metadata.Edm;
14 using System.Data.Query.InternalTrees;
16 namespace System.Data.Query.PlanCompiler
19 /// Utility class for the methods shared among the classes comprising the plan compiler
21 internal static class PlanCompilerUtil
24 /// Utility method that determines whether a given CaseOp subtree can be optimized.
25 /// Called by both PreProcessor and NominalTypeEliminator.
27 /// If the case statement is of the shape:
28 /// case when X then NULL else Y, or
29 /// case when X then Y else NULL,
30 /// where Y is of row type, and the types of the input CaseOp, the NULL and Y are the same,
33 /// <param name="op"></param>
34 /// <param name="n"></param>
35 /// <returns></returns>
36 internal static bool IsRowTypeCaseOpWithNullability(CaseOp op, Node n, out bool thenClauseIsNull)
38 thenClauseIsNull = false; //any default value will do
40 if (!TypeSemantics.IsRowType(op.Type))
44 if (n.Children.Count != 3)
49 //All three types must be equal
50 if (!n.Child1.Op.Type.EdmEquals(op.Type) || !n.Child2.Op.Type.EdmEquals(op.Type))
55 //At least one of Child1 and Child2 needs to be a null
56 if (n.Child1.Op.OpType == OpType.Null)
58 thenClauseIsNull = true;
61 if (n.Child2.Op.OpType == OpType.Null)
63 // thenClauseIsNull stays false
71 /// Is this function a collection aggregate function. It is, if
72 /// - it has exactly one child
73 /// - that child is a collection type
74 /// - and the function has been marked with the aggregate attribute
76 /// <param name="op">the function op</param>
77 /// <param name="n">the current subtree</param>
78 /// <returns>true, if this was a collection aggregate function</returns>
79 internal static bool IsCollectionAggregateFunction(FunctionOp op, Node n)
81 return ((n.Children.Count == 1) &&
82 TypeSemantics.IsCollectionType(n.Child0.Op.Type) &&
83 TypeSemantics.IsAggregateFunction(op.Function));
87 /// Is the given op one of the ConstantBaseOp-s
89 /// <param name="opType"></param>
90 /// <returns></returns>
91 internal static bool IsConstantBaseOp(OpType opType)
93 return opType == OpType.Constant ||
94 opType == OpType.InternalConstant ||
95 opType == OpType.Null ||
96 opType == OpType.NullSentinel;
100 /// Combine two predicates by trying to avoid the predicate parts of the
101 /// second one that are already present in the first one.
103 /// In particular, given two nodes, predicate1 and predicate2,
104 /// it creates a combined predicate logically equivalent to
105 /// predicate1 AND predicate2,
106 /// but it does not include any AND parts of predicate2 that are present
109 /// <param name="predicate1"></param>
110 /// <param name="predicate2"></param>
111 /// <param name="command"></param>
112 /// <returns></returns>
113 internal static Node CombinePredicates(Node predicate1, Node predicate2, Command command)
115 IEnumerable<Node> andParts1 = BreakIntoAndParts(predicate1);
116 IEnumerable<Node> andParts2 = BreakIntoAndParts(predicate2);
118 Node result = predicate1;
120 foreach (Node predicatePart2 in andParts2)
122 bool foundMatch = false;
123 foreach (Node predicatePart1 in andParts1)
125 if (predicatePart1.IsEquivalent(predicatePart2))
133 result = command.CreateNode(command.CreateConditionalOp(OpType.And), result, predicatePart2);
140 /// Create a list of AND parts for a given predicate.
141 /// For example, if the predicate is of the shape:
142 /// ((p1 and p2) and (p3 and p4)) the list is p1, p2, p3, p4
143 /// The predicates p1,p2, p3, p4 may be roots of subtrees that
144 /// have nodes with AND ops, but
145 /// would not be broken unless they are the AND nodes themselves.
147 /// <param name="predicate"></param>
148 /// <param name="andParts"></param>
149 private static IEnumerable<Node> BreakIntoAndParts(Node predicate)
151 return Helpers.GetLeafNodes<Node>(predicate,
152 node => (node.Op.OpType != OpType.And),
153 node => (new[] {node.Child0, node.Child1}));