1 //---------------------------------------------------------------------
2 // <copyright file="FragmentQuery.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 //---------------------------------------------------------------------
11 using System.Diagnostics;
12 using System.Collections.Generic;
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;
19 using System.Globalization;
21 namespace System.Data.Mapping.ViewGeneration.QueryRewriting
23 internal class FragmentQuery : ITileQuery
25 private BoolExpression m_fromVariable; // optional
26 private string m_label; // optional
28 private HashSet<MemberPath> m_attributes;
29 private BoolExpression m_condition;
31 public HashSet<MemberPath> Attributes
33 get { return m_attributes; }
36 public BoolExpression Condition
38 get { return m_condition; }
41 public static FragmentQuery Create(BoolExpression fromVariable, CellQuery cellQuery)
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);
49 public static FragmentQuery Create(string label, RoleBoolean roleBoolean, CellQuery cellQuery)
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);
60 public static FragmentQuery Create(IEnumerable<MemberPath> attrs, BoolExpression whereClause)
62 return new FragmentQuery(null /* no name */, null /* no fromVariable*/, attrs, whereClause);
65 public static FragmentQuery Create(BoolExpression whereClause)
67 return new FragmentQuery(null /* no name */, null /* no fromVariable*/, new MemberPath[] { }, whereClause);
70 internal FragmentQuery(string label, BoolExpression fromVariable, IEnumerable<MemberPath> attrs, BoolExpression condition)
73 m_fromVariable = fromVariable;
74 m_condition = condition;
75 m_attributes = new HashSet<MemberPath>(attrs);
78 public BoolExpression FromVariable
80 get { return m_fromVariable; }
83 public string Description
87 string label = m_label;
88 if (label == null && m_fromVariable != null)
90 label = m_fromVariable.ToString();
96 public override string ToString()
99 StringBuilder b = new StringBuilder();
100 foreach (MemberPath value in this.Attributes)
102 if (b.Length > 0) { b.Append(','); }
103 b.Append(value.ToString());
106 if (Description != null && Description != b.ToString())
108 return String.Format(CultureInfo.InvariantCulture, "{0}: [{1} where {2}]", Description, b, this.Condition);
112 return String.Format(CultureInfo.InvariantCulture, "[{0} where {1}]", b, this.Condition);
116 #region Static methods
118 // creates a condition member=value
119 internal static BoolExpression CreateMemberCondition(MemberPath path, Constant domainValue, MemberDomainMap domainMap)
121 if (domainValue is TypeConstant)
123 return BoolExpression.CreateLiteral(new TypeRestriction(new MemberProjectedSlot(path),
124 new Domain(domainValue, domainMap.GetDomain(path))), domainMap);
128 return BoolExpression.CreateLiteral(new ScalarRestriction(new MemberProjectedSlot(path),
129 new Domain(domainValue, domainMap.GetDomain(path))), domainMap);
133 internal static IEqualityComparer<FragmentQuery> GetEqualityComparer(FragmentQueryProcessor qp)
135 return new FragmentQueryEqualityComparer(qp);
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>
145 FragmentQueryProcessor _qp;
147 internal FragmentQueryEqualityComparer(FragmentQueryProcessor qp)
152 #region IEqualityComparer<FragmentQuery> Members
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)
157 if (!x.Attributes.SetEquals(y.Attributes))
161 return _qp.IsEquivalentTo(x, y);
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)
169 int attrHashCode = 0;
170 foreach (MemberPath member in q.Attributes)
172 attrHashCode ^= MemberPath.EqualityComparer.GetHashCode(member);
175 int constHashCode = 0;
176 foreach (MemberRestriction oneOf in q.Condition.MemberRestrictions)
178 varHashCode ^= MemberPath.EqualityComparer.GetHashCode(oneOf.RestrictedMemberSlot.MemberPath);
179 foreach (Constant constant in oneOf.Domain.Values)
181 constHashCode ^= Constant.EqualityComparer.GetHashCode(constant);
184 return attrHashCode * 13 + varHashCode * 7 + constHashCode;