private static void GetTypesAndConditionForWrapper( LeftCellWrapper wrapper, out bool hasCondition, out List <EdmType> edmTypes) { hasCondition = false; edmTypes = new List <EdmType>(); foreach (Cell cell in wrapper.Cells) { foreach (MemberRestriction condition in cell.CQuery.Conditions) { foreach (Constant constant in condition.Domain.Values) { TypeConstant typeConstant = constant as TypeConstant; if (typeConstant != null) { edmTypes.Add(typeConstant.EdmType); } else { hasCondition = true; } } } } }
private bool TryMergeCellQueries( CellTreeOpType opType, ref CellTreeNode node1, CellTreeNode node2) { LeafCellTreeNode leafCellTreeNode1 = node1 as LeafCellTreeNode; LeafCellTreeNode leafCellTreeNode2 = node2 as LeafCellTreeNode; CellQuery mergedQuery1; CellQuery mergedQuery2; if (!CellTreeSimplifier.TryMergeTwoCellQueries(leafCellTreeNode1.LeftCellWrapper.RightCellQuery, leafCellTreeNode2.LeftCellWrapper.RightCellQuery, opType, out mergedQuery1) || !CellTreeSimplifier.TryMergeTwoCellQueries(leafCellTreeNode1.LeftCellWrapper.LeftCellQuery, leafCellTreeNode2.LeftCellWrapper.LeftCellQuery, opType, out mergedQuery2)) { return(false); } OpCellTreeNode opCellTreeNode = new OpCellTreeNode(this.m_viewgenContext, opType); opCellTreeNode.Add(node1); opCellTreeNode.Add(node2); if (opType != CellTreeOpType.FOJ) { ; } LeftCellWrapper cellWrapper = new LeftCellWrapper(this.m_viewgenContext.ViewTarget, opCellTreeNode.Attributes, opCellTreeNode.LeftFragmentQuery, mergedQuery2, mergedQuery1, this.m_viewgenContext.MemberMaps, leafCellTreeNode1.LeftCellWrapper.Cells.Concat <Cell>(leafCellTreeNode2.LeftCellWrapper.Cells)); node1 = (CellTreeNode) new LeafCellTreeNode(this.m_viewgenContext, cellWrapper, opCellTreeNode.RightFragmentQuery); return(true); }
/// <summary> /// When we are dealing with an update view, this method /// finds out if the given Table is mapped to different EntitySets /// </summary> private void MatchSplitErrors() { List <LeftCellWrapper> leftCellWrappers = m_viewgenContext.AllWrappersForExtent; //Check that the given Table is mapped to only one EntitySet (avoid AssociationSets) var nonAssociationWrappers = leftCellWrappers.Where(r => !(r.LeftExtent is AssociationSet) && !(r.RightCellQuery.Extent is AssociationSet)); if (m_viewgenContext.ViewTarget == ViewTarget.UpdateView && nonAssociationWrappers.Any()) { LeftCellWrapper firstLeftCWrapper = nonAssociationWrappers.First(); EntitySetBase rightExtent = firstLeftCWrapper.RightCellQuery.Extent; foreach (var leftCellWrapper in nonAssociationWrappers) { //!(leftCellWrapper.RightCellQuery.Extent is AssociationSet) && if (!leftCellWrapper.RightCellQuery.Extent.EdmEquals(rightExtent)) { //A Table may be mapped to two extents but the extents may be Equal (by some form of Refconstraint) if (!RightSideEqual(leftCellWrapper, firstLeftCWrapper)) { //Report Error m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternSplittingError, Strings.Viewgen_ErrorPattern_TableMappedToMultipleES(leftCellWrapper.LeftExtent.ToString(), leftCellWrapper.RightCellQuery.Extent.ToString(), rightExtent.ToString()), leftCellWrapper.Cells.First(), "")); } } } } }
private void MatchSplitErrors() { IEnumerable <LeftCellWrapper> source = this.m_viewgenContext.AllWrappersForExtent.Where <LeftCellWrapper>((Func <LeftCellWrapper, bool>)(r => { if (!(r.LeftExtent is AssociationSet)) { return(!(r.RightCellQuery.Extent is AssociationSet)); } return(false); })); if (this.m_viewgenContext.ViewTarget != ViewTarget.UpdateView || !source.Any <LeftCellWrapper>()) { return; } LeftCellWrapper wrapper2 = source.First <LeftCellWrapper>(); EntitySetBase extent = wrapper2.RightCellQuery.Extent; foreach (LeftCellWrapper wrapper1 in source) { if (!wrapper1.RightCellQuery.Extent.EdmEquals((MetadataItem)extent) && !this.RightSideEqual(wrapper1, wrapper2)) { this.m_errorLog.AddEntry(new ErrorLog.Record(ViewGenErrorCode.ErrorPatternSplittingError, Strings.Viewgen_ErrorPattern_TableMappedToMultipleES((object)wrapper1.LeftExtent.ToString(), (object)wrapper1.RightCellQuery.Extent.ToString(), (object)extent.ToString()), wrapper1.Cells.First <Cell>(), "")); } } }
// effects: Given the cells for the extent (extentCells) along with // the signatures (multiconstants + needed attributes) for this extent, generates // the left cell wrappers for it extent (viewTarget indicates whether // the view is for querying or update purposes // Modifies m_cellWrappers to contain this list private bool CreateLeftCellWrappers(IList <Cell> extentCells, ViewTarget viewTarget) { var alignedCells = AlignFields(extentCells, m_memberMaps.ProjectedSlotMap, viewTarget); Debug.Assert(alignedCells.Count == extentCells.Count, "Cell counts disagree"); // Go through all the cells and create cell wrappers that can be used for generating the view m_cellWrappers = new List <LeftCellWrapper>(); for (var i = 0; i < alignedCells.Count; i++) { var alignedCell = alignedCells[i]; var left = alignedCell.GetLeftQuery(viewTarget); var right = alignedCell.GetRightQuery(viewTarget); // Obtain the non-null projected slots into attributes var attributes = left.GetNonNullSlots(); var fromVariable = BoolExpression.CreateLiteral( new CellIdBoolean(m_identifiers, extentCells[i].CellNumber), m_memberMaps.LeftDomainMap); var leftFragmentQuery = FragmentQuery.Create(fromVariable, left); if (viewTarget == ViewTarget.UpdateView) { leftFragmentQuery = m_leftFragmentQP.CreateDerivedViewBySelectingConstantAttributes(leftFragmentQuery) ?? leftFragmentQuery; } var leftWrapper = new LeftCellWrapper( m_viewTarget, attributes, leftFragmentQuery, left, right, m_memberMaps, extentCells[i]); m_cellWrappers.Add(leftWrapper); } return(true); }
private bool RightSideEqual(LeftCellWrapper wrapper1, LeftCellWrapper wrapper2) { var rightFragmentQuery1 = CreateRightFragmentQuery(wrapper1); var rightFragmentQuery2 = CreateRightFragmentQuery(wrapper2); return(m_viewgenContext.RightFragmentQP.IsEquivalentTo(rightFragmentQuery1, rightFragmentQuery2)); }
// <summary> // Gets the types on the Edm side mapped in this fragment wrapper. // It also returns an out parameter indicating whether there were any C side conditions. // </summary> private static void GetTypesAndConditionForWrapper(LeftCellWrapper wrapper, out bool hasCondition, out List <EdmType> edmTypes) { hasCondition = false; edmTypes = new List <EdmType>(); //Figure out which type has no Cell mapped to it foreach (var cell in wrapper.Cells) { foreach (var restriction in cell.CQuery.Conditions) { foreach (var cellConst in restriction.Domain.Values) { //if there is a mapping to this type... var typeConst = cellConst as TypeConstant; if (typeConst != null) { edmTypes.Add(typeConst.EdmType); } else { hasCondition = true; } } } } }
// 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); } }
internal static BoolExpression PropagateCellConstantsToWhereClause( LeftCellWrapper wrapper, BoolExpression expression, Constant constant, MemberPath member, MemberMaps memberMaps) { MemberProjectedSlot mappedSlotForSmember = wrapper.GetCSideMappedSlotForSMember(member); if (mappedSlotForSmember == null) { return(expression); } NegatedConstant negatedConstant = constant as NegatedConstant; IEnumerable <Constant> domain = memberMaps.QueryDomainMap.GetDomain(mappedSlotForSmember.MemberPath); Set <Constant> set = new Set <Constant>(Constant.EqualityComparer); if (negatedConstant != null) { set.Unite(domain); set.Difference(negatedConstant.Elements); } else { set.Add(constant); } MemberRestriction memberRestriction = (MemberRestriction) new ScalarRestriction(mappedSlotForSmember.MemberPath, (IEnumerable <Constant>)set, domain); return(BoolExpression.CreateAnd(expression, BoolExpression.CreateLiteral((BoolLiteral)memberRestriction, memberMaps.QueryDomainMap))); }
internal static CellTreeNode TileToCellTree( Tile <FragmentQuery> tile, ViewgenContext context) { if (tile.OpKind == TileOpKind.Named) { FragmentQuery view = ((TileNamed <FragmentQuery>)tile).NamedQuery; LeftCellWrapper cellWrapper = context.AllWrappersForExtent.First <LeftCellWrapper>((Func <LeftCellWrapper, bool>)(w => w.FragmentQuery == view)); return((CellTreeNode) new LeafCellTreeNode(context, cellWrapper)); } CellTreeOpType opType; switch (tile.OpKind) { case TileOpKind.Union: opType = CellTreeOpType.Union; break; case TileOpKind.Join: opType = CellTreeOpType.IJ; break; case TileOpKind.AntiSemiJoin: opType = CellTreeOpType.LASJ; break; default: return((CellTreeNode)null); } return((CellTreeNode) new OpCellTreeNode(context, opType, new CellTreeNode[2] { QueryRewriter.TileToCellTree(tile.Arg1, context), QueryRewriter.TileToCellTree(tile.Arg2, context) })); }
internal static void CheckConstraints(CellTreeNode node, LeftCellWrapper wrapper, ViewgenContext context, ErrorLog errorLog) { DomainConstraintVisitor visitor = new DomainConstraintVisitor(wrapper, context, errorLog); node.Accept <bool, bool>(visitor, true); }
// 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); } }
// requires: node1 and node2 are two children of the same parent // connected by opType // effects: Given two cell tree nodes, node1 and node2, runs the // TM/SP rule on them to merge them (if they belong to the same // extent). Returns true if the merge succeeds private bool TryMergeCellQueries( CellTreeOpType opType, ref CellTreeNode node1, CellTreeNode node2) { var leaf1 = node1 as LeafCellTreeNode; var leaf2 = node2 as LeafCellTreeNode; Debug.Assert(leaf1 != null, "Merge only possible on leaf nodes (1)"); Debug.Assert(leaf2 != null, "Merge only possible on leaf nodes (2)"); CellQuery mergedLeftCellQuery; CellQuery mergedRightCellQuery; if ( !TryMergeTwoCellQueries( leaf1.LeftCellWrapper.RightCellQuery, leaf2.LeftCellWrapper.RightCellQuery, opType, out mergedRightCellQuery)) { return(false); } if ( !TryMergeTwoCellQueries( leaf1.LeftCellWrapper.LeftCellQuery, leaf2.LeftCellWrapper.LeftCellQuery, opType, out mergedLeftCellQuery)) { return(false); } // Create a temporary node and add the two children // so that we can get the merged selectiondomains and attributes // Note that temp.SelectionDomain below determines the domain // based on the opType, e.g., for IJ, it intersects the // multiconstants of all the children var temp = new OpCellTreeNode(m_viewgenContext, opType); temp.Add(node1); temp.Add(node2); // Note: We are losing the original cell number information here and the line number information // But we will not raise any // We do not create CellExpressions with LOJ, FOJ - canBooleansOverlap is true for validation var inputOpType = opType; if (opType == CellTreeOpType.FOJ || opType == CellTreeOpType.LOJ) { inputOpType = CellTreeOpType.IJ; } var wrapper = new LeftCellWrapper( m_viewgenContext.ViewTarget, temp.Attributes, temp.LeftFragmentQuery, mergedLeftCellQuery, mergedRightCellQuery, m_viewgenContext.MemberMaps, leaf1.LeftCellWrapper.Cells.Concat(leaf2.LeftCellWrapper.Cells)); node1 = new LeafCellTreeNode(m_viewgenContext, wrapper, temp.RightFragmentQuery); return(true); }
private bool CSideHasDifferentEntitySets(LeftCellWrapper a, LeftCellWrapper b) { if (this.IsQueryView()) { return(a.LeftExtent == b.LeftExtent); } return(a.RightCellQuery == b.RightCellQuery); }
internal static void CheckConstraints( CellTreeNode node, LeftCellWrapper wrapper, ViewgenContext context, ErrorLog errorLog) { RewritingValidator.DomainConstraintVisitor constraintVisitor = new RewritingValidator.DomainConstraintVisitor(wrapper, context, errorLog); node.Accept <bool, bool>((CellTreeNode.SimpleCellTreeVisitor <bool, bool>)constraintVisitor, true); }
private DomainConstraintVisitor( LeftCellWrapper wrapper, ViewgenContext context, ErrorLog errorLog) { this.m_wrapper = wrapper; this.m_viewgenContext = context; this.m_errorLog = errorLog; }
internal void EnsureExtentIsFullyMapped(HashSet <FragmentQuery> outputUsedViews) { if (this._context.ViewTarget == ViewTarget.QueryView && this._config.IsValidationEnabled) { this.EnsureConfigurationIsFullyMapped(this._extentPath, BoolExpression.True, outputUsedViews, this._errorLog); if (this._errorLog.Count <= 0) { return; } ExceptionHelpers.ThrowMappingException(this._errorLog, this._config); } else { if (this._config.IsValidationEnabled) { foreach (MemberPath member in this._context.MemberMaps.ProjectedSlotMap.Members) { Constant defaultConstant; if (member.IsScalarType() && !member.IsPartOfKey && (!this._domainMap.IsConditionMember(member) && !Domain.TryGetDefaultValueForMemberPath(member, out defaultConstant))) { HashSet <MemberPath> memberPathSet = new HashSet <MemberPath>((IEnumerable <MemberPath>) this._keyAttributes); memberPathSet.Add(member); foreach (LeftCellWrapper leftCellWrapper in this._context.AllWrappersForExtent) { FragmentQuery fragmentQuery = leftCellWrapper.FragmentQuery; Tile <FragmentQuery> rewriting; IEnumerable <MemberPath> notCoveredAttributes; if (!this.RewriteQuery((Tile <FragmentQuery>)QueryRewriter.CreateTile(new FragmentQuery(fragmentQuery.Description, fragmentQuery.FromVariable, (IEnumerable <MemberPath>)memberPathSet, fragmentQuery.Condition)), (Tile <FragmentQuery>)QueryRewriter.CreateTile(FragmentQuery.Create((IEnumerable <MemberPath>) this._keyAttributes, BoolExpression.CreateNot(fragmentQuery.Condition))), out rewriting, out notCoveredAttributes, false)) { Domain.GetDefaultValueForMemberPath(member, (IEnumerable <LeftCellWrapper>) new LeftCellWrapper[1] { leftCellWrapper }, this._config); } } } } } foreach (Tile <FragmentQuery> view in this._views) { Tile <FragmentQuery> toFill = view; Tile <FragmentQuery> tile = (Tile <FragmentQuery>)QueryRewriter.CreateTile(FragmentQuery.Create((IEnumerable <MemberPath>) this._keyAttributes, BoolExpression.CreateNot(toFill.Query.Condition))); Tile <FragmentQuery> rewriting; IEnumerable <MemberPath> notCoveredAttributes; if (!this.RewriteQuery(toFill, tile, out rewriting, out notCoveredAttributes, true)) { LeftCellWrapper leftCellWrapper = this._context.AllWrappersForExtent.First <LeftCellWrapper>((Func <LeftCellWrapper, bool>)(lcr => lcr.FragmentQuery.Equals((object)toFill.Query))); this._errorLog.AddEntry(new ErrorLog.Record(ViewGenErrorCode.ImpopssibleCondition, Strings.Viewgen_QV_RewritingNotFound((object)leftCellWrapper.RightExtent.ToString()), leftCellWrapper.Cells, string.Empty)); } else { outputUsedViews.UnionWith(rewriting.GetNamedQueries()); } } } }
private bool CompareS( ErrorPatternMatcher.ComparisonOP op, ViewgenContext context, LeftCellWrapper leftWrapper1, LeftCellWrapper leftWrapper2, FragmentQuery rightQuery1, FragmentQuery rightQuery2) { return(this.Compare(false, op, context, leftWrapper1, leftWrapper2, rightQuery1, rightQuery2)); }
private static MemberPath GetRightMemberPath( MemberPath conditionMember, LeftCellWrapper leftCellWrapper) { List <int> projectedPositions = leftCellWrapper.OnlyInputCell.GetRightQuery(ViewTarget.QueryView).GetProjectedPositions(conditionMember); if (projectedPositions.Count != 1) { return((MemberPath)null); } int slotNum = projectedPositions.First <int>(); return(((MemberProjectedSlot)leftCellWrapper.OnlyInputCell.GetLeftQuery(ViewTarget.QueryView).ProjectedSlotAt(slotNum)).MemberPath); }
private void CheckConstraintsOnNonNullableMembers(LeftCellWrapper wrapper) { foreach (MemberPath nonConditionMember in this._domainMap.NonConditionMembers(this._viewgenContext.Extent)) { bool flag = nonConditionMember.EdmType is System.Data.Entity.Core.Metadata.Edm.SimpleType; if (!nonConditionMember.IsNullable && flag) { FragmentQuery query = RewritingValidator.AddNullConditionOnCSideFragment(wrapper, nonConditionMember, this._viewgenContext.MemberMaps); if (query != null && this._viewgenContext.RightFragmentQP.IsSatisfiable(query)) { this._errorLog.AddEntry(new ErrorLog.Record(ViewGenErrorCode.NullableMappingForNonNullableColumn, Strings.Viewgen_NullableMappingForNonNullableColumn((object)wrapper.LeftExtent.ToString(), (object)nonConditionMember.ToFullString()), wrapper.Cells, "")); } } } }
private static MemberPath GetRightMemberPath(MemberPath conditionMember, LeftCellWrapper leftCellWrapper) { var rightCellQuery = leftCellWrapper.OnlyInputCell.GetRightQuery(ViewTarget.QueryView); var projectPositions = rightCellQuery.GetProjectedPositions(conditionMember); //Make the case simple. If the member is mapped more than once in the same cell wrapper //we are not going try and guess the pattern if (projectPositions.Count != 1) { return(null); } var firstProjectedPosition = projectPositions.First(); var leftCellQuery = leftCellWrapper.OnlyInputCell.GetLeftQuery(ViewTarget.QueryView); return(((MemberProjectedSlot)leftCellQuery.ProjectedSlotAt(firstProjectedPosition)).MemberPath); }
private void CheckConstraintsOnProjectedConditionMembers( Dictionary <RewritingValidator.MemberValueBinding, CellTreeNode> memberValueTrees, LeftCellWrapper wrapper, CellTreeNode sQueryTree, BoolExpression inExtentCondition) { foreach (MemberPath conditionMember in this._domainMap.ConditionMembers(this._viewgenContext.Extent)) { int slotNum = this._viewgenContext.MemberMaps.ProjectedSlotMap.IndexOf(conditionMember); MemberProjectedSlot memberProjectedSlot = wrapper.RightCellQuery.ProjectedSlotAt(slotNum) as MemberProjectedSlot; if (memberProjectedSlot != null) { foreach (Constant constant in this._domainMap.GetDomain(conditionMember)) { CellTreeNode cellTreeNode1; if (memberValueTrees.TryGetValue(new RewritingValidator.MemberValueBinding(conditionMember, constant), out cellTreeNode1)) { FragmentQuery cQuery = FragmentQuery.Create(RewritingValidator.PropagateCellConstantsToWhereClause(wrapper, wrapper.RightCellQuery.WhereClause, constant, conditionMember, this._viewgenContext.MemberMaps)); CellTreeNode cellTreeNode2; if (sQueryTree != this._basicView) { cellTreeNode2 = (CellTreeNode) new OpCellTreeNode(this._viewgenContext, CellTreeOpType.IJ, new CellTreeNode[2] { cellTreeNode1, sQueryTree }); } else { cellTreeNode2 = cellTreeNode1; } CellTreeNode cellTreeNode3 = cellTreeNode2; BoolExpression unsatisfiedConstraint; if (!this.CheckEquivalence(cQuery, cellTreeNode3.RightFragmentQuery, inExtentCondition, out unsatisfiedConstraint)) { this.ReportConstraintViolation(Strings.ViewGen_CQ_DomainConstraint((object)memberProjectedSlot.ToUserString()), unsatisfiedConstraint, ViewGenErrorCode.DomainConstraintViolation, cellTreeNode3.GetLeaves().Concat <LeftCellWrapper>((IEnumerable <LeftCellWrapper>) new LeftCellWrapper[1] { wrapper })); } } } } } }
private bool Compare( bool lookingForC, ErrorPatternMatcher.ComparisonOP op, ViewgenContext context, LeftCellWrapper leftWrapper1, LeftCellWrapper leftWrapper2, FragmentQuery rightQuery1, FragmentQuery rightQuery2) { if (lookingForC && this.IsQueryView() || !lookingForC && !this.IsQueryView()) { LCWComparer lcwComparer; switch (op) { case ErrorPatternMatcher.ComparisonOP.IsContainedIn: lcwComparer = new LCWComparer(context.LeftFragmentQP.IsContainedIn); break; case ErrorPatternMatcher.ComparisonOP.IsDisjointFrom: lcwComparer = new LCWComparer(context.LeftFragmentQP.IsDisjointFrom); break; default: return(false); } return(lcwComparer(leftWrapper1.FragmentQuery, leftWrapper2.FragmentQuery)); } LCWComparer lcwComparer1; switch (op) { case ErrorPatternMatcher.ComparisonOP.IsContainedIn: lcwComparer1 = new LCWComparer(context.RightFragmentQP.IsContainedIn); break; case ErrorPatternMatcher.ComparisonOP.IsDisjointFrom: lcwComparer1 = new LCWComparer(context.RightFragmentQP.IsDisjointFrom); break; default: return(false); } return(lcwComparer1(rightQuery1, rightQuery2)); }
private bool Compare( bool lookingForC, ComparisonOP op, ViewgenContext context, LeftCellWrapper leftWrapper1, LeftCellWrapper leftWrapper2, FragmentQuery rightQuery1, FragmentQuery rightQuery2) { LCWComparer comparer; if ((lookingForC && IsQueryView()) || (!lookingForC && !IsQueryView())) { if (op == ComparisonOP.IsContainedIn) { comparer = context.LeftFragmentQP.IsContainedIn; } else if (op == ComparisonOP.IsDisjointFrom) { comparer = context.LeftFragmentQP.IsDisjointFrom; } else { Debug.Fail("Unexpected comparison operator, only IsDisjointFrom and IsContainedIn are expected"); return(false); } return(comparer(leftWrapper1.FragmentQuery, leftWrapper2.FragmentQuery)); } else { if (op == ComparisonOP.IsContainedIn) { comparer = context.RightFragmentQP.IsContainedIn; } else if (op == ComparisonOP.IsDisjointFrom) { comparer = context.RightFragmentQP.IsDisjointFrom; } else { Debug.Fail("Unexpected comparison operator, only IsDisjointFrom and IsContainedIn are expected"); return(false); } return(comparer(rightQuery1, rightQuery2)); } }
private void CheckConstraintsOnProjectedConditionMembers( Dictionary <MemberValueBinding, CellTreeNode> memberValueTrees, LeftCellWrapper wrapper, CellTreeNode sQueryTree, BoolExpression inExtentCondition) { // for S-side condition members that are projected, // add condition <member=value> on both sides of the mapping constraint, and check key equivalence // applies to columns that are (1) projected and (2) conditional foreach (var column in _domainMap.ConditionMembers(_viewgenContext.Extent)) { // Get the slot on the C side and see if it is projected var index = _viewgenContext.MemberMaps.ProjectedSlotMap.IndexOf(column); var slot = wrapper.RightCellQuery.ProjectedSlotAt(index) as MemberProjectedSlot; if (slot != null) { foreach (var domainValue in _domainMap.GetDomain(column)) { CellTreeNode sQueryTreeForDomainValue; if (memberValueTrees.TryGetValue(new MemberValueBinding(column, domainValue), out sQueryTreeForDomainValue)) { var cWhereClause = PropagateCellConstantsToWhereClause( wrapper, wrapper.RightCellQuery.WhereClause, domainValue, column, _viewgenContext.MemberMaps); var cCombinedQuery = FragmentQuery.Create(cWhereClause); var sCombinedTree = (sQueryTree == _basicView) ? sQueryTreeForDomainValue : new OpCellTreeNode( _viewgenContext, CellTreeOpType.IJ, sQueryTreeForDomainValue, sQueryTree); BoolExpression unsatisfiedConstraint; if (!CheckEquivalence( cCombinedQuery, sCombinedTree.RightFragmentQuery, inExtentCondition, out unsatisfiedConstraint)) { var memberLossMessage = Strings.ViewGen_CQ_DomainConstraint(slot.ToUserString()); ReportConstraintViolation( memberLossMessage, unsatisfiedConstraint, ViewGenErrorCode.DomainConstraintViolation, sCombinedTree.GetLeaves().Concat(new[] { wrapper })); } } } } } }
// effects: Given a sequence of constants that need to be propagated // to the C-side and the current boolean expression, generates a new // expression of the form "expression AND C-side Member in constants" // expression" and returns it. Each constant is propagated only if member // is projected -- if member is not projected, returns "expression" internal static BoolExpression PropagateCellConstantsToWhereClause( LeftCellWrapper wrapper, BoolExpression expression, Constant constant, MemberPath member, MemberMaps memberMaps) { var joinSlot = wrapper.GetCSideMappedSlotForSMember(member); if (joinSlot == null) { return(expression); } var negatedConstant = constant as NegatedConstant; // Look at the constants and determine if they correspond to // typeConstants or scalarConstants // This slot is being projected. We need to add a where clause element Debug.Assert(constant is ScalarConstant || constant.IsNull() || negatedConstant != null, "Invalid type of constant"); // We want the possible values for joinSlot.MemberPath which is a // C-side element -- so we use the queryDomainMap var possibleValues = memberMaps.QueryDomainMap.GetDomain(joinSlot.MemberPath); // Note: the values in constaints can be null or not null as // well (i.e., just not scalarConstants) var allowedValues = new Set <Constant>(Constant.EqualityComparer); if (negatedConstant != null) { // select all values from the c-side domain that are not in the negated set allowedValues.Unite(possibleValues); allowedValues.Difference(negatedConstant.Elements); } else { allowedValues.Add(constant); } MemberRestriction restriction = new ScalarRestriction(joinSlot.MemberPath, allowedValues, possibleValues); var result = BoolExpression.CreateAnd(expression, BoolExpression.CreateLiteral(restriction, memberMaps.QueryDomainMap)); return(result); }
private static FragmentQuery AddNullConditionOnCSideFragment( LeftCellWrapper wrapper, MemberPath member, MemberMaps memberMaps) { MemberProjectedSlot mappedSlotForSmember = wrapper.GetCSideMappedSlotForSMember(member); if (mappedSlotForSmember == null || !mappedSlotForSmember.MemberPath.IsNullable) { return((FragmentQuery)null); } BoolExpression whereClause = wrapper.RightCellQuery.WhereClause; IEnumerable <Constant> domain = memberMaps.QueryDomainMap.GetDomain(mappedSlotForSmember.MemberPath); MemberRestriction memberRestriction = (MemberRestriction) new ScalarRestriction(mappedSlotForSmember.MemberPath, (IEnumerable <Constant>) new Set <Constant>(Constant.EqualityComparer) { Constant.Null }, domain); return(FragmentQuery.Create(BoolExpression.CreateAnd(whereClause, BoolExpression.CreateLiteral((BoolLiteral)memberRestriction, memberMaps.QueryDomainMap)))); }
/// <summary> /// Given a LeftCellWrapper for the S-side fragment and a non-nullable colum m, return a CQuery with nullability condition /// appended to Cquery of c-side member that column m is mapped to /// </summary> private static FragmentQuery AddNullConditionOnCSideFragment(LeftCellWrapper wrapper, MemberPath member, MemberMaps memberMaps) { MemberProjectedSlot projectedSlot = wrapper.GetCSideMappedSlotForSMember(member); if (projectedSlot == null || !projectedSlot.MemberPath.IsNullable) //don't bother checking further fore non nullable C-side member { return(null); } BoolExpression expression = wrapper.RightCellQuery.WhereClause; IEnumerable <Constant> possibleValues = memberMaps.QueryDomainMap.GetDomain(projectedSlot.MemberPath); Set <Constant> allowedValues = new Set <Constant>(Constant.EqualityComparer); allowedValues.Add(Constant.Null); //Create a condition as conjunction of originalCondition and slot IS NULL MemberRestriction restriction = new ScalarRestriction(projectedSlot.MemberPath, allowedValues, possibleValues); BoolExpression resultingExpr = BoolExpression.CreateAnd(expression, BoolExpression.CreateLiteral(restriction, memberMaps.QueryDomainMap)); return(FragmentQuery.Create(resultingExpr)); }
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); }
/// <summary> /// Checks whether non nullable S-side members are mapped to nullable C-query. /// It is possible that C-side attribute is nullable but the fragment's C-query is not /// </summary> private void CheckConstraintsOnNonNullableMembers(LeftCellWrapper wrapper) { //For each non-condition member that has non-nullability constraint foreach (var column in _domainMap.NonConditionMembers(_viewgenContext.Extent)) { var isColumnSimpleType = (column.EdmType as SimpleType) != null; if (!column.IsNullable && isColumnSimpleType) { var cFragment = AddNullConditionOnCSideFragment(wrapper, column, _viewgenContext.MemberMaps); if (cFragment != null && _viewgenContext.RightFragmentQP.IsSatisfiable(cFragment)) { _errorLog.AddEntry( new ErrorLog.Record( ViewGenErrorCode.NullableMappingForNonNullableColumn, Strings.Viewgen_NullableMappingForNonNullableColumn(wrapper.LeftExtent.ToString(), column.ToFullString()), wrapper.Cells, "")); } } } }
// effects: Given the cells for the extent (extentCells) along with // the signatures (multiconstants + needed attributes) for this extent, generates // the left cell wrappers for it extent (viewTarget indicates whether // the view is for querying or update purposes // Modifies m_cellWrappers to contain this list private bool CreateLeftCellWrappers(IList<Cell> extentCells, ViewTarget viewTarget) { var alignedCells = AlignFields(extentCells, m_memberMaps.ProjectedSlotMap, viewTarget); Debug.Assert(alignedCells.Count == extentCells.Count, "Cell counts disagree"); // Go through all the cells and create cell wrappers that can be used for generating the view m_cellWrappers = new List<LeftCellWrapper>(); for (var i = 0; i < alignedCells.Count; i++) { var alignedCell = alignedCells[i]; var left = alignedCell.GetLeftQuery(viewTarget); var right = alignedCell.GetRightQuery(viewTarget); // Obtain the non-null projected slots into attributes var attributes = left.GetNonNullSlots(); var fromVariable = BoolExpression.CreateLiteral( new CellIdBoolean(m_identifiers, extentCells[i].CellNumber), m_memberMaps.LeftDomainMap); var leftFragmentQuery = FragmentQuery.Create(fromVariable, left); if (viewTarget == ViewTarget.UpdateView) { leftFragmentQuery = m_leftFragmentQP.CreateDerivedViewBySelectingConstantAttributes(leftFragmentQuery) ?? leftFragmentQuery; } var leftWrapper = new LeftCellWrapper( m_viewTarget, attributes, leftFragmentQuery, left, right, m_memberMaps, extentCells[i]); m_cellWrappers.Add(leftWrapper); } return true; }
// requires: node1 and node2 are two children of the same parent // connected by opType // effects: Given two cell tree nodes, node1 and node2, runs the // TM/SP rule on them to merge them (if they belong to the same // extent). Returns true if the merge succeeds private bool TryMergeCellQueries(CellTreeOpType opType, ref CellTreeNode node1, CellTreeNode node2) { LeafCellTreeNode leaf1 = node1 as LeafCellTreeNode; LeafCellTreeNode leaf2 = node2 as LeafCellTreeNode; Debug.Assert(leaf1 != null, "Merge only possible on leaf nodes (1)"); Debug.Assert(leaf2 != null, "Merge only possible on leaf nodes (2)"); CellQuery mergedLeftCellQuery; CellQuery mergedRightCellQuery; if (!TryMergeTwoCellQueries(leaf1.LeftCellWrapper.RightCellQuery, leaf2.LeftCellWrapper.RightCellQuery, opType, m_viewgenContext.MemberMaps.RightDomainMap, out mergedRightCellQuery)) { return false; } if (!TryMergeTwoCellQueries(leaf1.LeftCellWrapper.LeftCellQuery, leaf2.LeftCellWrapper.LeftCellQuery, opType, m_viewgenContext.MemberMaps.LeftDomainMap, out mergedLeftCellQuery)) { return false; } // Create a temporary node and add the two children // so that we can get the merged selectiondomains and attributes // Note that temp.SelectionDomain below determines the domain // based on the opType, e.g., for IJ, it intersects the // multiconstants of all the children OpCellTreeNode temp = new OpCellTreeNode(m_viewgenContext, opType); temp.Add(node1); temp.Add(node2); // Note: We are losing the original cell number information here and the line number information // But we will not raise any // We do not create CellExpressions with LOJ, FOJ - canBooleansOverlap is true for validation CellTreeOpType inputOpType = opType; if (opType == CellTreeOpType.FOJ || opType == CellTreeOpType.LOJ) { inputOpType = CellTreeOpType.IJ; } LeftCellWrapper wrapper = new LeftCellWrapper(m_viewgenContext.ViewTarget, temp.Attributes, temp.LeftFragmentQuery, mergedLeftCellQuery, mergedRightCellQuery, m_viewgenContext.MemberMaps, leaf1.LeftCellWrapper.Cells.Concat(leaf2.LeftCellWrapper.Cells)); node1 = new LeafCellTreeNode(m_viewgenContext, wrapper, temp.RightFragmentQuery); return true; }