// effects: Creates a view generator object that can be used to generate views // based on usedCells (projectedSlotMap are useful for deciphering the fields) internal BasicViewGenerator(MemberProjectionIndex projectedSlotMap, List<LeftCellWrapper> usedCells, FragmentQuery activeDomain, ViewgenContext context, MemberDomainMap domainMap, ErrorLog errorLog, ConfigViewGenerator config) { Debug.Assert(usedCells.Count > 0, "No used cells"); m_projectedSlotMap = projectedSlotMap; m_usedCells = usedCells; m_viewgenContext = context; m_activeDomain = activeDomain; m_errorLog = errorLog; m_config = config; m_domainMap = domainMap; }
// effects: Returns the cached rewriting of (left) queries in terms of views, if any internal bool TryGetCachedRewriting(FragmentQuery query, out Tile<FragmentQuery> rewriting) { return m_rewritingCache.TryGetValue(query, out rewriting); }
// effects: Records the cached rewriting of (left) queries in terms of views internal void SetCachedRewriting(FragmentQuery query, Tile<FragmentQuery> rewriting) { m_rewritingCache[query] = rewriting; }
internal QueryRewriter(EdmType generatedType, ViewgenContext context, ViewGenMode typesGenerationMode) { Debug.Assert(typesGenerationMode != ViewGenMode.GenerateAllViews); _typesGenerationMode = typesGenerationMode; _context = context; _generatedType = generatedType; _domainMap = context.MemberMaps.LeftDomainMap; _config = context.Config; _identifiers = context.CqlIdentifiers; _qp = new RewritingProcessor<Tile<FragmentQuery>>(new DefaultTileProcessor<FragmentQuery>(context.LeftFragmentQP)); _extentPath = new MemberPath(context.Extent); _keyAttributes = new List<MemberPath>(MemberPath.GetKeyMembers(context.Extent, _domainMap)); // populate _fragmentQueries and _views foreach (var leftCellWrapper in _context.AllWrappersForExtent) { var query = leftCellWrapper.FragmentQuery; Tile<FragmentQuery> tile = CreateTile(query); _fragmentQueries.Add(query); _views.Add(tile); } Debug.Assert(_views.Count > 0); AdjustMemberDomainsForUpdateViews(); // must be done after adjusting domains _domainQuery = GetDomainQuery(FragmentQueries, generatedType); _usedViews = new HashSet<FragmentQuery>(); }
// This makes sure that the mapping describes how to store all C-side data, // i.e., the view given by C-side cell queries is injective internal void EnsureExtentIsFullyMapped(HashSet<FragmentQuery> outputUsedViews) { if (_context.ViewTarget == ViewTarget.QueryView && _config.IsValidationEnabled) { // Run the check below for OfType views too so we can determine // what views are used (low overhead due to caching of rewritings) EnsureConfigurationIsFullyMapped(_extentPath, BoolExpression.True, outputUsedViews, _errorLog); if (_errorLog.Count > 0) { ExceptionHelpers.ThrowMappingException(_errorLog, _config); } } else { if (_config.IsValidationEnabled) { // Ensure that non-nullable, no-default attributes are always populated properly foreach (var memberPath in _context.MemberMaps.ProjectedSlotMap.Members) { Constant defaultConstant; if (memberPath.IsScalarType() && !memberPath.IsPartOfKey && !_domainMap.IsConditionMember(memberPath) && !Domain.TryGetDefaultValueForMemberPath(memberPath, out defaultConstant)) { var attributes = new HashSet<MemberPath>(_keyAttributes); attributes.Add(memberPath); foreach (var leftCellWrapper in _context.AllWrappersForExtent) { var fragmentQuery = leftCellWrapper.FragmentQuery; var tileQuery = new FragmentQuery( fragmentQuery.Description, fragmentQuery.FromVariable, attributes, fragmentQuery.Condition); Tile<FragmentQuery> noNullToAvoid = CreateTile(FragmentQuery.Create(_keyAttributes, BoolExpression.CreateNot(fragmentQuery.Condition))); Tile<FragmentQuery> noNullRewriting; IEnumerable<MemberPath> notCoveredAttributes; if ( !RewriteQuery( CreateTile(tileQuery), noNullToAvoid, /*_views,*/ out noNullRewriting, out notCoveredAttributes, false /* isRelaxed */)) { // force error Domain.GetDefaultValueForMemberPath(memberPath, new[] { leftCellWrapper }, _config); } } } } } // find a rewriting for each tile // some of the views may be redundant and unused foreach (var toFill in _views) { Tile<FragmentQuery> rewriting; Tile<FragmentQuery> toAvoid = CreateTile(FragmentQuery.Create(_keyAttributes, BoolExpression.CreateNot(toFill.Query.Condition))); IEnumerable<MemberPath> notCoveredAttributes; var found = RewriteQuery(toFill, toAvoid, out rewriting, out notCoveredAttributes, true /* isRelaxed */); //Must be able to find the rewriting since the query is one of the views // otherwise it means condition on the fragment is not satisfiable if (!found) { var fragment = _context.AllWrappersForExtent.First(lcr => lcr.FragmentQuery.Equals(toFill.Query)); Debug.Assert(fragment != null); var record = new ErrorLog.Record( ViewGenErrorCode.ImpopssibleCondition, Strings.Viewgen_QV_RewritingNotFound(fragment.RightExtent.ToString()), fragment.Cells, String.Empty); _errorLog.AddEntry(record); } else { outputUsedViews.UnionWith(rewriting.GetNamedQueries()); } } } }
// Returns MemberPaths which have conditions in the where clause // Filters out all trivial conditions (e.g., num=1 where dom(num)={1}) // i.e., where all constants from the domain are contained in range private static Set<MemberPath> GetVariables(FragmentQuery query) { var memberVariables = from domainConstraint in query.Condition.VariableConstraints where domainConstraint.Variable.Identifier is MemberRestriction && false == domainConstraint.Variable.Domain.All(constant => domainConstraint.Range.Contains(constant)) select ((MemberRestriction)domainConstraint.Variable.Identifier).RestrictedMemberSlot.MemberPath; return new Set<MemberPath>(memberVariables, MemberPath.EqualityComparer); }
private bool IsTrue(FragmentQuery query) { return !_context.LeftFragmentQP.IsSatisfiable(FragmentQuery.Create(BoolExpression.CreateNot(query.Condition))); }
private IEnumerable<Tile<FragmentQuery>> GetRelevantViews(FragmentQuery query) { // Step 1: // Determine connected and directly/indirectly connected variables // Directly connected variables: those that appear in query's WHERE clause // Indirectly connected variables: directly connected variables + variables in all views that contain directly connected variables // Disconnected variables: those that appear in some view's WHERE clause but are not indirectly connected var connectedVariables = GetVariables(query); // Step 2: // Take a union of all views that contain connected variables // If it evaluates to True, we can discard all other views; no special True-view is needed // Otherwise: // If isRelaxed == false: // Take a union of all views. If it yields True, than assume that True-view is available. // Later, try to pick a smaller subset (instead of all views) once we know that attributes are needed // If isRelaxed == true: // Discard all views that don't contain connected variables; assume that True-view is available Tile<FragmentQuery> unionOfConnectedViews = null; var connectedViews = new List<Tile<FragmentQuery>>(); Tile<FragmentQuery> firstTrueView = null; foreach (var tile in _views) { // notice: this is a syntactic check. We assume that if the variable is not present in the condition, // its value is unrestricted (which in general may not be true because the KB may have e.g., X=1 => Y=1, // so even if condition on Y is absent, the view would still be relevant if (GetVariables(tile.Query).Overlaps(connectedVariables)) { unionOfConnectedViews = (unionOfConnectedViews == null) ? tile : _qp.Union(unionOfConnectedViews, tile); connectedViews.Add(tile); } else if (IsTrue(tile.Query) && firstTrueView == null) { firstTrueView = tile; // don't add True views; only one of them might be needed, if at all } } if (unionOfConnectedViews != null && IsTrue(unionOfConnectedViews.Query)) // the collected views give us "True" { return connectedViews; } if (firstTrueView == null) { // can we obtain True at all? Tile<FragmentQuery> unionTile = null; foreach (var view in _fragmentQueries) { unionTile = (unionTile == null) ? CreateTile(view) : _qp.Union(unionTile, CreateTile(view)); if (IsTrue(unionTile.Query)) { // yes, we can; use a surrogate view - replace it later firstTrueView = _trueViewSurrogate; break; } } } if (firstTrueView != null) // the collected views don't give us True, but { connectedViews.Add(firstTrueView); return connectedViews; } // Step 3: // For each indirectly-connected variable x: // Union all views that contain x. The condition on x must disappear, i.e., union must imply that x is in Domain(x) // That is, the union must be equivalent to the expression in which all conditions on x have been eliminated. // If that's not the case (i.e., can't get rid of x), remove all these views from consideration. return _views; }
private static TileNamed<FragmentQuery> CreateTile(FragmentQuery query) { return new TileNamed<FragmentQuery>(query); }
// returns true if the view is useful for covering the projected attribute private bool CoverAttribute( MemberPath projectedAttribute, FragmentQuery view, Dictionary<MemberPath, FragmentQuery> attributeConditions) { FragmentQuery currentAttributeCondition; if (attributeConditions.TryGetValue(projectedAttribute, out currentAttributeCondition)) { currentAttributeCondition = FragmentQuery.Create(BoolExpression.CreateAndNot(currentAttributeCondition.Condition, view.Condition)); if (_qp.IsEmpty(CreateTile(currentAttributeCondition))) { // this attribute is covered! remove it from the list attributeConditions.Remove(projectedAttribute); } else { attributeConditions[projectedAttribute] = currentAttributeCondition; } return true; } return false; }
private bool CoverAttributes(ref Tile<FragmentQuery> rewriting, FragmentQuery toFillQuery, Dictionary<MemberPath, FragmentQuery> attributeConditions) { // first, account for already used views HashSet<FragmentQuery> usedViews = new HashSet<FragmentQuery>(rewriting.GetNamedQueries()); Debug.Assert(usedViews.Count > 0); //List<FragmentQuery> usedViewsList = new List<FragmentQuery>(usedViews); //usedViewsList.Sort(FragmentQuery.GetComparer(toFillQuery.Attributes)); foreach (FragmentQuery view in usedViews) { foreach (MemberPath projectedAttribute in NonKeys(view.Attributes)) { CoverAttribute(projectedAttribute, view, attributeConditions, toFillQuery); } if (attributeConditions.Count == 0) { return true; // we are done } } // still need to fill some attributes Tile<FragmentQuery> attributeTile = null; foreach (FragmentQuery view in _fragmentQueries) { foreach (MemberPath projectedAttribute in NonKeys(view.Attributes)) { if (CoverAttribute(projectedAttribute, view, attributeConditions, toFillQuery)) { attributeTile = (attributeTile == null) ? CreateTile(view) : _qp.Union(attributeTile, CreateTile(view)); } } if (attributeConditions.Count == 0) { break; // we are done! } } if (attributeConditions.Count == 0) { // yes, we covered all attributes Debug.Assert(attributeTile != null); rewriting = _qp.Join(rewriting, attributeTile); return true; } else { // create rewriting that we couldn't satisfy return false; // couldn't cover some attribute(s) } }
// effects: Returns the cached rewriting of (left) queries in terms of views, if any internal bool TryGetCachedRewriting(FragmentQuery query, out Tile <FragmentQuery> rewriting) { return(m_rewritingCache.TryGetValue(query, out rewriting)); }
private FragmentQuery CreateRightFragmentQuery(LeftCellWrapper wrapper) { return(FragmentQuery.Create(wrapper.OnlyInputCell.CellLabel.ToString(), wrapper.CreateRoleBoolean(), wrapper.OnlyInputCell.GetRightQuery(this.m_viewgenContext.ViewTarget))); }
private void MatchPartitionErrors() { List <LeftCellWrapper> wrappersForExtent = this.m_viewgenContext.AllWrappersForExtent; int num = 0; foreach (LeftCellWrapper leftCellWrapper1 in wrappersForExtent) { foreach (LeftCellWrapper leftCellWrapper2 in wrappersForExtent.Skip <LeftCellWrapper>(++num)) { FragmentQuery rightFragmentQuery1 = this.CreateRightFragmentQuery(leftCellWrapper1); FragmentQuery rightFragmentQuery2 = this.CreateRightFragmentQuery(leftCellWrapper2); bool flag1 = this.CompareS(ErrorPatternMatcher.ComparisonOP.IsDisjointFrom, this.m_viewgenContext, leftCellWrapper1, leftCellWrapper2, rightFragmentQuery1, rightFragmentQuery2); bool flag2 = this.CompareC(ErrorPatternMatcher.ComparisonOP.IsDisjointFrom, this.m_viewgenContext, leftCellWrapper1, leftCellWrapper2, rightFragmentQuery1, rightFragmentQuery2); bool flag3; bool flag4; if (flag1) { if (!flag2) { flag3 = this.CompareC(ErrorPatternMatcher.ComparisonOP.IsContainedIn, this.m_viewgenContext, leftCellWrapper1, leftCellWrapper2, rightFragmentQuery1, rightFragmentQuery2); flag4 = this.CompareC(ErrorPatternMatcher.ComparisonOP.IsContainedIn, this.m_viewgenContext, leftCellWrapper2, leftCellWrapper1, rightFragmentQuery2, rightFragmentQuery1); bool flag5 = flag3 && flag4; StringBuilder stringBuilder = new StringBuilder(); if (flag5) { stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Eq); } else if (flag3 || flag4) { if (this.CSideHasDifferentEntitySets(leftCellWrapper1, leftCellWrapper2)) { stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Subs_Ref); } else { stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Subs); } } else { stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Unk); } this.m_errorLog.AddEntry(new ErrorLog.Record(ViewGenErrorCode.ErrorPatternInvalidPartitionError, stringBuilder.ToString(), ErrorPatternMatcher.ToIEnum(leftCellWrapper1.OnlyInputCell, leftCellWrapper2.OnlyInputCell), "")); if (this.FoundTooManyErrors()) { return; } } else { continue; } } else { flag3 = this.CompareC(ErrorPatternMatcher.ComparisonOP.IsContainedIn, this.m_viewgenContext, leftCellWrapper1, leftCellWrapper2, rightFragmentQuery1, rightFragmentQuery2); flag4 = this.CompareC(ErrorPatternMatcher.ComparisonOP.IsContainedIn, this.m_viewgenContext, leftCellWrapper2, leftCellWrapper1, rightFragmentQuery2, rightFragmentQuery1); } bool flag6 = this.CompareS(ErrorPatternMatcher.ComparisonOP.IsContainedIn, this.m_viewgenContext, leftCellWrapper1, leftCellWrapper2, rightFragmentQuery1, rightFragmentQuery2); bool flag7 = this.CompareS(ErrorPatternMatcher.ComparisonOP.IsContainedIn, this.m_viewgenContext, leftCellWrapper2, leftCellWrapper1, rightFragmentQuery2, rightFragmentQuery1); bool flag8 = flag3 && flag4; if (flag6 && flag7) { if (!flag8) { StringBuilder stringBuilder = new StringBuilder(); if (flag2) { stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Disj); } else if (flag3 || flag4) { if (this.CSideHasDifferentEntitySets(leftCellWrapper1, leftCellWrapper2)) { stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Subs_Ref); } else { if (leftCellWrapper1.LeftExtent.Equals((object)leftCellWrapper2.LeftExtent)) { bool hasCondition1; List <EdmType> edmTypes1; ErrorPatternMatcher.GetTypesAndConditionForWrapper(leftCellWrapper1, out hasCondition1, out edmTypes1); bool hasCondition2; List <EdmType> edmTypes2; ErrorPatternMatcher.GetTypesAndConditionForWrapper(leftCellWrapper2, out hasCondition2, out edmTypes2); if (!hasCondition1 && !hasCondition2 && (edmTypes1.Except <EdmType>((IEnumerable <EdmType>)edmTypes2).Count <EdmType>() != 0 || edmTypes2.Except <EdmType>((IEnumerable <EdmType>)edmTypes1).Count <EdmType>() != 0) && (!ErrorPatternMatcher.CheckForStoreConditions(leftCellWrapper1) || !ErrorPatternMatcher.CheckForStoreConditions(leftCellWrapper2))) { this.m_errorLog.AddEntry(new ErrorLog.Record(ViewGenErrorCode.ErrorPatternConditionError, Strings.Viewgen_ErrorPattern_Partition_MultipleTypesMappedToSameTable_WithoutCondition((object)StringUtil.ToCommaSeparatedString((IEnumerable)edmTypes1.Select <EdmType, string>((Func <EdmType, string>)(it => it.FullName)).Union <string>(edmTypes2.Select <EdmType, string>((Func <EdmType, string>)(it => it.FullName)))), (object)leftCellWrapper1.LeftExtent), ErrorPatternMatcher.ToIEnum(leftCellWrapper1.OnlyInputCell, leftCellWrapper2.OnlyInputCell), "")); return; } } stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Subs); } } else if (!this.IsQueryView() && (leftCellWrapper1.OnlyInputCell.CQuery.Extent is AssociationSet || leftCellWrapper2.OnlyInputCell.CQuery.Extent is AssociationSet)) { stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Unk_Association); } else { stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Unk); } this.m_errorLog.AddEntry(new ErrorLog.Record(ViewGenErrorCode.ErrorPatternInvalidPartitionError, stringBuilder.ToString(), ErrorPatternMatcher.ToIEnum(leftCellWrapper1.OnlyInputCell, leftCellWrapper2.OnlyInputCell), "")); if (this.FoundTooManyErrors()) { return; } } } else if ((flag6 || flag7) && (!flag6 || !flag3 || flag4) && (!flag7 || !flag4 || flag3)) { StringBuilder stringBuilder = new StringBuilder(); if (flag2) { stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Sub_Disj); } else if (flag8) { if (this.CSideHasDifferentEntitySets(leftCellWrapper1, leftCellWrapper2)) { stringBuilder.Append(" " + Strings.Viewgen_ErrorPattern_Partition_Sub_Eq_Ref); } else { stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Sub_Eq); } } else { stringBuilder.Append(Strings.Viewgen_ErrorPattern_Partition_Sub_Unk); } this.m_errorLog.AddEntry(new ErrorLog.Record(ViewGenErrorCode.ErrorPatternInvalidPartitionError, stringBuilder.ToString(), ErrorPatternMatcher.ToIEnum(leftCellWrapper1.OnlyInputCell, leftCellWrapper2.OnlyInputCell), "")); if (this.FoundTooManyErrors()) { return; } } } } }