private void GenerateCellRelations(int cellNumber) { // Generate the view cell relation List <ViewCellSlot> projectedSlots = new List <ViewCellSlot>(); // construct a ViewCellSlot for each slot Debug.Assert(CQuery.NumProjectedSlots == SQuery.NumProjectedSlots, "Cell queries in cell have a different number of slots"); for (int i = 0; i < CQuery.NumProjectedSlots; i++) { ProjectedSlot cSlot = CQuery.ProjectedSlotAt(i); ProjectedSlot sSlot = SQuery.ProjectedSlotAt(i); Debug.Assert(cSlot != null, "Has cell query been normalized?"); Debug.Assert(sSlot != null, "Has cell query been normalized?"); // These slots better be MemberProjectedSlots. We do not have constants etc at this point. Debug.Assert(cSlot is MemberProjectedSlot, "cSlot is expected to be MemberProjectedSlot"); Debug.Assert(sSlot is MemberProjectedSlot, "sSlot is expected to be MemberProjectedSlot"); MemberProjectedSlot cJoinSlot = (MemberProjectedSlot)cSlot; MemberProjectedSlot sJoinSlot = (MemberProjectedSlot)sSlot; ViewCellSlot slot = new ViewCellSlot(i, cJoinSlot, sJoinSlot); projectedSlots.Add(slot); } m_viewCellRelation = new ViewCellRelation(this, projectedSlots, cellNumber); }
// effects: Given a cell, determines the paths to which the paths in // columns map to in the C-space and returns them. If some columns // are not projected in the cell, or if the corresponding properties // are not mapped into C-space, returns null internal Set <EdmProperty> GetCSlotsForTableColumns(IEnumerable <MemberPath> columns) { List <int> fieldNums = SQuery.GetProjectedPositions(columns); if (fieldNums == null) { return(null); } // The fields are mapped -- see if they are mapped on the // cSide and they correspond to the primary key of the // entity set Set <EdmProperty> cSideMembers = new Set <EdmProperty>(); foreach (int fieldNum in fieldNums) { ProjectedSlot projectedSlot = CQuery.ProjectedSlotAt(fieldNum); MemberProjectedSlot slot = projectedSlot as MemberProjectedSlot; if (slot != null) { // We can call LastMember since columns do not map to // extents or memberEnds. Can cast to EdmProperty since it // cannot be an association end cSideMembers.Add((EdmProperty)slot.MemberPath.LeafEdmMember); } else { return(null); } } return(cSideMembers); }
ComputeConstantDomainSetsForSlotsInQueryViews(IEnumerable <Cell> cells, EdmItemCollection edmItemCollection, bool isValidationEnabled) { Dictionary <MemberPath, CellConstantSet> cDomainMap = new Dictionary <MemberPath, CellConstantSet>(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 (MemberRestriction restriction in cQuery.GetConjunctsFromWhereClause()) { MemberProjectedSlot slot = restriction.RestrictedMemberSlot; CellConstantSet cDomain = DeriveDomainFromMemberPath(slot.MemberPath, edmItemCollection, isValidationEnabled); // 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(restriction.Domain.Values.Where(c => !(c.Equals(Constant.Null) || c.Equals(Constant.NotNull)))); CellConstantSet values; bool found = cDomainMap.TryGetValue(slot.MemberPath, out values); if (!found) { cDomainMap[slot.MemberPath] = cDomain; } else { values.AddRange(cDomain); } } } return(cDomainMap); }
//True = domain is restricted, False = domain is not restricted (because there is no condition) private static bool GetRestrictedOrUnrestrictedDomain(MemberProjectedSlot slot, CellQuery cellQuery, EdmItemCollection edmItemCollection, out CellConstantSet domain) { CellConstantSet domainValues = DeriveDomainFromMemberPath(slot.MemberPath, edmItemCollection, true /* leaveDomainUnbounded */); //Note, out domain is set even in the case where method call returns false return(TryGetDomainRestrictedByWhereClause(domainValues, slot, cellQuery, out domain)); }
// requires: children to be a list of nodes that are children of an // Inner Join node. slotNum does not correspond to the key slot // effects: Determines the child number from which the slot should be // picked up. private static int GetInnerJoinChildForSlot(List <CqlBlock> children, int slotNum) { // Picks the child with the non-constant slot first. If none, picks a non-null constant slot. // If not een that, picks any one int result = -1; for (int i = 0; i < children.Count; i++) { CqlBlock child = children[i]; if (false == child.IsProjected(slotNum)) { continue; } ProjectedSlot slot = child.SlotValue(slotNum); ConstantProjectedSlot constantSlot = slot as ConstantProjectedSlot; MemberProjectedSlot joinSlot = slot as MemberProjectedSlot; if (joinSlot != null) { // Pick the non-constant slot result = i; } else if (constantSlot != null && constantSlot.CellConstant.IsNull()) { if (result == -1) { // In case, all are null result = i; } } else { // Just pick anything result = i; } } return(result); }
/// <summary> /// Creates a complete member restriction with the meaning "<paramref name="slot"/> in <paramref name="domain"/>". /// </summary> protected MemberRestriction(MemberProjectedSlot slot, Domain domain) { m_restrictedMemberSlot = slot; m_domain = domain; m_isComplete = true; Debug.Assert(m_domain.Count != 0, "If you want a boolean that evaluates to false, " + "use the ConstantBool abstraction"); }
private bool TryGetWithRelationship(StorageAssociationSetMapping colocatedAssociationSetMap, EntitySetBase thisExtent, MemberPath sRootNode, ref List <SlotInfo> foreignKeySlots, out WithRelationship withRelationship) { Debug.Assert(foreignKeySlots != null); withRelationship = null; //Get the map for foreign key end StorageEndPropertyMapping foreignKeyEndMap = GetForeignKeyEndMapFromAssocitionMap(colocatedAssociationSetMap, thisExtent); if (foreignKeyEndMap == null || foreignKeyEndMap.EndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many) { return(false); } AssociationEndMember toEnd = (AssociationEndMember)foreignKeyEndMap.EndMember; AssociationEndMember fromEnd = MetadataHelper.GetOtherAssociationEnd(toEnd); EntityType toEndEntityType = (EntityType)((RefType)(toEnd.TypeUsage.EdmType)).ElementType; EntityType fromEndEntityType = (EntityType)(((RefType)fromEnd.TypeUsage.EdmType).ElementType); // Get the member path for AssociationSet AssociationSet associationSet = (AssociationSet)colocatedAssociationSetMap.Set; MemberPath prefix = new MemberPath(associationSet, toEnd); // Collect the member paths for edm scalar properties that belong to the target entity key. // These will be used as part of WITH RELATIONSHIP. // Get the key properties from edm type since the query parser depends on the order of key members IEnumerable <StorageScalarPropertyMapping> propertyMaps = foreignKeyEndMap.Properties.Cast <StorageScalarPropertyMapping>(); List <MemberPath> toEndEntityKeyMemberPaths = new List <MemberPath>(); foreach (EdmProperty edmProperty in toEndEntityType.KeyMembers) { IEnumerable <StorageScalarPropertyMapping> scalarPropertyMaps = propertyMaps.Where(propMap => (propMap.EdmProperty.Equals(edmProperty))); Debug.Assert(scalarPropertyMaps.Count() == 1, "Can't Map the same column multiple times in the same end"); StorageScalarPropertyMapping scalarPropertyMap = scalarPropertyMaps.First(); // Create SlotInfo for Freign Key member that needs to be projected. MemberProjectedSlot sSlot = new MemberProjectedSlot(new MemberPath(sRootNode, scalarPropertyMap.ColumnProperty)); MemberPath endMemberKeyPath = new MemberPath(prefix, edmProperty); toEndEntityKeyMemberPaths.Add(endMemberKeyPath); foreignKeySlots.Add(new SlotInfo(true, true, sSlot, endMemberKeyPath)); } // Parent assignable from child: Ensures they are in the same hierarchy. if (thisExtent.ElementType.IsAssignableFrom(fromEndEntityType)) { // Now create the WITH RELATIONSHIP with all the needed info. withRelationship = new WithRelationship(associationSet, fromEnd, fromEndEntityType, toEnd, toEndEntityType, toEndEntityKeyMemberPaths); return(true); } else { return(false); } }
// requires: The Where clause satisfies the same requirements a GetConjunctsFromWhereClause // effects: For each slot that has a NotNull condition in the where // clause, checks if it is projected. If all such slots are // projected, returns null. Else returns an error record internal ErrorLog.Record CheckForProjectedNotNullSlots(Cell sourceCell, IEnumerable <Cell> associationSets) { StringBuilder builder = new StringBuilder(); bool foundError = false; foreach (MemberRestriction restriction in Conditions) { if (restriction.Domain.ContainsNotNull()) { MemberProjectedSlot slot = MemberProjectedSlot.GetSlotForMember(m_projectedSlots, restriction.RestrictedMemberSlot.MemberPath); if (slot == null) //member with not null condition is not mapped in this extent { bool missingMapping = true; if (Extent is EntitySet) { bool isCQuery = sourceCell.CQuery == this; ViewTarget target = isCQuery ? ViewTarget.QueryView : ViewTarget.UpdateView; CellQuery rightCellQuery = isCQuery? sourceCell.SQuery : sourceCell.CQuery; //Find out if there is an association mapping but only if the current Not Null condition is on an EntitySet EntitySet rightExtent = rightCellQuery.Extent as EntitySet; if (rightExtent != null) { List <AssociationSet> associations = MetadataHelper.GetAssociationsForEntitySet(rightCellQuery.Extent as EntitySet); foreach (var association in associations.Where(association => association.AssociationSetEnds.Any(end => (end.CorrespondingAssociationEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One && (MetadataHelper.GetOppositeEnd(end).EntitySet.EdmEquals(rightExtent)))))) { foreach (var associationCell in associationSets.Where(c => c.GetRightQuery(target).Extent.EdmEquals(association))) { if (MemberProjectedSlot.GetSlotForMember(associationCell.GetLeftQuery(target).ProjectedSlots, restriction.RestrictedMemberSlot.MemberPath) != null) { missingMapping = false; } } } } } if (missingMapping) { // condition of NotNull and slot not being projected builder.AppendLine(System.Data.Entity.Strings.ViewGen_NotNull_No_Projected_Slot( restriction.RestrictedMemberSlot.MemberPath.PathToString(false))); foundError = true; } } } } if (false == foundError) { return(null); } ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.NotNullNoProjectedSlot, builder.ToString(), sourceCell, String.Empty); return(record); }
// effects: Returns the fields in this, i.e., not constants or null slots private IEnumerable <MemberProjectedSlot> GetMemberProjectedSlots() { foreach (ProjectedSlot slot in m_projectedSlots) { MemberProjectedSlot memberSlot = slot as MemberProjectedSlot; if (memberSlot != null) { yield return(memberSlot); } } }
protected override bool IsEqualTo(ProjectedSlot right) { MemberProjectedSlot rightSlot = right as MemberProjectedSlot; if (rightSlot == null) { return(false); } // We want equality of the paths return(MemberPath.EqualityComparer.Equals(m_memberPath, rightSlot.m_memberPath)); }
// effects: returns the index at which this slot appears in the projection // or -1 if it is not projected internal int GetProjectedPosition(MemberProjectedSlot slot) { for (int i = 0; i < m_projectedSlots.Length; i++) { if (MemberProjectedSlot.EqualityComparer.Equals(slot, m_projectedSlots[i])) { return(i); } } return(-1); }
// effects: Determines all the identifiers used in this and adds them to identifiers internal void GetIdentifiers(CqlIdentifiers identifiers) { foreach (ProjectedSlot projectedSlot in m_projectedSlots) { MemberProjectedSlot slot = projectedSlot as MemberProjectedSlot; if (slot != null) { slot.MemberPath.GetIdentifiers(identifiers); } } m_extentMemberPath.GetIdentifiers(identifiers); }
// requires: slot corresponds to a slot in the corresponding // BasicCellRelation // effects: Given a slot in the corresponding basicCellRelation, // looks up the slot in this viewcellrelation and returns it. Returns // null if it does not find the slot in the left or right side of the viewrelation internal ViewCellSlot LookupViewSlot(MemberProjectedSlot slot) { // CHANGE_Microsoft_IMPROVE: We could have a dictionary to speed this up foreach (ViewCellSlot viewSlot in m_slots) { // If the left or right slots are equal, return the viewSlot if (ProjectedSlot.EqualityComparer.Equals(slot, viewSlot.CSlot) || ProjectedSlot.EqualityComparer.Equals(slot, viewSlot.SSlot)) { return viewSlot; } } return null; }
// effects: returns the List of indexes at which this member appears in the projection // or empty list if it is not projected internal List <int> GetProjectedPositions(MemberPath member) { List <int> pathIndexes = new List <int>(); for (int i = 0; i < m_projectedSlots.Length; i++) { MemberProjectedSlot slot = m_projectedSlots[i] as MemberProjectedSlot; if (slot != null && MemberPath.EqualityComparer.Equals(member, slot.MemberPath)) { pathIndexes.Add(i); } } return(pathIndexes); }
/// <summary> /// Searches for members in <paramref name="slots"/> and returns the corresponding slots in the same order as present in /// <paramref name="members"/>. Returns null if even one member is not present in slots. /// </summary> internal static List <MemberProjectedSlot> GetSlots(IEnumerable <MemberProjectedSlot> slots, IEnumerable <MemberPath> members) { List <MemberProjectedSlot> result = new List <MemberProjectedSlot>(); foreach (MemberPath member in members) { MemberProjectedSlot slot = GetSlotForMember(Helpers.AsSuperTypeList <MemberProjectedSlot, ProjectedSlot>(slots), member); if (slot == null) { return(null); } result.Add(slot); } return(result); }
// effects : Return the slot numbers for members in Cell Query that // represent the association end member passed in. internal List <int> GetAssociationEndSlots(AssociationEndMember endMember) { List <int> slotIndexes = new List <int>(); Debug.Assert(this.Extent is AssociationSet); for (int i = 0; i < m_projectedSlots.Length; i++) { MemberProjectedSlot slot = m_projectedSlots[i] as MemberProjectedSlot; if (slot != null && slot.MemberPath.RootEdmMember.Equals(endMember)) { slotIndexes.Add(i); } } return(slotIndexes); }
// requires: All slots in this are null or non-constants // effects: Returns the non-null slots of this internal AttributeSet GetNonNullSlots() { AttributeSet attributes = new AttributeSet(MemberPath.EqualityComparer); foreach (ProjectedSlot projectedSlot in m_projectedSlots) { // null means 'unused' slot -- we ignore those if (projectedSlot != null) { MemberProjectedSlot projectedVar = projectedSlot as MemberProjectedSlot; Debug.Assert(projectedVar != null, "Projected slot must not be a constant"); attributes.Add(projectedVar.MemberPath); } } return(attributes); }
// requires: RightCellQuery.Extent corresponds to a relationship set // effects: Returns the ends to which the key of the corresponding // table (i.e., the left query) maps to in the relationship set. For // example, if RightCellQuery.Extent is OrderOrders and it maps to // <oid, otherOid> of table SOrders with key oid, this returns the // end to which oid is mapped. Similarly, if we have a link table // with the whole key mapped to two ends of the association set, it // returns both ends private Set <AssociationEndMember> GetEndsForTablePrimaryKey() { CellQuery rightQuery = RightCellQuery; Set <AssociationEndMember> result = new Set <AssociationEndMember>(EqualityComparer <AssociationEndMember> .Default); // Get the key slots for the table (they are in the slotMap) and // check for that slot on the C-side foreach (int keySlot in m_memberMaps.ProjectedSlotMap.KeySlots) { MemberProjectedSlot slot = (MemberProjectedSlot)rightQuery.ProjectedSlotAt(keySlot); MemberPath path = slot.MemberPath; // See what end it maps to in the relationSet AssociationEndMember endMember = (AssociationEndMember)path.RootEdmMember; Debug.Assert(endMember != null, "Element in path before scalar path is not end property?"); result.Add(endMember); } Debug.Assert(result != null, "No end found for keyslots of table?"); return(result); }
// requires: projectedSlotMap which contains a mapping of the fields // for "this" to integers // effects: Align the fields of this cell query using the // projectedSlotMap and generates a new query into newMainQuery // Based on the re-aligned fields in this, re-aligns the // corresponding fields in otherQuery as well and modifies // newOtherQuery to contain it // Example: // input: Proj[A,B,"5"] = Proj[F,"7",G] // Proj[C,B] = Proj[H,I] // projectedSlotMap: A -> 0, B -> 1, C -> 2 // output: Proj[A,B,null] = Proj[F,"7",null] // Proj[null,B,C] = Proj[null,I,H] internal void CreateFieldAlignedCellQueries(CellQuery otherQuery, MemberProjectionIndex projectedSlotMap, out CellQuery newMainQuery, out CellQuery newOtherQuery) { // mainSlots and otherSlots hold the new slots for two queries int numAlignedSlots = projectedSlotMap.Count; ProjectedSlot[] mainSlots = new ProjectedSlot[numAlignedSlots]; ProjectedSlot[] otherSlots = new ProjectedSlot[numAlignedSlots]; // Go through the slots for this query and find the new slot for them for (int i = 0; i < m_projectedSlots.Length; i++) { MemberProjectedSlot slot = m_projectedSlots[i] as MemberProjectedSlot; Debug.Assert(slot != null, "All slots during cell normalization must field slots"); // Get the the ith slot's variable and then get the // new slot number from the field map int newSlotNum = projectedSlotMap.IndexOf(slot.MemberPath); Debug.Assert(newSlotNum >= 0, "Field projected but not in projectedSlotMap"); mainSlots[newSlotNum] = m_projectedSlots[i]; otherSlots[newSlotNum] = otherQuery.m_projectedSlots[i]; // We ignore constants -- note that this is not the // isHighpriority or discriminator case. An example of this // is when (say) Address does not have zip but USAddress // does. Then the constraint looks like Pi_NULL, A, B(E) = // Pi_x, y, z(S) // We don't care about this null in the view generation of // the left side. Note that this could happen in inheritance // or in cases when say the S side has 20 fields but the C // side has only 3 - the other 17 are null or default. // NOTE: We allow such constants only on the C side and not // ont the S side. Otherwise, we can have a situation Pi_A, // B, C(E) = Pi_5, y, z(S) Then someone can set A to 7 and we // will not roundtrip. We check for this in validation } // Make the new cell queries with the new slots newMainQuery = new CellQuery(this, mainSlots); newOtherQuery = new CellQuery(otherQuery, otherSlots); }
internal string ToESqlString() { StringBuilder builder = new StringBuilder(); builder.Append("\n\tSELECT "); if (m_selectDistinct == SelectDistinct.Yes) { builder.Append("DISTINCT "); } foreach (ProjectedSlot ps in m_projectedSlots) { MemberProjectedSlot jtn = ps as MemberProjectedSlot; StructuralType st = jtn.MemberPath.LeafEdmMember.DeclaringType; StringBuilder sb = new StringBuilder(); jtn.MemberPath.AsEsql(sb, "e"); builder.AppendFormat("{0}, ", sb.ToString()); } //remove the extra-comma after the last slot builder.Remove(builder.Length - 2, 2); builder.Append("\n\tFROM "); EntitySetBase extent = m_extentMemberPath.Extent; CqlWriter.AppendEscapedQualifiedName(builder, extent.EntityContainer.Name, extent.Name); builder.Append(" AS e"); if (m_whereClause.IsTrue == false) { builder.Append("\n\tWHERE "); StringBuilder qbuilder = new StringBuilder(); m_whereClause.AsEsql(qbuilder, "e"); builder.Append(qbuilder.ToString()); } builder.Append("\n "); return(builder.ToString()); }
/// <summary> /// Given two lists <paramref name="slots1"/> and <paramref name="slots2"/>, merge them and returnthe resulting slots, /// i.e., empty slots from one are overridden by the slots from the other. /// </summary> private static bool TryMergeSlots(ProjectedSlot[] slots1, ProjectedSlot[] slots2, out ProjectedSlot[] slots) { Debug.Assert(slots1.Length == slots2.Length, "Merged slots of two cells must be same size"); slots = new ProjectedSlot[slots1.Length]; for (int i = 0; i < slots.Length; i++) { ProjectedSlot slot1 = slots1[i]; ProjectedSlot slot2 = slots2[i]; if (slot1 == null) { slots[i] = slot2; } else if (slot2 == null) { slots[i] = slot1; } else { // Both slots are non-null: Either both are the same // members or one of them is a constant // Note: if both are constants (even different constants) // it does not matter which one we pick because the CASE statement will override it MemberProjectedSlot memberSlot1 = slot1 as MemberProjectedSlot; MemberProjectedSlot memberSlot2 = slot2 as MemberProjectedSlot; if (memberSlot1 != null && memberSlot2 != null && false == EqualityComparer.Equals(memberSlot1, memberSlot2)) { // Illegal combination of slots; non-constant fields disagree return(false); } // If one of them is a field we have to get the field ProjectedSlot pickedSlot = (memberSlot1 != null) ? slot1 : slot2; slots[i] = pickedSlot; } } return(true); }
// requires: this domainMap has been created for the C-side // effects: Fixes the mergedDomain map in this by merging entries // available in updateDomainMap internal static void PropagateUpdateDomainToQueryDomain(IEnumerable <Cell> cells, MemberDomainMap queryDomainMap, MemberDomainMap updateDomainMap) { foreach (Cell cell in cells) { CellQuery cQuery = cell.CQuery; CellQuery sQuery = cell.SQuery; for (int i = 0; i < cQuery.NumProjectedSlots; i++) { MemberProjectedSlot cSlot = cQuery.ProjectedSlotAt(i) as MemberProjectedSlot; MemberProjectedSlot sSlot = sQuery.ProjectedSlotAt(i) as MemberProjectedSlot; if (cSlot == null || sSlot == null) { continue; } // Get the domain for sSlot and merge with cSlot's MemberPath cPath = cSlot.MemberPath; MemberPath sPath = sSlot.MemberPath; CellConstantSet cDomain = queryDomainMap.GetDomainInternal(cPath); CellConstantSet sDomain = updateDomainMap.GetDomainInternal(sPath); // skip NULL because if c-side member is nullable, it's already there, and otherwise can't be taken // skip negated because negated values are translated in a special way cDomain.Unite(sDomain.Where(constant => !constant.IsNull() && !(constant is NegatedConstant))); if (updateDomainMap.IsConditionMember(sPath) && !queryDomainMap.IsConditionMember(cPath)) { // record this member so KB knows we have to generate constraints for it queryDomainMap.m_projectedConditionMembers.Add(cPath); } } } ExpandNegationsInDomainMap(queryDomainMap.m_conditionDomainMap); ExpandNegationsInDomainMap(queryDomainMap.m_nonConditionDomainMap); }
// requires: "this" is a query on the C-side // and cSideSlotIndexes corresponds to the indexes // (into "this") that the slot is being mapped into // cSideSlotIndexes.Count > 1 - that is, a particular column in "this"'s corresponding S-Query // has been mapped to more than one property in "this" // // effects: Checks that the multiple mappings on the C-side are // backed by an appropriate Referential constraint // If a column is mapped to two properties <A, B> in a single cell: // (a) Must be an association // (b) The two properties must be on opposite ends of the association // (c) The association must have a RI constraint // (d) Ordinal[A] == Ordinal[B] in the RI constraint // (c) and (d) can be stated as - the slots are equivalent, i.e., // kept equal via an RI constraint private bool AreSlotsEquivalentViaRefConstraints(ReadOnlyCollection <int> cSideSlotIndexes) { // Check (a): Must be an association AssociationSet assocSet = Extent as AssociationSet; if (assocSet == null) { return(false); } // Check (b): The two properties must be on opposite ends of the association // There better be exactly two properties! Debug.Assert(cSideSlotIndexes.Count > 1, "Method called when no duplicate mapping"); if (cSideSlotIndexes.Count > 2) { return(false); } // They better be join tree slots (if they are mapped!) and map to opposite ends MemberProjectedSlot slot0 = (MemberProjectedSlot)m_projectedSlots[cSideSlotIndexes[0]]; MemberProjectedSlot slot1 = (MemberProjectedSlot)m_projectedSlots[cSideSlotIndexes[1]]; return(slot0.MemberPath.IsEquivalentViaRefConstraint(slot1.MemberPath)); }
internal override BoolLiteral RemapBool(Dictionary <MemberPath, MemberPath> remap) { MemberProjectedSlot newVar = (MemberProjectedSlot)this.RestrictedMemberSlot.RemapSlot(remap); return(new TypeRestriction(newVar, this.Domain)); }
/// <summary> /// Creates a complete type restriction of the form "<paramref name="slot"/> in <paramref name="domain"/>". /// </summary> internal TypeRestriction(MemberProjectedSlot slot, Domain domain) : base(slot, domain) { }
/// <summary> /// Creates a scalar member restriction with the meaning "<paramref name="slot"/> in <paramref name="domain"/>". /// </summary> internal ScalarRestriction(MemberProjectedSlot slot, Domain domain) : base(slot, domain) { }
// returns true when the case statement is completed private bool AddRewritingToCaseStatement( Tile<FragmentQuery> rewriting, CaseStatement caseStatement, MemberPath currentPath, Constant domainValue) { var whenCondition = BoolExpression.True; // check whether the rewriting is always true or always false // if it's always true, we don't need any other WHEN clauses in the case statement // if it's always false, we don't need to add this WHEN clause to the case statement // given: domainQuery is satisfied. Check (domainQuery -> rewriting) var isAlwaysTrue = _qp.IsContainedIn(CreateTile(_domainQuery), rewriting); var isAlwaysFalse = _qp.IsDisjointFrom(CreateTile(_domainQuery), rewriting); Debug.Assert(!(isAlwaysTrue && isAlwaysFalse)); if (isAlwaysFalse) { return false; // don't need an unsatisfiable WHEN clause } if (isAlwaysTrue) { Debug.Assert(caseStatement.Clauses.Count == 0); } ProjectedSlot projectedSlot; if (domainValue.HasNotNull()) { projectedSlot = new MemberProjectedSlot(currentPath); } else { projectedSlot = new ConstantProjectedSlot(domainValue); } if (!isAlwaysTrue) { whenCondition = TileToBoolExpr(rewriting); } else { whenCondition = BoolExpression.True; } caseStatement.AddWhenThen(whenCondition, projectedSlot); return isAlwaysTrue; }
// effects: Returns an error record if the keys of the extent/associationSet being mapped are // present in the projected slots of this query. Returns null // otherwise. ownerCell indicates the cell that owns this and // resourceString is a resource used for error messages internal ErrorLog.Record VerifyKeysPresent(Cell ownerCell, Func <object, object, string> formatEntitySetMessage, Func <object, object, object, string> formatAssociationSetMessage, ViewGenErrorCode errorCode) { List <MemberPath> prefixes = new List <MemberPath>(1); // Keep track of the key corresponding to each prefix List <ExtentKey> keys = new List <ExtentKey>(1); if (Extent is EntitySet) { // For entity set just get the full path of the key properties MemberPath prefix = new MemberPath(Extent); prefixes.Add(prefix); EntityType entityType = (EntityType)Extent.ElementType; List <ExtentKey> entitySetKeys = ExtentKey.GetKeysForEntityType(prefix, entityType); Debug.Assert(entitySetKeys.Count == 1, "Currently, we only support primary keys"); keys.Add(entitySetKeys[0]); } else { AssociationSet relationshipSet = (AssociationSet)Extent; // For association set, get the full path of the key // properties of each end foreach (AssociationSetEnd relationEnd in relationshipSet.AssociationSetEnds) { AssociationEndMember assocEndMember = relationEnd.CorrespondingAssociationEndMember; MemberPath prefix = new MemberPath(relationshipSet, assocEndMember); prefixes.Add(prefix); List <ExtentKey> endKeys = ExtentKey.GetKeysForEntityType(prefix, MetadataHelper.GetEntityTypeForEnd(assocEndMember)); Debug.Assert(endKeys.Count == 1, "Currently, we only support primary keys"); keys.Add(endKeys[0]); } } for (int i = 0; i < prefixes.Count; i++) { MemberPath prefix = prefixes[i]; // Get all or none key slots that are being projected in this cell query List <MemberProjectedSlot> keySlots = MemberProjectedSlot.GetKeySlots(GetMemberProjectedSlots(), prefix); if (keySlots == null) { ExtentKey key = keys[i]; string message; if (Extent is EntitySet) { string keyPropertiesString = MemberPath.PropertiesToUserString(key.KeyFields, true); message = formatEntitySetMessage(keyPropertiesString, Extent.Name); } else { string endName = prefix.RootEdmMember.Name; string keyPropertiesString = MemberPath.PropertiesToUserString(key.KeyFields, false); message = formatAssociationSetMessage(keyPropertiesString, endName, Extent.Name); } ErrorLog.Record error = new ErrorLog.Record(true, errorCode, message, ownerCell, String.Empty); return(error); } } return(null); }
/// <summary> /// Creates an incomplete member restriction with the meaning "<paramref name="slot"/> in <paramref name="values"/>". /// </summary> protected MemberRestriction(MemberProjectedSlot slot, IEnumerable<Constant> values) { m_restrictedMemberSlot = slot; m_domain = new Domain(values, values); }
ComputeConstantDomainSetsForSlotsInUpdateViews(IEnumerable <Cell> cells, EdmItemCollection edmItemCollection) { Dictionary <MemberPath, CellConstantSet> updateDomainMap = new Dictionary <MemberPath, CellConstantSet>(MemberPath.EqualityComparer); foreach (Cell cell in cells) { CellQuery cQuery = cell.CQuery; CellQuery sQuery = cell.SQuery; foreach (MemberProjectedSlot sSlot in sQuery.GetConjunctsFromWhereClause().Select(oneOfConst => oneOfConst.RestrictedMemberSlot)) { // obtain initial slot domain and restrict it if the slot has conditions CellConstantSet restrictedDomain; bool wasDomainRestricted = GetRestrictedOrUnrestrictedDomain(sSlot, sQuery, edmItemCollection, out restrictedDomain); // Suppose that we have a cell: // Proj(ID, A) WHERE(A=5) FROM E = Proj(ID, B) FROM T // 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 domainValues are the same // if no restriction on the S-side and the slot is projected then take the domain from the C-side if (!wasDomainRestricted) { int projectedPosition = sQuery.GetProjectedPosition(sSlot); if (projectedPosition >= 0) { // get the domain of the respective C-side slot MemberProjectedSlot cSlot = cQuery.ProjectedSlotAt(projectedPosition) as MemberProjectedSlot; Debug.Assert(cSlot != null, "Assuming constants are not projected"); wasDomainRestricted = GetRestrictedOrUnrestrictedDomain(cSlot, cQuery, edmItemCollection, out restrictedDomain); if (!wasDomainRestricted) { continue; } } } // Add the default value to the domain MemberPath sSlotMemberPath = sSlot.MemberPath; Constant defaultValue; if (TryGetDefaultValueForMemberPath(sSlotMemberPath, out defaultValue)) { restrictedDomain.Add(defaultValue); } // add all constants appearing in the domain to sDomainMap CellConstantSet sSlotDomain; if (!updateDomainMap.TryGetValue(sSlotMemberPath, out sSlotDomain)) { updateDomainMap[sSlotMemberPath] = restrictedDomain; } else { sSlotDomain.AddRange(restrictedDomain); } } } return(updateDomainMap); }
// 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 bool TryGetDomainRestrictedByWhereClause(IEnumerable<Constant> domain, MemberProjectedSlot slot, CellQuery cellQuery, out CellConstantSet result) { var conditionsForSlot = cellQuery.GetConjunctsFromWhereClause() .Where(restriction => MemberPath.EqualityComparer.Equals(restriction.RestrictedMemberSlot.MemberPath, slot.MemberPath)) .Select(restriction => new CellConstantSet(restriction.Domain.Values, Constant.EqualityComparer)); //Debug.Assert(!conditionsForSlot.Skip(1).Any(), "More than one Clause with the same path"); if (!conditionsForSlot.Any()) { // If the slot was not mentioned in the query return the domain without restricting it result = new CellConstantSet(domain); return false; } // Now get all the possible values from domain and conditionValues CellConstantSet possibleValues = DeterminePossibleValues(conditionsForSlot.SelectMany(m => m.Select(c => c)), domain); Domain restrictedDomain = new Domain(domain, possibleValues); foreach (var conditionValues in conditionsForSlot) { // Domain derived from Edm-Type INTERSECTED with Conditions restrictedDomain = restrictedDomain.Intersect(new Domain(conditionValues, possibleValues)); } result = new CellConstantSet(restrictedDomain.Values, Constant.EqualityComparer); return !domain.SequenceEqual(result); }
/// <summary> /// Creates an incomplete member restriction with the meaning "<paramref name="slot"/> = <paramref name="value"/>". /// "Partial" means that the <see cref="Domain"/> in this restriction is partial - hence the operations on the restriction are limited. /// </summary> protected MemberRestriction(MemberProjectedSlot slot, Constant value) : this(slot, new Constant[] { value }) { }
//True = domain is restricted, False = domain is not restricted (because there is no condition) private static bool GetRestrictedOrUnrestrictedDomain(MemberProjectedSlot slot, CellQuery cellQuery, EdmItemCollection edmItemCollection, out CellConstantSet domain) { CellConstantSet domainValues = DeriveDomainFromMemberPath(slot.MemberPath, edmItemCollection, true /* leaveDomainUnbounded */); //Note, out domain is set even in the case where method call returns false return TryGetDomainRestrictedByWhereClause(domainValues, slot, cellQuery, out domain); }
internal CellConstantSetInfo(Set<Constant> iconstants, MemberProjectedSlot islot) : base(iconstants) { slot = islot; }
// effects: /// <summary> /// Creates a view cell slot that corresponds to <paramref name="slotNum"/> in some cell. The <paramref name="cSlot"/> and <paramref name="sSlot"/> represent the /// slots in the left and right queries of the view cell. /// </summary> internal ViewCellSlot(int slotNum, MemberProjectedSlot cSlot, MemberProjectedSlot sSlot) { m_slotNum = slotNum; m_cSlot = cSlot; m_sSlot = sSlot; }
// requires: All slots in this are join tree slots // This method is called for an S-side query // cQuery is the corresponding C-side query in the cell // sourceCell is the original cell for "this" and cQuery // effects: Checks if any of the columns in "this" are mapped to multiple properties in cQuery. If so, // returns an error record about the duplicated slots internal ErrorLog.Record CheckForDuplicateFields(CellQuery cQuery, Cell sourceCell) { // slotMap stores the slots on the S-side and the // C-side properties that it maps to KeyToListMap <MemberProjectedSlot, int> slotMap = new KeyToListMap <MemberProjectedSlot, int>(ProjectedSlot.EqualityComparer); // Note that this does work for self-association. In the manager // employee example, ManagerId and EmployeeId from the SEmployee // table map to the two ends -- Manager.ManagerId and // Employee.EmployeeId in the C Space for (int i = 0; i < m_projectedSlots.Length; i++) { ProjectedSlot projectedSlot = m_projectedSlots[i]; MemberProjectedSlot slot = projectedSlot as MemberProjectedSlot; Debug.Assert(slot != null, "All slots for this method must be JoinTreeSlots"); slotMap.Add(slot, i); } StringBuilder builder = null; // Now determine the entries that have more than one integer per slot bool isErrorSituation = false; foreach (MemberProjectedSlot slot in slotMap.Keys) { ReadOnlyCollection <int> indexes = slotMap.ListForKey(slot); Debug.Assert(indexes.Count >= 1, "Each slot must have one index at least"); if (indexes.Count > 1 && cQuery.AreSlotsEquivalentViaRefConstraints(indexes) == false) { // The column is mapped to more than one property and it // failed the "association corresponds to referential // constraints" check isErrorSituation = true; if (builder == null) { builder = new StringBuilder(System.Data.Entity.Strings.ViewGen_Duplicate_CProperties(Extent.Name)); builder.AppendLine(); } StringBuilder tmpBuilder = new StringBuilder(); for (int i = 0; i < indexes.Count; i++) { int index = indexes[i]; if (i != 0) { tmpBuilder.Append(", "); } // The slot must be a JoinTreeSlot. If it isn't it is an internal error MemberProjectedSlot cSlot = (MemberProjectedSlot)cQuery.m_projectedSlots[index]; tmpBuilder.Append(cSlot.ToUserString()); } builder.AppendLine(Strings.ViewGen_Duplicate_CProperties_IsMapped(slot.ToUserString(), tmpBuilder.ToString())); } } if (false == isErrorSituation) { return(null); } ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.DuplicateCPropertiesMapped, builder.ToString(), sourceCell, String.Empty); return(record); }
// effects: returns the index at which this slot appears in the projection // or -1 if it is not projected internal int GetProjectedPosition(MemberProjectedSlot slot) { for (var i = 0; i < m_projectedSlots.Length; i++) { if (ProjectedSlot.EqualityComparer.Equals(slot, m_projectedSlots[i])) { return i; } } return -1; }
/// <summary> /// Creates a complete member restriction with the meaning "<paramref name="slot"/> in <paramref name="values"/>". /// </summary> /// <param name="possibleValues">all the values that the <paramref name="slot"/> can take</param> protected MemberRestriction(MemberProjectedSlot slot, IEnumerable <Constant> values, IEnumerable <Constant> possibleValues) : this(slot, new Domain(values, possibleValues)) { Debug.Assert(possibleValues != null); }
/// <summary> /// Creates a complete member restriction with the meaning "<paramref name="slot"/> in <paramref name="values"/>". /// </summary> /// <param name="possibleValues">all the values that the <paramref name="slot"/> can take</param> protected MemberRestriction(MemberProjectedSlot slot, IEnumerable<Constant> values, IEnumerable<Constant> possibleValues) : this(slot, new Domain(values, possibleValues)) { Debug.Assert(possibleValues != null); }
// 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 bool TryGetDomainRestrictedByWhereClause(IEnumerable <Constant> domain, MemberProjectedSlot slot, CellQuery cellQuery, out CellConstantSet result) { var conditionsForSlot = cellQuery.GetConjunctsFromWhereClause() .Where(restriction => MemberPath.EqualityComparer.Equals(restriction.RestrictedMemberSlot.MemberPath, slot.MemberPath)) .Select(restriction => new CellConstantSet(restriction.Domain.Values, Constant.EqualityComparer)); //Debug.Assert(!conditionsForSlot.Skip(1).Any(), "More than one Clause with the same path"); if (!conditionsForSlot.Any()) { // If the slot was not mentioned in the query return the domain without restricting it result = new CellConstantSet(domain); return(false); } // Now get all the possible values from domain and conditionValues CellConstantSet possibleValues = DeterminePossibleValues(conditionsForSlot.SelectMany(m => m.Select(c => c)), domain); Domain restrictedDomain = new Domain(domain, possibleValues); foreach (var conditionValues in conditionsForSlot) { // Domain derived from Edm-Type INTERSECTED with Conditions restrictedDomain = restrictedDomain.Intersect(new Domain(conditionValues, possibleValues)); } result = new CellConstantSet(restrictedDomain.Values, Constant.EqualityComparer); return(!domain.SequenceEqual(result)); }
/// <summary> /// Creates an incomplete member restriction with the meaning "<paramref name="slot"/> in <paramref name="values"/>". /// </summary> protected MemberRestriction(MemberProjectedSlot slot, IEnumerable <Constant> values) { m_restrictedMemberSlot = slot; m_domain = new Domain(values, values); }