private bool PerformSingleCellChecks() { int count = this.m_errorLog.Count; foreach (Cell cell in this.m_cells) { ErrorLog.Record record1 = cell.SQuery.CheckForDuplicateFields(cell.CQuery, cell); if (record1 != null) { this.m_errorLog.AddEntry(record1); } ErrorLog.Record record2 = cell.CQuery.VerifyKeysPresent(cell, new Func <object, object, string>(Strings.ViewGen_EntitySetKey_Missing), new Func <object, object, object, string>(Strings.ViewGen_AssociationSetKey_Missing), ViewGenErrorCode.KeyNotMappedForCSideExtent); if (record2 != null) { this.m_errorLog.AddEntry(record2); } ErrorLog.Record record3 = cell.SQuery.VerifyKeysPresent(cell, new Func <object, object, string>(Strings.ViewGen_TableKey_Missing), (Func <object, object, object, string>)null, ViewGenErrorCode.KeyNotMappedForTable); if (record3 != null) { this.m_errorLog.AddEntry(record3); } ErrorLog.Record record4 = cell.CQuery.CheckForProjectedNotNullSlots(cell, this.m_cells.Where <Cell>((Func <Cell, bool>)(c => c.SQuery.Extent is AssociationSet))); if (record4 != null) { this.m_errorLog.AddEntry(record4); } ErrorLog.Record record5 = cell.SQuery.CheckForProjectedNotNullSlots(cell, this.m_cells.Where <Cell>((Func <Cell, bool>)(c => c.CQuery.Extent is AssociationSet))); if (record5 != null) { this.m_errorLog.AddEntry(record5); } } return(this.m_errorLog.Count == count); }
// <summary> // Checks that if a DISTINCT operator exists between some C-Extent and S-Extent, there are no additional // mapping fragments between that C-Extent and S-Extent. // We need to enforce this because DISTINCT is not understood by viewgen machinery, and two fragments may be merged // despite one of them having DISTINCT. // </summary> private bool CheckCellsWithDistinctFlag() { var errorLogSize = m_errorLog.Count; foreach (var cell in m_cells) { if (cell.SQuery.SelectDistinctFlag == CellQuery.SelectDistinct.Yes) { var cExtent = cell.CQuery.Extent; var sExtent = cell.SQuery.Extent; //There should be no other fragments mapping cExtent to sExtent var mapepdFragments = m_cells.Where(otherCell => otherCell != cell) .Where( otherCell => otherCell.CQuery.Extent == cExtent && otherCell.SQuery.Extent == sExtent); if (mapepdFragments.Any()) { var cellsToReport = Enumerable.Repeat(cell, 1).Union(mapepdFragments); var record = new ErrorLog.Record( ViewGenErrorCode.MultipleFragmentsBetweenCandSExtentWithDistinct, Strings.Viewgen_MultipleFragmentsBetweenCandSExtentWithDistinct(cExtent.Name, sExtent.Name), cellsToReport, String.Empty); m_errorLog.AddEntry(record); } } } return(m_errorLog.Count == errorLogSize); }
// requires: constraint.ChildColumns form a key in // constraint.ChildTable (actually they should subsume the primary key) private void GuaranteeForeignKeyConstraintInCSpace(QueryRewriter childRewriter, QueryRewriter parentRewriter, ErrorLog errorLog, ConfigViewGenerator config) { ViewgenContext childContext = childRewriter.ViewgenContext; ViewgenContext parentContext = parentRewriter.ViewgenContext; CellTreeNode cNode = childRewriter.BasicView; CellTreeNode pNode = parentRewriter.BasicView; FragmentQueryProcessor qp = FragmentQueryProcessor.Merge(childContext.RightFragmentQP, parentContext.RightFragmentQP); bool cImpliesP = qp.IsContainedIn(cNode.RightFragmentQuery, pNode.RightFragmentQuery); if (false == cImpliesP) { // Foreign key constraint not being ensured in C-space string childExtents = LeftCellWrapper.GetExtentListAsUserString(cNode.GetLeaves()); string parentExtents = LeftCellWrapper.GetExtentListAsUserString(pNode.GetLeaves()); string message = System.Data.Entity.Strings.ViewGen_Foreign_Key_Not_Guaranteed_InCSpace( ToUserString()); // Add all wrappers into allWrappers Set <LeftCellWrapper> allWrappers = new Set <LeftCellWrapper>(pNode.GetLeaves()); allWrappers.AddRange(cNode.GetLeaves()); ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.ForeignKeyNotGuaranteedInCSpace, message, allWrappers, String.Empty); errorLog.AddEntry(record); } }
// requires: constraint.ChildColumns form a key in // constraint.ChildTable (actually they should subsume the primary key) private void GuaranteeForeignKeyConstraintInCSpace( QueryRewriter childRewriter, QueryRewriter parentRewriter, ErrorLog errorLog) { var childContext = childRewriter.ViewgenContext; var parentContext = parentRewriter.ViewgenContext; var cNode = childRewriter.BasicView; var pNode = parentRewriter.BasicView; var qp = FragmentQueryProcessor.Merge(childContext.RightFragmentQP, parentContext.RightFragmentQP); var cImpliesP = qp.IsContainedIn(cNode.RightFragmentQuery, pNode.RightFragmentQuery); if (false == cImpliesP) { // Foreign key constraint not being ensured in C-space var childExtents = LeftCellWrapper.GetExtentListAsUserString(cNode.GetLeaves()); var parentExtents = LeftCellWrapper.GetExtentListAsUserString(pNode.GetLeaves()); var message = Strings.ViewGen_Foreign_Key_Not_Guaranteed_InCSpace( ToUserString()); // Add all wrappers into allWrappers var allWrappers = new Set <LeftCellWrapper>(pNode.GetLeaves()); allWrappers.AddRange(cNode.GetLeaves()); var record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyNotGuaranteedInCSpace, message, allWrappers, String.Empty); errorLog.AddEntry(record); } }
private bool CheckConstraintWhenParentChildMapped( Cell cell, ErrorLog errorLog, AssociationEndMember parentEnd, ConfigViewGenerator config) { bool flag = true; if (parentEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) { ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyUpperBoundMustBeOne, Strings.ViewGen_Foreign_Key_UpperBound_MustBeOne((object)this.ToUserString(), (object)cell.CQuery.Extent.Name, (object)parentEnd.Name), cell, string.Empty); errorLog.AddEntry(record); flag = false; } if (!MemberPath.AreAllMembersNullable(this.ChildColumns) && parentEnd.RelationshipMultiplicity != RelationshipMultiplicity.One) { ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyLowerBoundMustBeOne, Strings.ViewGen_Foreign_Key_LowerBound_MustBeOne((object)this.ToUserString(), (object)cell.CQuery.Extent.Name, (object)parentEnd.Name), cell, string.Empty); errorLog.AddEntry(record); flag = false; } if (config.IsNormalTracing && flag) { Trace.WriteLine("Foreign key mapped to relationship " + cell.CQuery.Extent.Name); } return(flag); }
// effects: Given the foreign key constraint, checks if the // constraint.ParentColumns are mapped to the entity set E'e keys in // C-space where E corresponds to the entity set corresponding to end // Returns true iff such a mapping exists in cell private bool CheckParentColumnsForForeignKey( Cell cell, IEnumerable <Cell> cells, AssociationEndMember parentEnd, ref List <ErrorLog.Record> errorList) { // The child columns are mapped to some end of cell.CQuery.Extent. ParentColumns // must correspond to the EntitySet for this end var relationSet = (AssociationSet)cell.CQuery.Extent; var endSet = MetadataHelper.GetEntitySetAtEnd(relationSet, parentEnd); // Check if the ParentColumns are mapped to endSet's keys // Find the entity set that they map to - if any var entitySet = FindEntitySetForColumnsMappedToEntityKeys(cells, ParentColumns); if (entitySet == null || endSet.Equals(entitySet) == false) { if (errorList == null) //lazily initialize only if there is an error { errorList = new List <ErrorLog.Record>(); } // childColumns are mapped to parentEnd but ParentColumns are not mapped to the end // corresponding to the parentEnd -- this is an error var message = Strings.ViewGen_Foreign_Key_ParentTable_NotMappedToEnd( ToUserString(), ChildTable.Name, cell.CQuery.Extent.Name, parentEnd.Name, ParentTable.Name, endSet.Name); var record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyParentTableNotMappedToEnd, message, cell, String.Empty); errorList.Add(record); return(false); } return(true); }
// effects: constructor that allows single mapping error internal InternalMappingException(string message, ErrorLog.Record record) : base(message) { EntityUtil.CheckArgumentNull(record, "record"); m_errorLog = new ErrorLog(); m_errorLog.AddEntry(record); }
// effects: constructor that allows single mapping error internal InternalMappingException(string message, ErrorLog.Record record) : base(message) { DebugCheck.NotNull(record); m_errorLog = new ErrorLog(); m_errorLog.AddEntry(record); }
internal static void ThrowMappingException(ErrorLog.Record errorRecord, ConfigViewGenerator config) { InternalMappingException exception = new InternalMappingException(errorRecord.ToUserString(), errorRecord); if (config.IsNormalTracing) { exception.ErrorLog.PrintTrace(); } throw exception; }
private static ErrorLog EnsureAllCSpaceContainerSetsAreMapped( IEnumerable <Cell> cells, EntityContainerMapping containerMapping) { Set <EntitySetBase> set = new Set <EntitySetBase>(); EntityContainer entityContainer = (EntityContainer)null; foreach (Cell cell in cells) { set.Add(cell.CQuery.Extent); string sourceLocation = cell.CellLabel.SourceLocation; entityContainer = cell.CQuery.Extent.EntityContainer; } List <EntitySetBase> entitySetBaseList = new List <EntitySetBase>(); foreach (EntitySetBase baseEntitySet in entityContainer.BaseEntitySets) { if (!set.Contains(baseEntitySet) && !containerMapping.HasQueryViewForSetMap(baseEntitySet.Name)) { AssociationSet associationSet = baseEntitySet as AssociationSet; if (associationSet == null || !associationSet.ElementType.IsForeignKey) { entitySetBaseList.Add(baseEntitySet); } } } ErrorLog errorLog = new ErrorLog(); if (entitySetBaseList.Count > 0) { StringBuilder stringBuilder = new StringBuilder(); bool flag = true; foreach (EntitySetBase entitySetBase in entitySetBaseList) { if (!flag) { stringBuilder.Append(", "); } flag = false; stringBuilder.Append(entitySetBase.Name); } string message = Strings.ViewGen_Missing_Set_Mapping((object)stringBuilder); int num = -1; foreach (Cell cell in cells) { if (num == -1 || cell.CellLabel.StartLineNumber < num) { num = cell.CellLabel.StartLineNumber; } } ErrorLog.Record record = new ErrorLog.Record(new EdmSchemaError(message, 3027, EdmSchemaErrorSeverity.Error, containerMapping.SourceLocation, containerMapping.StartLineNumber, containerMapping.StartLinePosition, (Exception)null)); errorLog.AddEntry(record); } return(errorLog); }
internal void CheckConstraint( Set <Cell> cells, QueryRewriter childRewriter, QueryRewriter parentRewriter, ErrorLog errorLog, ConfigViewGenerator config) { if (!this.IsConstraintRelevantForCells((IEnumerable <Cell>)cells)) { return; } if (config.IsNormalTracing) { Trace.WriteLine(string.Empty); Trace.WriteLine(string.Empty); Trace.Write("Checking: "); Trace.WriteLine((object)this); } if (childRewriter == null && parentRewriter == null) { return; } if (childRewriter == null) { ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyMissingTableMapping, Strings.ViewGen_Foreign_Key_Missing_Table_Mapping((object)this.ToUserString(), (object)this.ChildTable.Name), (IEnumerable <LeftCellWrapper>)parentRewriter.UsedCells, string.Empty); errorLog.AddEntry(record); } else if (parentRewriter == null) { ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyMissingTableMapping, Strings.ViewGen_Foreign_Key_Missing_Table_Mapping((object)this.ToUserString(), (object)this.ParentTable.Name), (IEnumerable <LeftCellWrapper>)childRewriter.UsedCells, string.Empty); errorLog.AddEntry(record); } else { if (this.CheckIfConstraintMappedToForeignKeyAssociation(childRewriter, parentRewriter, cells)) { return; } int count = errorLog.Count; if (this.IsForeignKeySuperSetOfPrimaryKeyInChildTable()) { this.GuaranteeForeignKeyConstraintInCSpace(childRewriter, parentRewriter, errorLog); } else { this.GuaranteeMappedRelationshipForForeignKey(childRewriter, parentRewriter, (IEnumerable <Cell>)cells, errorLog, config); } if (count != errorLog.Count) { return; } this.CheckForeignKeyColumnOrder(cells, errorLog); } }
// effects: Check for problems in each cell that are not detected by the // "C-constraints-imply-S-constraints" principle. If the check fails, // adds relevant error info to m_errorLog and returns false. Else // retrns true private bool PerformSingleCellChecks() { int errorLogSize = m_errorLog.Count; foreach (Cell cell in m_cells) { // Check for duplication of element in a single cell name1, name2 // -> name Could be done by implication but that would require // setting self-inclusion constraints etc That seems unnecessary // We need this check only for the C side. if we map cname1 // and cmane2 to sname, that is a problem. But mapping sname1 // and sname2 to cname is ok ErrorLog.Record error = cell.SQuery.CheckForDuplicateFields(cell.CQuery, cell); if (error != null) { m_errorLog.AddEntry(error); } // Check that the EntityKey and the Table key are mapped // (Key for association is all ends) error = cell.CQuery.VerifyKeysPresent(cell, Strings.ViewGen_EntitySetKey_Missing, Strings.ViewGen_AssociationSetKey_Missing, ViewGenErrorCode.KeyNotMappedForCSideExtent); if (error != null) { m_errorLog.AddEntry(error); } error = cell.SQuery.VerifyKeysPresent(cell, Strings.ViewGen_TableKey_Missing, null, ViewGenErrorCode.KeyNotMappedForTable); if (error != null) { m_errorLog.AddEntry(error); } // Check that if any side has a not-null constraint -- if so, // we must project that slot error = cell.CQuery.CheckForProjectedNotNullSlots(cell, m_cells.Where(c => c.SQuery.Extent is AssociationSet)); if (error != null) { m_errorLog.AddEntry(error); } error = cell.SQuery.CheckForProjectedNotNullSlots(cell, m_cells.Where(c => c.CQuery.Extent is AssociationSet)); if (error != null) { m_errorLog.AddEntry(error); } } return(m_errorLog.Count == errorLogSize); }
private void AddUnrecoverableAttributesError( IEnumerable <MemberPath> attributes, BoolExpression domainAddedWhereClause, ErrorLog errorLog) { StringBuilder builder = new StringBuilder(); string str = StringUtil.FormatInvariant("{0}", (object)this._extentPath); string viewGenExtent = Strings.ViewGen_Extent; string commaSeparatedString = StringUtil.ToCommaSeparatedString((IEnumerable)QueryRewriter.GetTypeBasedMemberPathList(attributes)); builder.AppendLine(Strings.ViewGen_Cannot_Recover_Attributes((object)commaSeparatedString, (object)viewGenExtent, (object)str)); RewritingValidator.EntityConfigurationToUserString(domainAddedWhereClause, builder); ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.AttributesUnrecoverable, builder.ToString(), (IEnumerable <LeftCellWrapper>) this._context.AllWrappersForExtent, string.Empty); errorLog.AddEntry(record); }
// requires: IsForeignKeySuperSetOfPrimaryKeyInChildTable() is false // effects: Given that both the ChildColumns in this and the // primaryKey of ChildTable are mapped. Return true iff no error occurred private bool CheckConstraintWhenParentChildMapped( Cell cell, ErrorLog errorLog, AssociationEndMember parentEnd, ConfigViewGenerator config) { var ok = true; // The foreign key constraint has been mapped to a // relationship. Check if the multiplicities are consistent // If all columns in the child table (corresponding to // the constraint) are nullable, the parent end can be // 0..1 or 1..1. Else if must be 1..1 if (parentEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) { // Parent should at most one since we are talking // about foreign keys here var message = Strings.ViewGen_Foreign_Key_UpperBound_MustBeOne( ToUserString(), cell.CQuery.Extent.Name, parentEnd.Name); var record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyUpperBoundMustBeOne, message, cell, String.Empty); errorLog.AddEntry(record); ok = false; } if (MemberPath.AreAllMembersNullable(ChildColumns) == false && parentEnd.RelationshipMultiplicity != RelationshipMultiplicity.One) { // Some column in the constraint in the child table // is non-nullable and lower bound is not 1 var message = Strings.ViewGen_Foreign_Key_LowerBound_MustBeOne( ToUserString(), cell.CQuery.Extent.Name, parentEnd.Name); var record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyLowerBoundMustBeOne, message, cell, String.Empty); errorLog.AddEntry(record); ok = false; } if (config.IsNormalTracing && ok) { Trace.WriteLine("Foreign key mapped to relationship " + cell.CQuery.Extent.Name); } return(ok); }
/// <summary> /// Checks: /// 1) Concurrency token is not defined in this Extent's ElementTypes' derived types /// 2) Members with concurrency token should not have conditions specified /// </summary> private void CheckConcurrencyControlTokens() { Debug.Assert(m_viewTarget == ViewTarget.QueryView); // Get the token fields for this extent var extentType = m_extent.ElementType; var tokenMembers = MetadataHelper.GetConcurrencyMembersForTypeHierarchy(extentType, m_edmItemCollection); var tokenPaths = new Set <MemberPath>(MemberPath.EqualityComparer); foreach (var tokenMember in tokenMembers) { if (!tokenMember.DeclaringType.IsAssignableFrom(extentType)) { var message = Strings.ViewGen_Concurrency_Derived_Class(tokenMember.Name, tokenMember.DeclaringType.Name, m_extent); var record = new ErrorLog.Record(ViewGenErrorCode.ConcurrencyDerivedClass, message, m_cellWrappers, String.Empty); ExceptionHelpers.ThrowMappingException(record, m_config); } tokenPaths.Add(new MemberPath(m_extent, tokenMember)); } if (tokenMembers.Count > 0) { foreach (var wrapper in m_cellWrappers) { var conditionMembers = new Set <MemberPath>( wrapper.OnlyInputCell.CQuery.WhereClause.MemberRestrictions.Select(oneOf => oneOf.RestrictedMemberSlot.MemberPath), MemberPath.EqualityComparer); conditionMembers.Intersect(tokenPaths); if (conditionMembers.Count > 0) { // There is a condition on concurrency tokens. Throw an exception. var builder = new StringBuilder(); builder.AppendLine( Strings.ViewGen_Concurrency_Invalid_Condition( MemberPath.PropertiesToUserString(conditionMembers, false), m_extent.Name)); var record = new ErrorLog.Record( ViewGenErrorCode.ConcurrencyTokenHasCondition, builder.ToString(), new[] { wrapper }, String.Empty); ExceptionHelpers.ThrowMappingException(record, m_config); } } } }
private bool CheckParentColumnsForForeignKey( Cell cell, IEnumerable <Cell> cells, AssociationEndMember parentEnd, ref List <ErrorLog.Record> errorList) { EntitySet entitySetAtEnd = MetadataHelper.GetEntitySetAtEnd((AssociationSet)cell.CQuery.Extent, parentEnd); if (ForeignConstraint.FindEntitySetForColumnsMappedToEntityKeys(cells, this.ParentColumns).Contains(entitySetAtEnd)) { return(true); } if (errorList == null) { errorList = new List <ErrorLog.Record>(); } ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyParentTableNotMappedToEnd, Strings.ViewGen_Foreign_Key_ParentTable_NotMappedToEnd((object)this.ToUserString(), (object)this.ChildTable.Name, (object)cell.CQuery.Extent.Name, (object)parentEnd.Name, (object)this.ParentTable.Name, (object)entitySetAtEnd.Name), cell, string.Empty); errorList.Add(record); return(false); }
internal override bool VisitLeaf(LeafCellTreeNode node, bool dummy) { // make sure all projected attributes in wrapper correspond exactly to those in node var thisQuery = m_wrapper.RightCellQuery; var thatQuery = node.LeftCellWrapper.RightCellQuery; var collidingColumns = new List <MemberPath>(); if (thisQuery != thatQuery) { for (var i = 0; i < thisQuery.NumProjectedSlots; i++) { var thisSlot = thisQuery.ProjectedSlotAt(i) as MemberProjectedSlot; if (thisSlot != null) { var thatSlot = thatQuery.ProjectedSlotAt(i) as MemberProjectedSlot; if (thatSlot != null) { var tableMember = m_viewgenContext.MemberMaps.ProjectedSlotMap[i]; if (!tableMember.IsPartOfKey) { if (!MemberPath.EqualityComparer.Equals(thisSlot.MemberPath, thatSlot.MemberPath)) { collidingColumns.Add(tableMember); } } } } } } if (collidingColumns.Count > 0) { var columnsString = MemberPath.PropertiesToUserString(collidingColumns, false); var message = Strings.ViewGen_NonKeyProjectedWithOverlappingPartitions(columnsString); var record = new ErrorLog.Record( ViewGenErrorCode.NonKeyProjectedWithOverlappingPartitions, message, new[] { m_wrapper, node.LeftCellWrapper }, String.Empty); m_errorLog.AddEntry(record); } return(true); }
private void GuaranteeForeignKeyConstraintInCSpace( QueryRewriter childRewriter, QueryRewriter parentRewriter, ErrorLog errorLog) { ViewgenContext viewgenContext1 = childRewriter.ViewgenContext; ViewgenContext viewgenContext2 = parentRewriter.ViewgenContext; CellTreeNode basicView1 = childRewriter.BasicView; CellTreeNode basicView2 = parentRewriter.BasicView; if (FragmentQueryProcessor.Merge(viewgenContext1.RightFragmentQP, viewgenContext2.RightFragmentQP).IsContainedIn(basicView1.RightFragmentQuery, basicView2.RightFragmentQuery)) { return; } LeftCellWrapper.GetExtentListAsUserString((IEnumerable <LeftCellWrapper>)basicView1.GetLeaves()); LeftCellWrapper.GetExtentListAsUserString((IEnumerable <LeftCellWrapper>)basicView2.GetLeaves()); string message = Strings.ViewGen_Foreign_Key_Not_Guaranteed_InCSpace((object)this.ToUserString()); Set <LeftCellWrapper> set = new Set <LeftCellWrapper>((IEnumerable <LeftCellWrapper>)basicView2.GetLeaves()); set.AddRange((IEnumerable <LeftCellWrapper>)basicView1.GetLeaves()); ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyNotGuaranteedInCSpace, message, (IEnumerable <LeftCellWrapper>)set, string.Empty); errorLog.AddEntry(record); }
// requires: all columns in constraint.ParentColumns and // constraint.ChildColumns must have been mapped in some cell in m_cellGroup // effects: Given the foreign key constraint, checks if the // constraint.ChildColumns are mapped to the constraint.ParentColumns // in m_cellGroup in the right oder. If not, adds an error to m_errorLog and returns // false. Else returns true private bool CheckForeignKeyColumnOrder(Set <Cell> cells, ErrorLog errorLog) { // Go through every cell and find the cells that are relevant to // parent and those that are relevant to child // Then for each cell pair (parent, child) make sure that the // projected foreign keys columns in C-space are aligned var parentCells = new List <Cell>(); var childCells = new List <Cell>(); foreach (var cell in cells) { if (cell.SQuery.Extent.Equals(ChildTable)) { childCells.Add(cell); } if (cell.SQuery.Extent.Equals(ParentTable)) { parentCells.Add(cell); } } // Make sure that all child cells and parent cells align on // the columns, i.e., for each DISTINCT pair C and P, get the columns // on the S-side. Then get the corresponding fields on the // C-side. The fields on the C-side should match var foundParentCell = false; var foundChildCell = false; foreach (var childCell in childCells) { var allChildSlotNums = GetSlotNumsForColumns(childCell, ChildColumns); if (allChildSlotNums.Count == 0) { // slots in present in S-side, ignore continue; } List <MemberPath> childPaths = null; List <MemberPath> parentPaths = null; Cell errorParentCell = null; foreach (var childSlotNums in allChildSlotNums) { foundChildCell = true; // Get the fields on the C-side childPaths = new List <MemberPath>(childSlotNums.Count); foreach (var childSlotNum in childSlotNums) { // Initial slots only have JoinTreeSlots var childSlot = (MemberProjectedSlot)childCell.CQuery.ProjectedSlotAt(childSlotNum); Debug.Assert(childSlot != null); childPaths.Add(childSlot.MemberPath); } foreach (var parentCell in parentCells) { var allParentSlotNums = GetSlotNumsForColumns(parentCell, ParentColumns); if (allParentSlotNums.Count == 0) { // * Parent and child cell are the same - we do not // need to check since we want to check the foreign // key constraint mapping across cells // * Some slots not in present in S-side, ignore continue; } foreach (var parentSlotNums in allParentSlotNums) { foundParentCell = true; parentPaths = new List <MemberPath>(parentSlotNums.Count); foreach (var parentSlotNum in parentSlotNums) { var parentSlot = (MemberProjectedSlot)parentCell.CQuery.ProjectedSlotAt(parentSlotNum); Debug.Assert(parentSlot != null); parentPaths.Add(parentSlot.MemberPath); } // Make sure that the last member of each of these is the same // or the paths are essentially equivalent via referential constraints // We need to check that the last member is essentially the same because it could // be a regular scenario where aid is mapped to PersonAddress and Address - there // is no ref constraint. So when projected into C-Space, we will get Address.aid // and PersonAddress.Address.aid if (childPaths.Count == parentPaths.Count) { var notAllPathsMatched = false; for (var i = 0; i < childPaths.Count && !notAllPathsMatched; i++) { var parentPath = parentPaths[i]; var childPath = childPaths[i]; if (!parentPath.LeafEdmMember.Equals(childPath.LeafEdmMember)) //Child path did not match { if (parentPath.IsEquivalentViaRefConstraint(childPath)) { //Specifying the referential constraint once in the C space should be enough. //This is the only way possible today. //We might be able to derive more knowledge by using boolean logic return(true); } else { notAllPathsMatched = true; } } } if (!notAllPathsMatched) { return(true); //all childPaths matched parentPaths } else { //If not this one, some other Parent Cell may match. errorParentCell = parentCell; } } } } //foreach parentCell } //If execution is at this point, no parent cell's end has matched (otherwise it would have returned true) Debug.Assert(childPaths != null, "child paths should be set"); Debug.Assert(parentPaths != null, "parent paths should be set"); Debug.Assert(errorParentCell != null, "errorParentCell should be set"); var message = Strings.ViewGen_Foreign_Key_ColumnOrder_Incorrect( ToUserString(), MemberPath.PropertiesToUserString(ChildColumns, false), ChildTable.Name, MemberPath.PropertiesToUserString(childPaths, false), childCell.CQuery.Extent.Name, MemberPath.PropertiesToUserString(ParentColumns, false), ParentTable.Name, MemberPath.PropertiesToUserString(parentPaths, false), errorParentCell.CQuery.Extent.Name); var record = new ErrorLog.Record( ViewGenErrorCode.ForeignKeyColumnOrderIncorrect, message, new[] { errorParentCell, childCell }, String.Empty); errorLog.AddEntry(record); return(false); } Debug.Assert(foundParentCell, "Some cell that mapped the parent's key must be present!"); Debug.Assert( foundChildCell == true, "Some cell that mapped the child's foreign key must be present according to the requires clause!"); return(true); }
// effects: Ensures that there is a relationship mapped into the C-space for some cell in m_cellGroup. Else // adds an error to errorLog private void GuaranteeMappedRelationshipForForeignKey( QueryRewriter childRewriter, QueryRewriter parentRewriter, IEnumerable <Cell> cells, ErrorLog errorLog, ConfigViewGenerator config) { var childContext = childRewriter.ViewgenContext; var parentContext = parentRewriter.ViewgenContext; // Find a cell where this foreign key is mapped as a relationship var prefix = new MemberPath(ChildTable); var primaryKey = ExtentKey.GetPrimaryKeyForEntityType(prefix, ChildTable.ElementType); var primaryKeyFields = primaryKey.KeyFields; var foundCell = false; var foundValidParentColumnsForForeignKey = false; //we need to find only one, dont error on any one check being false List <ErrorLog.Record> errorListForInvalidParentColumnsForForeignKey = null; foreach (var cell in cells) { if (cell.SQuery.Extent.Equals(ChildTable) == false) { continue; } // The childtable is mapped to a relationship in the C-space in cell // Check that all the columns of the foreign key and the primary key in the child table are mapped to some // property in the C-space var parentEnd = GetRelationEndForColumns(cell, ChildColumns); if (parentEnd != null && CheckParentColumnsForForeignKey(cell, cells, parentEnd, ref errorListForInvalidParentColumnsForForeignKey) == false) { // Not an error unless we find no valid case continue; } else { foundValidParentColumnsForForeignKey = true; } var childEnd = GetRelationEndForColumns(cell, primaryKeyFields); Debug.Assert( childEnd == null || parentEnd != childEnd, "Ends are same => PKey and child columns are same - code should gone to other method"); // Note: If both of them are not-null, they are mapped to the // same association set -- since we checked that particular cell if (childEnd != null && parentEnd != null && FindEntitySetForColumnsMappedToEntityKeys(cells, primaryKeyFields) != null) { foundCell = true; CheckConstraintWhenParentChildMapped(cell, errorLog, parentEnd, config); break; // Done processing for the foreign key - either it was mapped correctly or it was not } else if (parentEnd != null) { // At this point, we know cell corresponds to an association set var assocSet = (AssociationSet)cell.CQuery.Extent; var parentSet = MetadataHelper.GetEntitySetAtEnd(assocSet, parentEnd); foundCell = CheckConstraintWhenOnlyParentMapped(assocSet, parentEnd, childRewriter, parentRewriter); if (foundCell) { break; } } } //CheckParentColumnsForForeignKey has returned no matches, Error. if (!foundValidParentColumnsForForeignKey) { Debug.Assert( errorListForInvalidParentColumnsForForeignKey != null && errorListForInvalidParentColumnsForForeignKey.Count > 0); foreach (var errorRecord in errorListForInvalidParentColumnsForForeignKey) { errorLog.AddEntry(errorRecord); } return; } if (foundCell == false) { // No cell found -- Declare error var message = Strings.ViewGen_Foreign_Key_Missing_Relationship_Mapping(ToUserString()); IEnumerable <LeftCellWrapper> parentWrappers = GetWrappersFromContext(parentContext, ParentTable); IEnumerable <LeftCellWrapper> childWrappers = GetWrappersFromContext(childContext, ChildTable); var bothExtentWrappers = new Set <LeftCellWrapper>(parentWrappers); bothExtentWrappers.AddRange(childWrappers); var record = new ErrorLog.Record( ViewGenErrorCode.ForeignKeyMissingRelationshipMapping, message, bothExtentWrappers, String.Empty); errorLog.AddEntry(record); } }
private void GuaranteeMappedRelationshipForForeignKey( QueryRewriter childRewriter, QueryRewriter parentRewriter, IEnumerable <Cell> cells, ErrorLog errorLog, ConfigViewGenerator config) { ViewgenContext viewgenContext1 = childRewriter.ViewgenContext; ViewgenContext viewgenContext2 = parentRewriter.ViewgenContext; IEnumerable <MemberPath> keyFields = ExtentKey.GetPrimaryKeyForEntityType(new MemberPath((EntitySetBase)this.ChildTable), this.ChildTable.ElementType).KeyFields; bool flag1 = false; bool flag2 = false; List <ErrorLog.Record> errorList = (List <ErrorLog.Record>)null; foreach (Cell cell in cells) { if (cell.SQuery.Extent.Equals((object)this.ChildTable)) { AssociationEndMember relationEndForColumns = ForeignConstraint.GetRelationEndForColumns(cell, this.ChildColumns); if (relationEndForColumns == null || this.CheckParentColumnsForForeignKey(cell, cells, relationEndForColumns, ref errorList)) { flag2 = true; if (ForeignConstraint.GetRelationEndForColumns(cell, keyFields) != null && relationEndForColumns != null && ForeignConstraint.FindEntitySetForColumnsMappedToEntityKeys(cells, keyFields).Count > 0) { flag1 = true; this.CheckConstraintWhenParentChildMapped(cell, errorLog, relationEndForColumns, config); break; } if (relationEndForColumns != null) { AssociationSet extent = (AssociationSet)cell.CQuery.Extent; MetadataHelper.GetEntitySetAtEnd(extent, relationEndForColumns); flag1 = ForeignConstraint.CheckConstraintWhenOnlyParentMapped(extent, relationEndForColumns, childRewriter, parentRewriter); if (flag1) { break; } } } } } if (!flag2) { foreach (ErrorLog.Record record in errorList) { errorLog.AddEntry(record); } } else { if (flag1) { return; } string message = Strings.ViewGen_Foreign_Key_Missing_Relationship_Mapping((object)this.ToUserString()); IEnumerable <LeftCellWrapper> wrappersFromContext1 = (IEnumerable <LeftCellWrapper>)ForeignConstraint.GetWrappersFromContext(viewgenContext2, (EntitySetBase)this.ParentTable); IEnumerable <LeftCellWrapper> wrappersFromContext2 = (IEnumerable <LeftCellWrapper>)ForeignConstraint.GetWrappersFromContext(viewgenContext1, (EntitySetBase)this.ChildTable); Set <LeftCellWrapper> set = new Set <LeftCellWrapper>(wrappersFromContext1); set.AddRange(wrappersFromContext2); ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyMissingRelationshipMapping, message, (IEnumerable <LeftCellWrapper>)set, string.Empty); errorLog.AddEntry(record); } }
// effects: Checks that this foreign key constraints for all the // tables are being ensured on the C-side as well. If not, adds // errors to the errorLog internal void CheckConstraint( Set <Cell> cells, QueryRewriter childRewriter, QueryRewriter parentRewriter, ErrorLog errorLog, ConfigViewGenerator config) { if (IsConstraintRelevantForCells(cells) == false) { // if the constraint does not deal with any cell in this group, ignore it return; } if (config.IsNormalTracing) { Trace.WriteLine(String.Empty); Trace.WriteLine(String.Empty); Trace.Write("Checking: "); Trace.WriteLine(this); } if (childRewriter == null && parentRewriter == null) { // Neither table is mapped - so we are fine return; } // If the child table has not been mapped, we used to say that we // are fine. However, if we have SPerson(pid) and SAddress(aid, // pid), where pid is an FK into SPerson, we are in trouble if // SAddress is not mapped - SPerson could get deleted. So we // check for it as well // if the parent table is not mapped, we also have a problem if (childRewriter == null) { var message = Strings.ViewGen_Foreign_Key_Missing_Table_Mapping( ToUserString(), ChildTable.Name); // Get the cells from the parent table var record = new ErrorLog.Record( ViewGenErrorCode.ForeignKeyMissingTableMapping, message, parentRewriter.UsedCells, String.Empty); errorLog.AddEntry(record); return; } if (parentRewriter == null) { var message = Strings.ViewGen_Foreign_Key_Missing_Table_Mapping( ToUserString(), ParentTable.Name); // Get the cells from the child table var record = new ErrorLog.Record( ViewGenErrorCode.ForeignKeyMissingTableMapping, message, childRewriter.UsedCells, String.Empty); errorLog.AddEntry(record); return; } // Note: we do not check if the parent columns correspond to the // table's keys - metadata checks for that //First check if the FK is covered by Foreign Key Association //If we find this, we don't need to check for independent associations. If user maps the Fk to both FK and independent associations, //the regular round tripping validation will catch the error. if (CheckIfConstraintMappedToForeignKeyAssociation(childRewriter, parentRewriter, cells)) { return; } // Check if the foreign key in the child table corresponds to the primary key, i.e., if // the foreign key (e.g., pid, pid2) is a superset of the actual key members (e.g., pid), it means // that the foreign key is also the primary key for this table -- so we can propagate the queries upto C-Space // rather than doing the cell check var initialErrorLogSize = errorLog.Count; if (IsForeignKeySuperSetOfPrimaryKeyInChildTable()) { GuaranteeForeignKeyConstraintInCSpace(childRewriter, parentRewriter, errorLog); } else { GuaranteeMappedRelationshipForForeignKey(childRewriter, parentRewriter, cells, errorLog, config); } if (initialErrorLogSize == errorLog.Count) { // Check if the order of columns in foreign key correponds to the // mappings in m_cellGroup, e.g., if <pid1, pid2> in SAddress is // a foreign key into <pid1, pid2> of the SPerson table, make // sure that this order is preserved through the mappings in m_cellGroup CheckForeignKeyColumnOrder(cells, errorLog); } }
// effects: Given a container, ensures that all entity/association // sets in container on the C-side have been mapped private static ErrorLog EnsureAllCSpaceContainerSetsAreMapped( IEnumerable <Cell> cells, StorageEntityContainerMapping containerMapping) { var mappedExtents = new Set <EntitySetBase>(); string mslFileLocation = null; EntityContainer container = null; // Determine the container and name of the file while determining // the set of mapped extents in the cells foreach (var cell in cells) { mappedExtents.Add(cell.CQuery.Extent); mslFileLocation = cell.CellLabel.SourceLocation; // All cells are from the same container container = cell.CQuery.Extent.EntityContainer; } Debug.Assert(container != null); var missingExtents = new List <EntitySetBase>(); // Go through all the extents in the container and determine // extents that are missing foreach (var extent in container.BaseEntitySets) { if (mappedExtents.Contains(extent) == false && !(containerMapping.HasQueryViewForSetMap(extent.Name))) { var associationSet = extent as AssociationSet; if (associationSet == null || !associationSet.ElementType.IsForeignKey) { missingExtents.Add(extent); } } } var errorLog = new ErrorLog(); // If any extent is not mapped, add an error if (missingExtents.Count > 0) { var extentBuilder = new StringBuilder(); var isFirst = true; foreach (var extent in missingExtents) { if (isFirst == false) { extentBuilder.Append(", "); } isFirst = false; extentBuilder.Append(extent.Name); } var message = Strings.ViewGen_Missing_Set_Mapping(extentBuilder); // Find the cell with smallest line number - so that we can // point to the beginning of the file var lowestLineNum = -1; Cell smallestCell = null; foreach (var cell in cells) { if (lowestLineNum == -1 || cell.CellLabel.StartLineNumber < lowestLineNum) { smallestCell = cell; lowestLineNum = cell.CellLabel.StartLineNumber; } } Debug.Assert(smallestCell != null && lowestLineNum >= 0); var edmSchemaError = new EdmSchemaError( message, (int)ViewGenErrorCode.MissingExtentMapping, EdmSchemaErrorSeverity.Error, containerMapping.SourceLocation, containerMapping.StartLineNumber, containerMapping.StartLinePosition, null); var record = new ErrorLog.Record(edmSchemaError); errorLog.AddEntry(record); } return(errorLog); }
private bool CheckForeignKeyColumnOrder(Set <Cell> cells, ErrorLog errorLog) { List <Cell> cellList1 = new List <Cell>(); List <Cell> cellList2 = new List <Cell>(); foreach (Cell cell in cells) { if (cell.SQuery.Extent.Equals((object)this.ChildTable)) { cellList2.Add(cell); } if (cell.SQuery.Extent.Equals((object)this.ParentTable)) { cellList1.Add(cell); } } foreach (Cell cell1 in cellList2) { List <List <int> > slotNumsForColumns1 = ForeignConstraint.GetSlotNumsForColumns(cell1, this.ChildColumns); if (slotNumsForColumns1.Count != 0) { List <MemberPath> memberPathList1 = (List <MemberPath>)null; List <MemberPath> memberPathList2 = (List <MemberPath>)null; Cell cell2 = (Cell)null; foreach (List <int> intList1 in slotNumsForColumns1) { memberPathList1 = new List <MemberPath>(intList1.Count); foreach (int slotNum in intList1) { MemberProjectedSlot memberProjectedSlot = (MemberProjectedSlot)cell1.CQuery.ProjectedSlotAt(slotNum); memberPathList1.Add(memberProjectedSlot.MemberPath); } foreach (Cell cell3 in cellList1) { List <List <int> > slotNumsForColumns2 = ForeignConstraint.GetSlotNumsForColumns(cell3, this.ParentColumns); if (slotNumsForColumns2.Count != 0) { foreach (List <int> intList2 in slotNumsForColumns2) { memberPathList2 = new List <MemberPath>(intList2.Count); foreach (int slotNum in intList2) { MemberProjectedSlot memberProjectedSlot = (MemberProjectedSlot)cell3.CQuery.ProjectedSlotAt(slotNum); memberPathList2.Add(memberProjectedSlot.MemberPath); } if (memberPathList1.Count == memberPathList2.Count) { bool flag = false; for (int index = 0; index < memberPathList1.Count && !flag; ++index) { MemberPath memberPath = memberPathList2[index]; MemberPath path1 = memberPathList1[index]; if (!memberPath.LeafEdmMember.Equals((object)path1.LeafEdmMember)) { if (memberPath.IsEquivalentViaRefConstraint(path1)) { return(true); } flag = true; } } if (!flag) { return(true); } cell2 = cell3; } } } } } ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyColumnOrderIncorrect, Strings.ViewGen_Foreign_Key_ColumnOrder_Incorrect((object)this.ToUserString(), (object)MemberPath.PropertiesToUserString(this.ChildColumns, false), (object)this.ChildTable.Name, (object)MemberPath.PropertiesToUserString((IEnumerable <MemberPath>)memberPathList1, false), (object)cell1.CQuery.Extent.Name, (object)MemberPath.PropertiesToUserString(this.ParentColumns, false), (object)this.ParentTable.Name, (object)MemberPath.PropertiesToUserString((IEnumerable <MemberPath>)memberPathList2, false), (object)cell2.CQuery.Extent.Name), (IEnumerable <Cell>) new Cell[2] { cell2, cell1 }, string.Empty); errorLog.AddEntry(record); return(false); } } return(true); }
private void EnsureConfigurationIsFullyMapped( MemberPath currentPath, BoolExpression currentWhereClause, HashSet <FragmentQuery> outputUsedViews, ErrorLog errorLog) { foreach (Constant domainValue in this.GetDomain(currentPath)) { if (domainValue != Constant.Undefined) { BoolExpression memberCondition = this.CreateMemberCondition(currentPath, domainValue); BoolExpression and = BoolExpression.CreateAnd(currentWhereClause, memberCondition); Tile <FragmentQuery> rewriting; if (!this.FindRewritingAndUsedViews((IEnumerable <MemberPath>) this._keyAttributes, and, outputUsedViews, out rewriting)) { if (!ErrorPatternMatcher.FindMappingErrors(this._context, this._domainMap, this._errorLog)) { StringBuilder builder = new StringBuilder(); string str = StringUtil.FormatInvariant("{0}", (object)this._extentPath); BoolExpression condition = rewriting.Query.Condition; condition.ExpensiveSimplify(); if (condition.RepresentsAllTypeConditions) { string viewGenExtent = Strings.ViewGen_Extent; builder.AppendLine(Strings.ViewGen_Cannot_Recover_Types((object)viewGenExtent, (object)str)); } else { string viewGenEntities = Strings.ViewGen_Entities; builder.AppendLine(Strings.ViewGen_Cannot_Disambiguate_MultiConstant((object)viewGenEntities, (object)str)); } RewritingValidator.EntityConfigurationToUserString(condition, builder); ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.AmbiguousMultiConstants, builder.ToString(), (IEnumerable <LeftCellWrapper>) this._context.AllWrappersForExtent, string.Empty); errorLog.AddEntry(record); } } else { TypeConstant typeConstant = domainValue as TypeConstant; if (typeConstant != null) { EdmType edmType = typeConstant.EdmType; List <MemberPath> list = QueryRewriter.GetNonConditionalScalarMembers(edmType, currentPath, this._domainMap).Union <MemberPath>(QueryRewriter.GetNonConditionalComplexMembers(edmType, currentPath, this._domainMap)).ToList <MemberPath>(); IEnumerable <MemberPath> notCoveredAttributes; if (list.Count > 0 && !this.FindRewritingAndUsedViews((IEnumerable <MemberPath>)list, and, outputUsedViews, out rewriting, out notCoveredAttributes)) { List <MemberPath> memberPathList = new List <MemberPath>(list.Where <MemberPath>((Func <MemberPath, bool>)(a => !a.IsPartOfKey))); this.AddUnrecoverableAttributesError(notCoveredAttributes, memberCondition, errorLog); } else { foreach (MemberPath conditionalComplexMember in QueryRewriter.GetConditionalComplexMembers(edmType, currentPath, this._domainMap)) { this.EnsureConfigurationIsFullyMapped(conditionalComplexMember, and, outputUsedViews, errorLog); } foreach (MemberPath conditionalScalarMember in QueryRewriter.GetConditionalScalarMembers(edmType, currentPath, this._domainMap)) { this.EnsureConfigurationIsFullyMapped(conditionalScalarMember, and, outputUsedViews, errorLog); } } } } } } }
internal InternalMappingException(string message, ErrorLog.Record record) : base(message) { this.m_errorLog = new ErrorLog(); this.m_errorLog.AddEntry(record); }