Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / Map / ViewGeneration / Structures / CellConstantDomain.cs / 2 / CellConstantDomain.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Data.Common.Utils; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Data.Metadata.Edm; using System.Data.Mapping.ViewGeneration.Utils; using System.Linq; namespace System.Data.Mapping.ViewGeneration.Structures { using CellConstantSet = Set; using CellConstantRWSet = Set ; using System.Data.Entity; // A set of cell constants -- to keep track of a cell constant's domain // values. It encapsulates the notions of NULL, NOT NULL and can be // enhanced in the future with more functionality // To represent "infinite" domains such as integer, a special constant CellConstant.NotNull is used. // For example: domain of System.Boolean is {true, false}, domain of // (nullable) System.Int32 property is {Null, NotNull}. internal class CellConstantDomain : InternalBase { #region Constructors // effects: Creates an "fully-done" set with no values -- possibleDiscreteValues are the values // that this domain can take internal CellConstantDomain(CellConstant value, IEnumerable possibleDiscreteValues) : this(new CellConstant[] {value}, possibleDiscreteValues) { } // effects: Creates a domain populated using values -- possibleValues // are all possible values that this can take internal CellConstantDomain(IEnumerable values, IEnumerable possibleDiscreteValues) { // Note that the values can contain both null and not null Debug.Assert(values != null); Debug.Assert(possibleDiscreteValues != null); // Determine the possibleValues first and then create the negatedConstant m_possibleValues = DeterminePossibleValues(values, possibleDiscreteValues); // Now we need to make sure that m_domain is correct. if "values" (v) already has // the negated stuff, we need to make sure it is in conformance // with what m_possibleValues (p) has // For NOT --> Add all constants into d that are present in p but // not in the NOT // v = 1, NOT(1, 2); p = 1, 2, 3 => d = 1, NOT(1, 2, 3), 3 // v = 1, 2, NOT(1); p = 1, 2, 4 => d = 1, 2, 4, NOT(1, 2, 4) // v = 1, 2, NOT(1, 2, 4), NOT(1, 2, 4, 5); p = 1, 2, 4, 5, 6 => // d = 1, 2, 5, 6, NOT(1, 2, 4, 5, 6) // NotNull works naturally now. If possibleValues has (1, 2, // NULL) and values has NOT(NULL), add 1, 2 to m_domain m_domain = NormalizeDomain(values, m_possibleValues); Debug.Assert(CheckRepInvariantLocal()); } // effects: Creates a copy of the set "domain" internal CellConstantDomain(CellConstantDomain domain) { m_domain = new Set (domain.m_domain, CellConstant.EqualityComparer); m_possibleValues = new Set (domain.m_possibleValues, CellConstant.EqualityComparer); Debug.Assert(CheckRepInvariantLocal()); } #endregion #region Fields // The set of values in the cell constant domain private CellConstantSet m_domain; // e.g., 1, 2, NULL, NOT(1, 2, NULL) private CellConstantSet m_possibleValues; // e.g., 1, 2, NULL, Undefined // Invariant: m_domain is a subset of m_possibleValues except for a // negated constant #endregion #region Properties // effects: Returns all the possible values that this can contain (including the negated constants) internal IEnumerable AllPossibleValues { get { return AllPossibleValuesInternal;} } // effects: Returns all the possible values that this can contain (including the negated constants) private Set AllPossibleValuesInternal { get { NegatedCellConstant negatedPossibleValue = new NegatedCellConstant(m_possibleValues); return m_possibleValues.Union(new CellConstant[] { negatedPossibleValue }); } } // effects: Returns the number of constants in this (including a negated constant) internal int Count { get { return m_domain.Count;} } // effects: Yields all the values in this internal IEnumerable Values { get { return m_domain;} } #endregion #region Static Helper Methods to create cell constant sets from metadata // effects: Given a member, determines all possible values that can be created from Metadata internal static CellConstantSet CreateDomainSetFromMemberPath(MemberPath memberPath, MetadataWorkspace workspace) { CellConstantSet domain = CreateDomainFromType(memberPath.EdmType, workspace); if (memberPath.IsNullable) { domain.Add(CellConstant.Null); } return domain; } // effects: Given a slot, determines all possible values that can be created from Metadata private static CellConstantSet CreateDomainSetFromSlot(JoinTreeSlot slot, MetadataWorkspace workspace) { CellConstantSet domain = CreateDomainSetFromMemberPath(slot.MemberPath, workspace); return domain; } // effects: Given a type, determines all possible values that can be created from Metadata private static CellConstantSet CreateDomainFromType(EdmType type, MetadataWorkspace workspace) { CellConstantSet domain = null; PrimitiveType scalarType = type as PrimitiveType; EnumType enumType = type as EnumType; if (scalarType != null) { // Get the domain for scalars -- for booleans, we special case. if (scalarType.PrimitiveTypeKind == PrimitiveTypeKind.Boolean) { domain = new Set (CreateList(true, false), CellConstant.EqualityComparer); } else { // Unbounded domain -- null is added by caller if the // property of this type is nullable domain = new Set (CellConstant.EqualityComparer); domain.Add(CellConstant.NotNull); } } else if (enumType != null) { // Get all the values for the enumeration domain = GetEnumeratedDomain(enumType); } else { Debug.Assert(Helper.IsEntityType(type) || Helper.IsComplexType(type) || Helper.IsRefType(type) || Helper.IsAssociationType(type)); // Treat ref types as their referenced entity types if (Helper.IsRefType(type)) { type = ((RefType)type).ElementType; } List types = new List (); foreach (EdmType derivedType in MetadataHelper.GetTypeAndSubtypesOf(type, workspace, false /*includeAbstractTypes*/)) { TypeConstant derivedTypeConstant = new TypeConstant(derivedType); types.Add(derivedTypeConstant); } domain = new Set (types, CellConstant.EqualityComparer); } Debug.Assert(domain != null, "Domain not set up for some type"); return domain; } // effect: returns the default value for the member // if the member is nullable and has no default, changes default value to CellConstant.NULL and returns true // if the mebmer is not nullable and has no default, returns false // CHANGE_[....]_FEATURE_DEFAULT_VALUES: return the right default once metadata supports it internal static bool TryGetDefaultValueForMemberPath(MemberPath memberPath, out CellConstant defaultConstant) { object defaultValue = memberPath.DefaultValue; defaultConstant = CellConstant.Null; if (defaultValue != null) { defaultConstant = new ScalarConstant(defaultValue); return true; } else if (memberPath.IsNullable || memberPath.IsComputed) { return true; } return false; } internal static CellConstant GetDefaultValueForMemberPath(MemberPath memberPath, IEnumerable wrappersForErrorReporting, ConfigViewGenerator config) { CellConstant defaultValue = null; if (!CellConstantDomain.TryGetDefaultValueForMemberPath(memberPath, out defaultValue)) { string message = Strings.ViewGen_No_Default_Value_1( memberPath.Extent.Name, memberPath.PathToString(false)); ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.NoDefaultValue, message, wrappersForErrorReporting, String.Empty); ExceptionHelpers.ThrowMappingException(record, config); } return defaultValue; } // effects: Given an enumeration type, enumType, returns the set of // values that enumType can take private static CellConstantSet GetEnumeratedDomain(EnumType enumType) { Set values = new Set (CellConstant.EqualityComparer); foreach (EnumMember enumerationValue in enumType.EnumMembers) { values.Add(new ScalarConstant(enumerationValue)); } return values; } #endregion #region External methods internal int GetHash() { int result = 0; foreach (CellConstant constant in m_domain) { result ^= CellConstant.EqualityComparer.GetHashCode(constant); } return result; } // effects: Returns true iff this domain has the same values as // second. Note that this method performs a semantic check not just // an element by element check internal bool IsEqualTo(CellConstantDomain second) { return m_domain.SetEquals(second.m_domain); } // requires: this is fully done // effects: Returns true iff this contains NOT(NULL OR ....) internal bool ContainsNotNull() { NegatedCellConstant negated = GetNegatedConstant(m_domain); return negated != null && negated.Contains(CellConstant.Null); } /// /// Returns true if the domain contains the given Cell Constant /// internal bool Contains(CellConstant constant) { return m_domain.Contains(constant); } internal override bool CheckRepInvariant() { return CheckRepInvariantLocal(); } // effects: Given a set of values in domain, "normalizes" it, i.e., // all positive constants are seperated out and any negative constant // is changed s.t. it is the negative of all positive values // extraValues indicates more constants that domain could take, e.g., // domain could be "1, 2, NOT(1, 2)", extraValues could be "3". In // this case, we return "1, 2, NOT(1, 2, 3)" internal static CellConstantSet NormalizeDomain(IEnumerabledomain, IEnumerable extraValues) { CellConstantSet possibleValues = DeterminePossibleValues(domain, extraValues); // For NOT --> Add all constants into d that are present in p but // not in the NOT // v = 1, NOT(1, 2); p = 1, 2, 3 => d = 1, NOT(1, 2, 3), 3 // v = 1, 2, NOT(1); p = 1, 2, 4 => d = 1, 2, 4, NOT(1, 2, 4) // v = 1, 2, NOT(1, 2, 4), NOT(1, 2, 4, 5); p = 1, 2, 4, 5, 6 => d = 1, 2, 5, 6, NOT(1, 2, 4, 5, 6) // NotNull works naturally now. If possibleValues has (1, 2, NULL) // and values has NOT(NULL), add 1, 2 to m_domain CellConstantSet result = new Set (CellConstant.EqualityComparer); foreach (CellConstant constant in domain) { NegatedCellConstant negated = constant as NegatedCellConstant; if (negated != null) { result.Add(new NegatedCellConstant(possibleValues)); // Compute all elements in possibleValues that are not present in negated. E.g., if // negated is NOT(1, 2, 3) and possibleValues is 1, 2, 3, // 4, we need to add 4 to result CellConstantSet remainingElements = possibleValues.Difference(negated.Elements); result.AddRange(remainingElements); } else { result.Add(constant); } } return result; } // effects: Given a set of values in domain // Returns all possible values that are present in domain. If // addNegatedIfPresent is true, the negated of all possible values is // added if a negated value is present static CellConstantSet DeterminePossibleValues(IEnumerable domain, bool addNegatedIfPresent) { // E.g., if we have 1, 2, NOT(1) --> Result = 1, 2 // 1, NOT(1, 2) --> Result = 1, 2 // 1, 2, NOT(NULL) --> Result = 1, 2, NULL // 1, 2, NOT(2), NOT(3, 4) --> Result = 1, 2, 3, 4 CellConstantSet result = new CellConstantRWSet(CellConstant.EqualityComparer); bool hasNegated = false; foreach (CellConstant constant in domain) { NegatedCellConstant negated = constant as NegatedCellConstant; if (negated != null) { hasNegated = true; // Go through all the constants in negated and add them to domain // We add them to possible values also even if (say) Null is not // allowed because we want the complete partitioning of // the space, e.g., if the values specified by the // caller are 1, NotNull -> we want 1, Null, Not(1, // Null) we can represent Not-Null as 1 + Not(1, NotNull) foreach (CellConstant constElement in negated.Elements) { Debug.Assert(constElement as NegatedCellConstant == null, "Negated cell constant inside NegatedCellConstant"); result.Add(constElement); } } else { result.Add(constant); } } if (hasNegated && addNegatedIfPresent) { NegatedCellConstant negatedValue = new NegatedCellConstant(result); result.Add(negatedValue); } return result; } #endregion #region Helper methods for determining domains from cells // effects: Given a set of cells, returns all the different values // that each memberPath in cells can take internal static Dictionary ComputeConstantDomainSetsForSlotsInQueryViews(IEnumerable cells, MetadataWorkspace workspace) { Dictionary | cDomainMap = new Dictionary (MemberPath.EqualityComparer); foreach (Cell cell in cells) { CellQuery cQuery = cell.CQuery; // Go through the conjuncts to get the constants (e.g., we // just don't want to NULL, NOT(NULL). We want to say that // the possible values are NULL, 4, NOT(NULL, 4) foreach (OneOfConst oneOfConst in cQuery.GetConjunctsFromWhereClause()) { JoinTreeSlot slot = oneOfConst.Slot; CellConstantSet cDomain = CreateDomainSetFromSlot(slot, workspace); // Now we add the domain of oneConst into this //Isnull=true and Isnull=false conditions should not contribute to a member's domain cDomain.AddRange(oneOfConst.Values.Values.Where(c=> !(c.Equals(CellConstant.Null)||c.Equals(CellConstant.NotNull)))); CellConstantSet values; bool found = cDomainMap.TryGetValue(slot.MemberPath, out values); if (!found) { cDomainMap[slot.MemberPath] = cDomain; } else { values.AddRange(cDomain); } } } return cDomainMap; } // effects: returns a dictionary that maps each S-side slot whose domain can be restricted to such an enumerated domain // The resulting domain is a union of // (a) constants appearing in conditions on that slot on S-side // (b) constants appearing in conditions on the respective slot on C-side, if the given slot // is projected (on the C-side) and no conditions are placed on it on S-side // (c) default value of the slot based on metadata internal static Dictionary ComputeConstantDomainSetsForSlotsInUpdateViews(IEnumerable cells, MetadataWorkspace workspace) { Dictionary | sDomainMap = new Dictionary (MemberPath.EqualityComparer); foreach (Cell cell in cells) { CellQuery cQuery = cell.CQuery; CellQuery sQuery = cell.SQuery; foreach (JoinTreeSlot sSlot in sQuery.GetAllQuerySlots()) { // obtain initial slot domain and restrict it if the slot has conditions CellConstantSet sDomain = CreateDomainSetFromSlot(sSlot, workspace); CellConstantSet restrictedDomain = RestrictDomainByWhereClause(sDomain, sSlot, sQuery); // Suppose that we have a cell: Proj(ID, A) Select(A=5)(E) == T(ID, B) // In the above cell, B on the S-side is 5 and we add // that to its range. But if B had a restriction, we do // not add 5. Note that do we not have a problem // w.r.t. possibleValues since if A=5 and B=1, we have an // empty cell -- we should catch that as an error. If A = 5 // and B = 5 is present then restrictedDomain and sDomain // are the same // if no restriction on the S-side and the slot is projected then take the domain from the C-side if (restrictedDomain.SetEquals(sDomain)) { int projectedPosition = sQuery.GetProjectedPosition(sSlot); if (projectedPosition >= 0) { // get the domain of the respective C-side slot JoinTreeSlot cSlot = cQuery.ProjectedSlotAt(projectedPosition) as JoinTreeSlot; Debug.Assert(cSlot != null, "Assuming constants are not projected"); CellConstantSet cDomain = CreateDomainSetFromSlot(cSlot, workspace); restrictedDomain = RestrictDomainByWhereClause(cDomain, cSlot, cQuery); } } // Add the default value to the domain MemberPath sSlotMemberPath = sSlot.MemberPath; CellConstant defaultValue; if (TryGetDefaultValueForMemberPath(sSlotMemberPath, out defaultValue)) { restrictedDomain.Add(defaultValue); } // add all constants appearing in the domain to sDomainMap CellConstantSet sSlotDomain; if (false == sDomainMap.TryGetValue(sSlotMemberPath, out sSlotDomain)) { sDomainMap[sSlotMemberPath] = restrictedDomain; } else { sSlotDomain.AddRange(restrictedDomain); } } } return sDomainMap; } // requires: domain not have any Negated constants other than NotNull // Also, cellQuery contains all final oneOfConsts or all partial oneOfConsts // cellquery must contain a whereclause of the form "True", "OneOfConst" or " // "OneOfConst AND ... AND OneOfConst" // slot must present in cellQuery and incomingDomain is the domain for it // effects: Returns the set of values that slot can take as restricted by cellQuery's whereClause private static CellConstantSet RestrictDomainByWhereClause(IEnumerable domain, JoinTreeSlot slot, CellQuery cellQuery) { // Keep track of different values CellConstantSet allValuesInQuery = null; foreach (OneOfConst oneOfConst in cellQuery.GetConjunctsFromWhereClause()) { // Determine the clause that is relevant for this slot if (false == MemberPath.EqualityComparer.Equals(oneOfConst.Slot.MemberPath, slot.MemberPath)) { continue; } Debug.Assert(allValuesInQuery == null, "More than one Clause with the same path"); allValuesInQuery = new CellConstantRWSet(oneOfConst.Values.Values, CellConstant.EqualityComparer); } // If the slot was not mentioned in the query, do nothing if (allValuesInQuery == null) { return new CellConstantRWSet(domain, CellConstant.EqualityComparer); } // Now get all the possible values from domain and allValuesInQuery CellConstantSet combined = DeterminePossibleValues(allValuesInQuery, domain); // We can now create CellConstantDomains! CellConstantDomain restrictedDomain = new CellConstantDomain(domain, combined); CellConstantDomain allDomainsInQuery = new CellConstantDomain(allValuesInQuery, combined); // Intersect the two domains to get the result restrictedDomain = restrictedDomain.Intersect(allDomainsInQuery); CellConstantSet result = new CellConstantRWSet(restrictedDomain.Values, CellConstant.EqualityComparer); return result; } #endregion #region Private helper methods // effects: Intersects the values in second with this domain and // returns the result private CellConstantDomain Intersect(CellConstantDomain second) { CheckTwoDomainInvariants(this, second); CellConstantDomain result = new CellConstantDomain(this); result.m_domain.Intersect(second.m_domain); return result; } // requires: constants has at most one NegatedCellConstant // effects: Returns the NegatedCellConstant in this if any. Else // returns null private static NegatedCellConstant GetNegatedConstant(IEnumerable constants) { NegatedCellConstant result = null; foreach (CellConstant constant in constants) { NegatedCellConstant negated = constant as NegatedCellConstant; if (negated != null) { Debug.Assert(result == null, "Multiple negated cell constants?"); result = negated; } } return result; } // effects: Given a set of values in domain1 and domain2, // Returns all possible positive values that are present in domain1 and domain2 private static CellConstantSet DeterminePossibleValues(IEnumerable domain1, IEnumerable domain2) { // E.g., if we have 1, 2, NOT(1) --> Result = 1, 2 // 1, NOT(1, 2) --> Result = 1, 2 // 1, 2, NOT(NULL) --> Result = 1, 2, NULL // 1, 2, NOT(2), NOT(3, 4) --> Result = 1, 2, 3, 4 CellConstantSet union = new CellConstantRWSet(domain1, CellConstant.EqualityComparer); union.Unite(domain2); CellConstantSet result = DeterminePossibleValues(union, false); return result; } // effects: Checks that two domains, domain1 and domain2, that are being compared/unioned/intersected, etc // are compatible with each other [Conditional("DEBUG")] private static void CheckTwoDomainInvariants(CellConstantDomain domain1, CellConstantDomain domain2) { domain1.CheckRepInvariant(); domain2.CheckRepInvariant(); // The possible values must match Debug.Assert(domain1.m_possibleValues.SetEquals(domain2.m_possibleValues), "domains must be compatible"); } // effects: A helper method. Given two // values, yields a list of CellConstants in the order of values private static IEnumerable CreateList(object value1, object value2) { yield return new ScalarConstant(value1); yield return new ScalarConstant(value2); } // effects: Checks the invariants in "this" private bool CheckRepInvariantLocal() { // Make sure m_domain has at most one negatedCellConstant // m_possibleValues has none NegatedCellConstant negated = GetNegatedConstant(m_domain); // Can be null or not-null Debug.Assert(negated == null || negated.CheckRepInvariantLocal(), "Negated cell constant's invariant broken"); negated = GetNegatedConstant(m_possibleValues); Debug.Assert(negated == null, "m_possibleValues cannot contain negated constant"); Debug.Assert(m_domain.IsSubsetOf(AllPossibleValuesInternal), "All domain values must be contained in possibleValues"); return true; } #endregion #region String methods // effects: Returns a user-friendly string that can be reported to an end-user internal string ToUserString() { StringBuilder builder = new StringBuilder(); bool isFirst = true; foreach (CellConstant constant in m_domain) { if (isFirst == false) { builder.Append(", "); } builder.Append(constant.ToUserString()); isFirst = false; } return builder.ToString(); } internal override void ToCompactString(StringBuilder builder) { builder.Append(ToUserString()); } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Data.Common.Utils; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Data.Metadata.Edm; using System.Data.Mapping.ViewGeneration.Utils; using System.Linq; namespace System.Data.Mapping.ViewGeneration.Structures { using CellConstantSet = Set; using CellConstantRWSet = Set ; using System.Data.Entity; // A set of cell constants -- to keep track of a cell constant's domain // values. It encapsulates the notions of NULL, NOT NULL and can be // enhanced in the future with more functionality // To represent "infinite" domains such as integer, a special constant CellConstant.NotNull is used. // For example: domain of System.Boolean is {true, false}, domain of // (nullable) System.Int32 property is {Null, NotNull}. internal class CellConstantDomain : InternalBase { #region Constructors // effects: Creates an "fully-done" set with no values -- possibleDiscreteValues are the values // that this domain can take internal CellConstantDomain(CellConstant value, IEnumerable possibleDiscreteValues) : this(new CellConstant[] {value}, possibleDiscreteValues) { } // effects: Creates a domain populated using values -- possibleValues // are all possible values that this can take internal CellConstantDomain(IEnumerable values, IEnumerable possibleDiscreteValues) { // Note that the values can contain both null and not null Debug.Assert(values != null); Debug.Assert(possibleDiscreteValues != null); // Determine the possibleValues first and then create the negatedConstant m_possibleValues = DeterminePossibleValues(values, possibleDiscreteValues); // Now we need to make sure that m_domain is correct. if "values" (v) already has // the negated stuff, we need to make sure it is in conformance // with what m_possibleValues (p) has // For NOT --> Add all constants into d that are present in p but // not in the NOT // v = 1, NOT(1, 2); p = 1, 2, 3 => d = 1, NOT(1, 2, 3), 3 // v = 1, 2, NOT(1); p = 1, 2, 4 => d = 1, 2, 4, NOT(1, 2, 4) // v = 1, 2, NOT(1, 2, 4), NOT(1, 2, 4, 5); p = 1, 2, 4, 5, 6 => // d = 1, 2, 5, 6, NOT(1, 2, 4, 5, 6) // NotNull works naturally now. If possibleValues has (1, 2, // NULL) and values has NOT(NULL), add 1, 2 to m_domain m_domain = NormalizeDomain(values, m_possibleValues); Debug.Assert(CheckRepInvariantLocal()); } // effects: Creates a copy of the set "domain" internal CellConstantDomain(CellConstantDomain domain) { m_domain = new Set (domain.m_domain, CellConstant.EqualityComparer); m_possibleValues = new Set (domain.m_possibleValues, CellConstant.EqualityComparer); Debug.Assert(CheckRepInvariantLocal()); } #endregion #region Fields // The set of values in the cell constant domain private CellConstantSet m_domain; // e.g., 1, 2, NULL, NOT(1, 2, NULL) private CellConstantSet m_possibleValues; // e.g., 1, 2, NULL, Undefined // Invariant: m_domain is a subset of m_possibleValues except for a // negated constant #endregion #region Properties // effects: Returns all the possible values that this can contain (including the negated constants) internal IEnumerable AllPossibleValues { get { return AllPossibleValuesInternal;} } // effects: Returns all the possible values that this can contain (including the negated constants) private Set AllPossibleValuesInternal { get { NegatedCellConstant negatedPossibleValue = new NegatedCellConstant(m_possibleValues); return m_possibleValues.Union(new CellConstant[] { negatedPossibleValue }); } } // effects: Returns the number of constants in this (including a negated constant) internal int Count { get { return m_domain.Count;} } // effects: Yields all the values in this internal IEnumerable Values { get { return m_domain;} } #endregion #region Static Helper Methods to create cell constant sets from metadata // effects: Given a member, determines all possible values that can be created from Metadata internal static CellConstantSet CreateDomainSetFromMemberPath(MemberPath memberPath, MetadataWorkspace workspace) { CellConstantSet domain = CreateDomainFromType(memberPath.EdmType, workspace); if (memberPath.IsNullable) { domain.Add(CellConstant.Null); } return domain; } // effects: Given a slot, determines all possible values that can be created from Metadata private static CellConstantSet CreateDomainSetFromSlot(JoinTreeSlot slot, MetadataWorkspace workspace) { CellConstantSet domain = CreateDomainSetFromMemberPath(slot.MemberPath, workspace); return domain; } // effects: Given a type, determines all possible values that can be created from Metadata private static CellConstantSet CreateDomainFromType(EdmType type, MetadataWorkspace workspace) { CellConstantSet domain = null; PrimitiveType scalarType = type as PrimitiveType; EnumType enumType = type as EnumType; if (scalarType != null) { // Get the domain for scalars -- for booleans, we special case. if (scalarType.PrimitiveTypeKind == PrimitiveTypeKind.Boolean) { domain = new Set (CreateList(true, false), CellConstant.EqualityComparer); } else { // Unbounded domain -- null is added by caller if the // property of this type is nullable domain = new Set (CellConstant.EqualityComparer); domain.Add(CellConstant.NotNull); } } else if (enumType != null) { // Get all the values for the enumeration domain = GetEnumeratedDomain(enumType); } else { Debug.Assert(Helper.IsEntityType(type) || Helper.IsComplexType(type) || Helper.IsRefType(type) || Helper.IsAssociationType(type)); // Treat ref types as their referenced entity types if (Helper.IsRefType(type)) { type = ((RefType)type).ElementType; } List types = new List (); foreach (EdmType derivedType in MetadataHelper.GetTypeAndSubtypesOf(type, workspace, false /*includeAbstractTypes*/)) { TypeConstant derivedTypeConstant = new TypeConstant(derivedType); types.Add(derivedTypeConstant); } domain = new Set (types, CellConstant.EqualityComparer); } Debug.Assert(domain != null, "Domain not set up for some type"); return domain; } // effect: returns the default value for the member // if the member is nullable and has no default, changes default value to CellConstant.NULL and returns true // if the mebmer is not nullable and has no default, returns false // CHANGE_[....]_FEATURE_DEFAULT_VALUES: return the right default once metadata supports it internal static bool TryGetDefaultValueForMemberPath(MemberPath memberPath, out CellConstant defaultConstant) { object defaultValue = memberPath.DefaultValue; defaultConstant = CellConstant.Null; if (defaultValue != null) { defaultConstant = new ScalarConstant(defaultValue); return true; } else if (memberPath.IsNullable || memberPath.IsComputed) { return true; } return false; } internal static CellConstant GetDefaultValueForMemberPath(MemberPath memberPath, IEnumerable wrappersForErrorReporting, ConfigViewGenerator config) { CellConstant defaultValue = null; if (!CellConstantDomain.TryGetDefaultValueForMemberPath(memberPath, out defaultValue)) { string message = Strings.ViewGen_No_Default_Value_1( memberPath.Extent.Name, memberPath.PathToString(false)); ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.NoDefaultValue, message, wrappersForErrorReporting, String.Empty); ExceptionHelpers.ThrowMappingException(record, config); } return defaultValue; } // effects: Given an enumeration type, enumType, returns the set of // values that enumType can take private static CellConstantSet GetEnumeratedDomain(EnumType enumType) { Set values = new Set (CellConstant.EqualityComparer); foreach (EnumMember enumerationValue in enumType.EnumMembers) { values.Add(new ScalarConstant(enumerationValue)); } return values; } #endregion #region External methods internal int GetHash() { int result = 0; foreach (CellConstant constant in m_domain) { result ^= CellConstant.EqualityComparer.GetHashCode(constant); } return result; } // effects: Returns true iff this domain has the same values as // second. Note that this method performs a semantic check not just // an element by element check internal bool IsEqualTo(CellConstantDomain second) { return m_domain.SetEquals(second.m_domain); } // requires: this is fully done // effects: Returns true iff this contains NOT(NULL OR ....) internal bool ContainsNotNull() { NegatedCellConstant negated = GetNegatedConstant(m_domain); return negated != null && negated.Contains(CellConstant.Null); } /// /// Returns true if the domain contains the given Cell Constant /// internal bool Contains(CellConstant constant) { return m_domain.Contains(constant); } internal override bool CheckRepInvariant() { return CheckRepInvariantLocal(); } // effects: Given a set of values in domain, "normalizes" it, i.e., // all positive constants are seperated out and any negative constant // is changed s.t. it is the negative of all positive values // extraValues indicates more constants that domain could take, e.g., // domain could be "1, 2, NOT(1, 2)", extraValues could be "3". In // this case, we return "1, 2, NOT(1, 2, 3)" internal static CellConstantSet NormalizeDomain(IEnumerabledomain, IEnumerable extraValues) { CellConstantSet possibleValues = DeterminePossibleValues(domain, extraValues); // For NOT --> Add all constants into d that are present in p but // not in the NOT // v = 1, NOT(1, 2); p = 1, 2, 3 => d = 1, NOT(1, 2, 3), 3 // v = 1, 2, NOT(1); p = 1, 2, 4 => d = 1, 2, 4, NOT(1, 2, 4) // v = 1, 2, NOT(1, 2, 4), NOT(1, 2, 4, 5); p = 1, 2, 4, 5, 6 => d = 1, 2, 5, 6, NOT(1, 2, 4, 5, 6) // NotNull works naturally now. If possibleValues has (1, 2, NULL) // and values has NOT(NULL), add 1, 2 to m_domain CellConstantSet result = new Set (CellConstant.EqualityComparer); foreach (CellConstant constant in domain) { NegatedCellConstant negated = constant as NegatedCellConstant; if (negated != null) { result.Add(new NegatedCellConstant(possibleValues)); // Compute all elements in possibleValues that are not present in negated. E.g., if // negated is NOT(1, 2, 3) and possibleValues is 1, 2, 3, // 4, we need to add 4 to result CellConstantSet remainingElements = possibleValues.Difference(negated.Elements); result.AddRange(remainingElements); } else { result.Add(constant); } } return result; } // effects: Given a set of values in domain // Returns all possible values that are present in domain. If // addNegatedIfPresent is true, the negated of all possible values is // added if a negated value is present static CellConstantSet DeterminePossibleValues(IEnumerable domain, bool addNegatedIfPresent) { // E.g., if we have 1, 2, NOT(1) --> Result = 1, 2 // 1, NOT(1, 2) --> Result = 1, 2 // 1, 2, NOT(NULL) --> Result = 1, 2, NULL // 1, 2, NOT(2), NOT(3, 4) --> Result = 1, 2, 3, 4 CellConstantSet result = new CellConstantRWSet(CellConstant.EqualityComparer); bool hasNegated = false; foreach (CellConstant constant in domain) { NegatedCellConstant negated = constant as NegatedCellConstant; if (negated != null) { hasNegated = true; // Go through all the constants in negated and add them to domain // We add them to possible values also even if (say) Null is not // allowed because we want the complete partitioning of // the space, e.g., if the values specified by the // caller are 1, NotNull -> we want 1, Null, Not(1, // Null) we can represent Not-Null as 1 + Not(1, NotNull) foreach (CellConstant constElement in negated.Elements) { Debug.Assert(constElement as NegatedCellConstant == null, "Negated cell constant inside NegatedCellConstant"); result.Add(constElement); } } else { result.Add(constant); } } if (hasNegated && addNegatedIfPresent) { NegatedCellConstant negatedValue = new NegatedCellConstant(result); result.Add(negatedValue); } return result; } #endregion #region Helper methods for determining domains from cells // effects: Given a set of cells, returns all the different values // that each memberPath in cells can take internal static Dictionary ComputeConstantDomainSetsForSlotsInQueryViews(IEnumerable cells, MetadataWorkspace workspace) { Dictionary | cDomainMap = new Dictionary (MemberPath.EqualityComparer); foreach (Cell cell in cells) { CellQuery cQuery = cell.CQuery; // Go through the conjuncts to get the constants (e.g., we // just don't want to NULL, NOT(NULL). We want to say that // the possible values are NULL, 4, NOT(NULL, 4) foreach (OneOfConst oneOfConst in cQuery.GetConjunctsFromWhereClause()) { JoinTreeSlot slot = oneOfConst.Slot; CellConstantSet cDomain = CreateDomainSetFromSlot(slot, workspace); // Now we add the domain of oneConst into this //Isnull=true and Isnull=false conditions should not contribute to a member's domain cDomain.AddRange(oneOfConst.Values.Values.Where(c=> !(c.Equals(CellConstant.Null)||c.Equals(CellConstant.NotNull)))); CellConstantSet values; bool found = cDomainMap.TryGetValue(slot.MemberPath, out values); if (!found) { cDomainMap[slot.MemberPath] = cDomain; } else { values.AddRange(cDomain); } } } return cDomainMap; } // effects: returns a dictionary that maps each S-side slot whose domain can be restricted to such an enumerated domain // The resulting domain is a union of // (a) constants appearing in conditions on that slot on S-side // (b) constants appearing in conditions on the respective slot on C-side, if the given slot // is projected (on the C-side) and no conditions are placed on it on S-side // (c) default value of the slot based on metadata internal static Dictionary ComputeConstantDomainSetsForSlotsInUpdateViews(IEnumerable cells, MetadataWorkspace workspace) { Dictionary | sDomainMap = new Dictionary (MemberPath.EqualityComparer); foreach (Cell cell in cells) { CellQuery cQuery = cell.CQuery; CellQuery sQuery = cell.SQuery; foreach (JoinTreeSlot sSlot in sQuery.GetAllQuerySlots()) { // obtain initial slot domain and restrict it if the slot has conditions CellConstantSet sDomain = CreateDomainSetFromSlot(sSlot, workspace); CellConstantSet restrictedDomain = RestrictDomainByWhereClause(sDomain, sSlot, sQuery); // Suppose that we have a cell: Proj(ID, A) Select(A=5)(E) == T(ID, B) // In the above cell, B on the S-side is 5 and we add // that to its range. But if B had a restriction, we do // not add 5. Note that do we not have a problem // w.r.t. possibleValues since if A=5 and B=1, we have an // empty cell -- we should catch that as an error. If A = 5 // and B = 5 is present then restrictedDomain and sDomain // are the same // if no restriction on the S-side and the slot is projected then take the domain from the C-side if (restrictedDomain.SetEquals(sDomain)) { int projectedPosition = sQuery.GetProjectedPosition(sSlot); if (projectedPosition >= 0) { // get the domain of the respective C-side slot JoinTreeSlot cSlot = cQuery.ProjectedSlotAt(projectedPosition) as JoinTreeSlot; Debug.Assert(cSlot != null, "Assuming constants are not projected"); CellConstantSet cDomain = CreateDomainSetFromSlot(cSlot, workspace); restrictedDomain = RestrictDomainByWhereClause(cDomain, cSlot, cQuery); } } // Add the default value to the domain MemberPath sSlotMemberPath = sSlot.MemberPath; CellConstant defaultValue; if (TryGetDefaultValueForMemberPath(sSlotMemberPath, out defaultValue)) { restrictedDomain.Add(defaultValue); } // add all constants appearing in the domain to sDomainMap CellConstantSet sSlotDomain; if (false == sDomainMap.TryGetValue(sSlotMemberPath, out sSlotDomain)) { sDomainMap[sSlotMemberPath] = restrictedDomain; } else { sSlotDomain.AddRange(restrictedDomain); } } } return sDomainMap; } // requires: domain not have any Negated constants other than NotNull // Also, cellQuery contains all final oneOfConsts or all partial oneOfConsts // cellquery must contain a whereclause of the form "True", "OneOfConst" or " // "OneOfConst AND ... AND OneOfConst" // slot must present in cellQuery and incomingDomain is the domain for it // effects: Returns the set of values that slot can take as restricted by cellQuery's whereClause private static CellConstantSet RestrictDomainByWhereClause(IEnumerable domain, JoinTreeSlot slot, CellQuery cellQuery) { // Keep track of different values CellConstantSet allValuesInQuery = null; foreach (OneOfConst oneOfConst in cellQuery.GetConjunctsFromWhereClause()) { // Determine the clause that is relevant for this slot if (false == MemberPath.EqualityComparer.Equals(oneOfConst.Slot.MemberPath, slot.MemberPath)) { continue; } Debug.Assert(allValuesInQuery == null, "More than one Clause with the same path"); allValuesInQuery = new CellConstantRWSet(oneOfConst.Values.Values, CellConstant.EqualityComparer); } // If the slot was not mentioned in the query, do nothing if (allValuesInQuery == null) { return new CellConstantRWSet(domain, CellConstant.EqualityComparer); } // Now get all the possible values from domain and allValuesInQuery CellConstantSet combined = DeterminePossibleValues(allValuesInQuery, domain); // We can now create CellConstantDomains! CellConstantDomain restrictedDomain = new CellConstantDomain(domain, combined); CellConstantDomain allDomainsInQuery = new CellConstantDomain(allValuesInQuery, combined); // Intersect the two domains to get the result restrictedDomain = restrictedDomain.Intersect(allDomainsInQuery); CellConstantSet result = new CellConstantRWSet(restrictedDomain.Values, CellConstant.EqualityComparer); return result; } #endregion #region Private helper methods // effects: Intersects the values in second with this domain and // returns the result private CellConstantDomain Intersect(CellConstantDomain second) { CheckTwoDomainInvariants(this, second); CellConstantDomain result = new CellConstantDomain(this); result.m_domain.Intersect(second.m_domain); return result; } // requires: constants has at most one NegatedCellConstant // effects: Returns the NegatedCellConstant in this if any. Else // returns null private static NegatedCellConstant GetNegatedConstant(IEnumerable constants) { NegatedCellConstant result = null; foreach (CellConstant constant in constants) { NegatedCellConstant negated = constant as NegatedCellConstant; if (negated != null) { Debug.Assert(result == null, "Multiple negated cell constants?"); result = negated; } } return result; } // effects: Given a set of values in domain1 and domain2, // Returns all possible positive values that are present in domain1 and domain2 private static CellConstantSet DeterminePossibleValues(IEnumerable domain1, IEnumerable domain2) { // E.g., if we have 1, 2, NOT(1) --> Result = 1, 2 // 1, NOT(1, 2) --> Result = 1, 2 // 1, 2, NOT(NULL) --> Result = 1, 2, NULL // 1, 2, NOT(2), NOT(3, 4) --> Result = 1, 2, 3, 4 CellConstantSet union = new CellConstantRWSet(domain1, CellConstant.EqualityComparer); union.Unite(domain2); CellConstantSet result = DeterminePossibleValues(union, false); return result; } // effects: Checks that two domains, domain1 and domain2, that are being compared/unioned/intersected, etc // are compatible with each other [Conditional("DEBUG")] private static void CheckTwoDomainInvariants(CellConstantDomain domain1, CellConstantDomain domain2) { domain1.CheckRepInvariant(); domain2.CheckRepInvariant(); // The possible values must match Debug.Assert(domain1.m_possibleValues.SetEquals(domain2.m_possibleValues), "domains must be compatible"); } // effects: A helper method. Given two // values, yields a list of CellConstants in the order of values private static IEnumerable CreateList(object value1, object value2) { yield return new ScalarConstant(value1); yield return new ScalarConstant(value2); } // effects: Checks the invariants in "this" private bool CheckRepInvariantLocal() { // Make sure m_domain has at most one negatedCellConstant // m_possibleValues has none NegatedCellConstant negated = GetNegatedConstant(m_domain); // Can be null or not-null Debug.Assert(negated == null || negated.CheckRepInvariantLocal(), "Negated cell constant's invariant broken"); negated = GetNegatedConstant(m_possibleValues); Debug.Assert(negated == null, "m_possibleValues cannot contain negated constant"); Debug.Assert(m_domain.IsSubsetOf(AllPossibleValuesInternal), "All domain values must be contained in possibleValues"); return true; } #endregion #region String methods // effects: Returns a user-friendly string that can be reported to an end-user internal string ToUserString() { StringBuilder builder = new StringBuilder(); bool isFirst = true; foreach (CellConstant constant in m_domain) { if (isFirst == false) { builder.Append(", "); } builder.Append(constant.ToUserString()); isFirst = false; } return builder.ToString(); } internal override void ToCompactString(StringBuilder builder) { builder.Append(ToUserString()); } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Component.cs
- DeleteIndexBinder.cs
- DataGridAutoFormat.cs
- DbResourceAllocator.cs
- DataGridAddNewRow.cs
- DotExpr.cs
- Image.cs
- ZipIOCentralDirectoryFileHeader.cs
- util.cs
- ExpandCollapseIsCheckedConverter.cs
- ListControlConvertEventArgs.cs
- SystemInfo.cs
- GACIdentityPermission.cs
- ResXFileRef.cs
- PDBReader.cs
- CounterSampleCalculator.cs
- TypeUtils.cs
- UpdatePanel.cs
- PrincipalPermissionMode.cs
- PasswordTextNavigator.cs
- FilterException.cs
- AccessViolationException.cs
- BitmapEffectGroup.cs
- ExpressionValueEditor.cs
- DataRow.cs
- LogExtent.cs
- InternalMappingException.cs
- CodeSpit.cs
- RadioButtonPopupAdapter.cs
- Helpers.cs
- ExpressionBindings.cs
- Function.cs
- DebugController.cs
- AutomationIdentifierGuids.cs
- ApplicationId.cs
- ResourcesBuildProvider.cs
- FilterQuery.cs
- DefaultPrintController.cs
- FormatSettings.cs
- ListenerElementsCollection.cs
- BuildTopDownAttribute.cs
- PersistenceMetadataNamespace.cs
- PageContentAsyncResult.cs
- XmlArrayItemAttribute.cs
- DataControlFieldCell.cs
- LayoutInformation.cs
- PagerSettings.cs
- BasicAsyncResult.cs
- FormsAuthenticationTicket.cs
- FacetDescription.cs
- RunClient.cs
- InvalidProgramException.cs
- Int32CollectionConverter.cs
- ChildTable.cs
- MultiPropertyDescriptorGridEntry.cs
- ProxyHelper.cs
- Int16KeyFrameCollection.cs
- HorizontalAlignConverter.cs
- GZipStream.cs
- RegexInterpreter.cs
- OuterGlowBitmapEffect.cs
- Lease.cs
- BamlBinaryWriter.cs
- RecognizedAudio.cs
- DataRowChangeEvent.cs
- NamespaceQuery.cs
- CrossContextChannel.cs
- EntityContainer.cs
- OrderByBuilder.cs
- SamlConstants.cs
- WebRequestModulesSection.cs
- TypeDependencyAttribute.cs
- TreeView.cs
- PipelineDeploymentState.cs
- EndpointAddressAugust2004.cs
- UIElementCollection.cs
- ExclusiveNamedPipeTransportManager.cs
- ClientBuildManagerCallback.cs
- StrokeCollection2.cs
- InternalConfigConfigurationFactory.cs
- RegistryKey.cs
- Location.cs
- ProfilePropertyMetadata.cs
- TemplatePropertyEntry.cs
- ArrayItemReference.cs
- DataListDesigner.cs
- ColorKeyFrameCollection.cs
- InternalDispatchObject.cs
- DataGridViewColumnCollection.cs
- HashMembershipCondition.cs
- TextParentUndoUnit.cs
- Queue.cs
- XmlSchemaValidationException.cs
- RTTrackingProfile.cs
- SqlDataSourceQueryEditor.cs
- UnknownExceptionActionHelper.cs
- _ListenerAsyncResult.cs
- DataControlPagerLinkButton.cs
- BitmapImage.cs
- __FastResourceComparer.cs