Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Mapping / ViewGeneration / QueryRewriting / FragmentQuery.cs
1 //---------------------------------------------------------------------
2 // <copyright file="FragmentQuery.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner [....]
7 // @backupOwner [....]
8 //---------------------------------------------------------------------
9
10 using System;
11 using System.Diagnostics;
12 using System.Collections.Generic;
13 using System.Text;
14 using System.Data.Common.Utils;
15 using System.Data.Common.Utils.Boolean;
16 using System.Data.Mapping.ViewGeneration.Structures;
17 using System.Data.Metadata.Edm;
18 using System.Linq;
19 using System.Globalization;
20
21 namespace System.Data.Mapping.ViewGeneration.QueryRewriting
22 {
23     internal class FragmentQuery : ITileQuery
24     {
25         private BoolExpression m_fromVariable; // optional
26         private string m_label; // optional
27
28         private HashSet<MemberPath> m_attributes;
29         private BoolExpression m_condition;
30
31         public HashSet<MemberPath> Attributes
32         {
33             get { return m_attributes; }
34         }
35
36         public BoolExpression Condition
37         {
38             get { return m_condition; }
39         }
40
41         public static FragmentQuery Create(BoolExpression fromVariable, CellQuery cellQuery)
42         {
43             BoolExpression whereClause = cellQuery.WhereClause;
44             whereClause = whereClause.MakeCopy();
45             whereClause.ExpensiveSimplify();
46             return new FragmentQuery(null /*label*/, fromVariable, new HashSet<MemberPath>(cellQuery.GetProjectedMembers()), whereClause);
47         }
48
49         public static FragmentQuery Create(string label, RoleBoolean roleBoolean, CellQuery cellQuery)
50         {
51             BoolExpression whereClause = cellQuery.WhereClause.Create(roleBoolean);
52             whereClause = BoolExpression.CreateAnd(whereClause, cellQuery.WhereClause);
53             //return new FragmentQuery(label, null /* fromVariable */, new HashSet<MemberPath>(cellQuery.GetProjectedMembers()), whereClause);
54             // don't need any attributes 
55             whereClause = whereClause.MakeCopy();
56             whereClause.ExpensiveSimplify();
57             return new FragmentQuery(label, null /* fromVariable */, new HashSet<MemberPath>(), whereClause);
58         }
59
60         public static FragmentQuery Create(IEnumerable<MemberPath> attrs, BoolExpression whereClause)
61         {
62             return new FragmentQuery(null /* no name */, null /* no fromVariable*/, attrs, whereClause);
63         }
64
65         public static FragmentQuery Create(BoolExpression whereClause)
66         {
67             return new FragmentQuery(null /* no name */, null /* no fromVariable*/, new MemberPath[] { }, whereClause);
68         }
69
70         internal FragmentQuery(string label, BoolExpression fromVariable, IEnumerable<MemberPath> attrs, BoolExpression condition)
71         {
72             m_label = label;
73             m_fromVariable = fromVariable;
74             m_condition = condition;
75             m_attributes = new HashSet<MemberPath>(attrs);
76         }
77
78         public BoolExpression FromVariable
79         {
80             get { return m_fromVariable; }
81         }
82
83         public string Description
84         {
85             get
86             {
87                 string label = m_label;
88                 if (label == null && m_fromVariable != null)
89                 {
90                     label = m_fromVariable.ToString();
91                 }
92                 return label;
93             }
94         }
95
96         public override string ToString()
97         {
98             // attributes
99             StringBuilder b = new StringBuilder();
100             foreach (MemberPath value in this.Attributes)
101             {
102                 if (b.Length > 0) { b.Append(','); }
103                 b.Append(value.ToString());
104             }
105
106             if (Description != null && Description != b.ToString())
107             {
108                 return String.Format(CultureInfo.InvariantCulture, "{0}: [{1} where {2}]", Description, b, this.Condition);
109             }
110             else
111             {
112                 return String.Format(CultureInfo.InvariantCulture, "[{0} where {1}]", b, this.Condition);
113             }
114         }
115
116         #region Static methods
117
118         // creates a condition member=value
119         internal static BoolExpression CreateMemberCondition(MemberPath path, Constant domainValue, MemberDomainMap domainMap)
120         {
121             if (domainValue is TypeConstant)
122             {
123                 return BoolExpression.CreateLiteral(new TypeRestriction(new MemberProjectedSlot(path),
124                                                     new Domain(domainValue, domainMap.GetDomain(path))), domainMap);
125             }
126             else
127             {
128                 return BoolExpression.CreateLiteral(new ScalarRestriction(new MemberProjectedSlot(path),
129                                                     new Domain(domainValue, domainMap.GetDomain(path))), domainMap);
130             }
131         }
132
133         internal static IEqualityComparer<FragmentQuery> GetEqualityComparer(FragmentQueryProcessor qp)
134         {
135             return new FragmentQueryEqualityComparer(qp);
136         }
137
138         #endregion
139
140         #region Equality Comparer
141         // Two queries are "equal" if they project the same set of attributes
142         // and their WHERE clauses are equivalent
143         private class FragmentQueryEqualityComparer : IEqualityComparer<FragmentQuery>
144         {
145             FragmentQueryProcessor _qp;
146
147             internal FragmentQueryEqualityComparer(FragmentQueryProcessor qp)
148             {
149                 _qp = qp;
150             }
151
152             #region IEqualityComparer<FragmentQuery> Members
153
154             [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2140:TransparentMethodsMustNotReferenceCriticalCode", Justification = "Based on Bug VSTS Pioneer #433188: IsVisibleOutsideAssembly is wrong on generic instantiations.")]       
155             public bool Equals(FragmentQuery x, FragmentQuery y)
156             {
157                 if (!x.Attributes.SetEquals(y.Attributes))
158                 {
159                     return false;
160                 }
161                 return _qp.IsEquivalentTo(x, y);
162             }
163
164             // Hashing a bit naive: it exploits syntactic properties,
165             // i.e., some semantically equivalent queries may produce different hash codes
166             // But that's fine for usage scenarios in QueryRewriter.cs 
167             public int GetHashCode(FragmentQuery q)
168             {
169                 int attrHashCode = 0;
170                 foreach (MemberPath member in q.Attributes)
171                 {
172                     attrHashCode ^= MemberPath.EqualityComparer.GetHashCode(member);
173                 }
174                 int varHashCode = 0;
175                 int constHashCode = 0;
176                 foreach (MemberRestriction oneOf in q.Condition.MemberRestrictions)
177                 {
178                     varHashCode ^= MemberPath.EqualityComparer.GetHashCode(oneOf.RestrictedMemberSlot.MemberPath);
179                     foreach (Constant constant in oneOf.Domain.Values)
180                     {
181                         constHashCode ^= Constant.EqualityComparer.GetHashCode(constant);
182                     }
183                 }
184                 return attrHashCode * 13 + varHashCode * 7 + constHashCode;
185             }
186
187             #endregion
188         }
189         #endregion
190
191     }
192
193 }