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>(); }
// <summary> // Fixes the range of the restriction in accordance with <paramref name="range" />. // Member restriction must be complete for this operation. // </summary> internal override DomainBoolExpr FixRange(Set<Constant> range, MemberDomainMap memberDomainMap) { Debug.Assert(IsComplete, "Ranges are fixed only for complete scalar restrictions."); var newPossibleValues = memberDomainMap.GetDomain(RestrictedMemberSlot.MemberPath); BoolLiteral newLiteral = new ScalarRestriction(RestrictedMemberSlot, new Domain(range, newPossibleValues)); return newLiteral.GetDomainBoolExpression(memberDomainMap); }
internal override BoolExpr<DomainConstraint<BoolLiteral, Constant>> GetDomainBoolExpression(MemberDomainMap domainMap) { // Essentially say that the variable can take values true or false and here its value is only true IEnumerable<Constant> actualValues = new Constant[] { new ScalarConstant(true) }; IEnumerable<Constant> possibleValues = new Constant[] { new ScalarConstant(true), new ScalarConstant(false) }; var variableDomain = new Set<Constant>(possibleValues, Constant.EqualityComparer).MakeReadOnly(); var thisDomain = new Set<Constant>(actualValues, Constant.EqualityComparer).MakeReadOnly(); var result = MakeTermExpression(this, variableDomain, thisDomain); return result; }
internal MemberMaps( ViewTarget viewTarget, MemberProjectionIndex projectedSlotMap, MemberDomainMap queryDomainMap, MemberDomainMap updateDomainMap) { m_projectedSlotMap = projectedSlotMap; m_queryDomainMap = queryDomainMap; m_updateDomainMap = updateDomainMap; Debug.Assert(m_queryDomainMap != null); Debug.Assert(m_updateDomainMap != null); Debug.Assert(m_projectedSlotMap != null); m_viewTarget = viewTarget; }
// 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; }
internal override BoolExpr<DomainConstraint<BoolLiteral, Constant>> FixRange(Set<Constant> range, MemberDomainMap memberDomainMap) { Debug.Assert(range.Count == 1, "For BoolLiterals, there should be precisely one value - true or false"); var scalar = (ScalarConstant)range.First(); var expr = GetDomainBoolExpression(memberDomainMap); if ((bool)scalar.Value == false) { // The range of the variable was "inverted". Return a NOT of // the expression expr = new NotExpr<DomainConstraint<BoolLiteral, Constant>>(expr); } return expr; }
// effects: Creates a ViewGenerator object that is capable of // producing query or update mapping views given the relevant schema // given the "cells" internal ViewGenerator( CellGroup cellGroup, ConfigViewGenerator config, List<ForeignConstraint> foreignKeyConstraints, StorageEntityContainerMapping entityContainerMapping) { m_cellGroup = cellGroup; m_config = config; m_queryRewriterCache = new Dictionary<EntitySetBase, QueryRewriter>(); m_foreignKeyConstraints = foreignKeyConstraints; m_entityContainerMapping = entityContainerMapping; var inheritanceGraph = MetadataHelper.BuildUndirectedGraphOfTypes(entityContainerMapping.StorageMappingItemCollection.EdmItemCollection); SetConfiguration(entityContainerMapping); // We fix all the cells at this point m_queryDomainMap = new MemberDomainMap( ViewTarget.QueryView, m_config.IsValidationEnabled, cellGroup, entityContainerMapping.StorageMappingItemCollection.EdmItemCollection, m_config, inheritanceGraph); m_updateDomainMap = new MemberDomainMap( ViewTarget.UpdateView, m_config.IsValidationEnabled, cellGroup, entityContainerMapping.StorageMappingItemCollection.EdmItemCollection, m_config, inheritanceGraph); // We now go and fix the queryDomain map so that it has all the // values from the S-side as well -- this is needed for domain // constraint propagation, i.e., values from the S-side get // propagated to te oneOfConst on the C-side. So we better get // the "possiblveValues" stuff to contain those constants as well MemberDomainMap.PropagateUpdateDomainToQueryDomain(cellGroup, m_queryDomainMap, m_updateDomainMap); UpdateWhereClauseForEachCell(cellGroup, m_queryDomainMap, m_updateDomainMap, m_config); // We need to simplify cell queries, yet we don't want the conditions to disappear // So, add an extra value to the domain, temporarily var queryOpenDomain = m_queryDomainMap.GetOpenDomain(); var updateOpenDomain = m_updateDomainMap.GetOpenDomain(); // Make sure the WHERE clauses of the cells reflect the changes foreach (var cell in cellGroup) { cell.CQuery.WhereClause.FixDomainMap(queryOpenDomain); cell.SQuery.WhereClause.FixDomainMap(updateOpenDomain); cell.CQuery.WhereClause.ExpensiveSimplify(); cell.SQuery.WhereClause.ExpensiveSimplify(); cell.CQuery.WhereClause.FixDomainMap(m_queryDomainMap); cell.SQuery.WhereClause.FixDomainMap(m_updateDomainMap); } }
/// <summary> /// Returns a boolean expression that is domain-aware and ready for optimizations etc. /// </summary> /// <param name="domainMap">Maps members to the values that each member can take; /// it can be null in which case the possible and actual values are the same.</param> internal override DomainBoolExpr GetDomainBoolExpression(MemberDomainMap domainMap) { // Get the variable name from the slot's memberpath and the possible domain values from the slot DomainTermExpr result; if (domainMap != null) { // Look up the domain from the domainMap var domain = domainMap.GetDomain(m_restrictedMemberSlot.MemberPath); result = MakeTermExpression(this, domain, m_domain.Values); } else { result = MakeTermExpression(this, m_domain.AllPossibleValues, m_domain.Values); } return result; }
internal override BoolExpr <DomainConstraint <BoolLiteral, Constant> > GetDomainBoolExpression(MemberDomainMap domainMap) { // Essentially say that the variable can take values true or false and here its value is only true IEnumerable <Constant> actualValues = new Constant[] { new ScalarConstant(true) }; IEnumerable <Constant> possibleValues = new Constant[] { new ScalarConstant(true), new ScalarConstant(false) }; var variableDomain = new Set <Constant>(possibleValues, Constant.EqualityComparer).MakeReadOnly(); var thisDomain = new Set <Constant>(actualValues, Constant.EqualityComparer).MakeReadOnly(); var result = MakeTermExpression(this, variableDomain, thisDomain); return(result); }
internal abstract DomainBoolExpr GetDomainBoolExpression(MemberDomainMap domainMap);
// effects: Creates a visitor with the JoinTreeNode remapping // information in remap private RemapBoolVisitor(MemberDomainMap memberDomainMap, Dictionary <MemberPath, MemberPath> remap) { m_remap = remap; m_memberDomainMap = memberDomainMap; }
internal ViewgenContext( ViewTarget viewTarget, EntitySetBase extent, IList<Cell> extentCells, CqlIdentifiers identifiers, ConfigViewGenerator config, MemberDomainMap queryDomainMap, MemberDomainMap updateDomainMap, EntityContainerMapping entityContainerMapping) { foreach (var cell in extentCells) { Debug.Assert(extent.Equals(cell.GetLeftQuery(viewTarget).Extent)); Debug.Assert(cell.CQuery.NumProjectedSlots == cell.SQuery.NumProjectedSlots); } m_extent = extent; m_viewTarget = viewTarget; m_config = config; m_edmItemCollection = entityContainerMapping.StorageMappingItemCollection.EdmItemCollection; m_entityContainerMapping = entityContainerMapping; m_identifiers = identifiers; // create a copy of updateDomainMap so generation of query views later on is not affected // it is modified in QueryRewriter.AdjustMemberDomainsForUpdateViews updateDomainMap = updateDomainMap.MakeCopy(); // Create a signature generator that handles all the // multiconstant work and generating the signatures var domainMap = viewTarget == ViewTarget.QueryView ? queryDomainMap : updateDomainMap; m_memberMaps = new MemberMaps( viewTarget, MemberProjectionIndex.Create(extent, m_edmItemCollection), queryDomainMap, updateDomainMap); // Create left fragment KB: includes constraints for the extent to be constructed var leftKB = new FragmentQueryKBChaseSupport(); leftKB.CreateVariableConstraints(extent, domainMap, m_edmItemCollection); m_leftFragmentQP = new FragmentQueryProcessor(leftKB); m_rewritingCache = new Dictionary<FragmentQuery, Tile<FragmentQuery>>( FragmentQuery.GetEqualityComparer(m_leftFragmentQP)); // Now using the signatures, create new cells such that // "extent's" query (C or S) is described in terms of multiconstants if (!CreateLeftCellWrappers(extentCells, viewTarget)) { return; } // Create right fragment KB: includes constraints for all extents and association roles of right queries var rightKB = new FragmentQueryKBChaseSupport(); var rightDomainMap = viewTarget == ViewTarget.QueryView ? updateDomainMap : queryDomainMap; foreach (var leftCellWrapper in m_cellWrappers) { var rightExtent = leftCellWrapper.RightExtent; rightKB.CreateVariableConstraints(rightExtent, rightDomainMap, m_edmItemCollection); rightKB.CreateAssociationConstraints(rightExtent, rightDomainMap, m_edmItemCollection); } if (m_viewTarget == ViewTarget.UpdateView) { CreateConstraintsForForeignKeyAssociationsAffectingThisWrapper(rightKB, rightDomainMap); } m_rightFragmentQP = new FragmentQueryProcessor(rightKB); // Check for concurrency control tokens if (m_viewTarget == ViewTarget.QueryView) { CheckConcurrencyControlTokens(); } // For backward compatibility - // order wrappers by increasing domain size, decreasing number of attributes m_cellWrappers.Sort(LeftCellWrapper.Comparer); }
private FixRangeVisitor(MemberDomainMap memberDomainMap) { this.m_memberDomainMap = memberDomainMap; }
internal void FixDomainMap(MemberDomainMap domainMap) { this.m_tree = BoolExpression.FixRangeVisitor.FixRange(this.m_tree, domainMap); }
internal static BoolExpression CreateLiteral( BoolLiteral literal, MemberDomainMap memberDomainMap) { return(new BoolExpression(literal.GetDomainBoolExpression(memberDomainMap), memberDomainMap)); }
internal void ReduceEnumerableDomainToEnumeratedValues(ConfigViewGenerator config) { MemberDomainMap.ReduceEnumerableDomainToEnumeratedValues(this.m_conditionDomainMap, config, this.m_edmItemCollection); MemberDomainMap.ReduceEnumerableDomainToEnumeratedValues(this.m_nonConditionDomainMap, config, this.m_edmItemCollection); }
internal void FixDomainMap(MemberDomainMap domainMap) { DebugCheck.NotNull(domainMap); m_tree = FixRangeVisitor.FixRange(m_tree, domainMap); }
// effects: Creates a boolean expression based on expr internal BoolExpression(DomainBoolExpr expr, MemberDomainMap memberDomainMap) { m_tree = expr; m_memberDomainMap = memberDomainMap; }
// <summary> // Find the Foreign Key Associations that relate EntitySets used in these left cell wrappers and // add any equivalence facts between sets implied by 1:1 associations. // We can collect other implication facts but we don't have a scenario that needs them( yet ). // </summary> private void CreateConstraintsForForeignKeyAssociationsAffectingThisWrapper( FragmentQueryKB rightKB, MemberDomainMap rightDomainMap) { var oneToOneForeignKeyAssociationSetsForThisWrapper = new OneToOneFkAssociationsForEntitiesFilter() .Filter( m_cellWrappers.Select(it => it.RightExtent).OfType<EntitySet>().Select(it => it.ElementType).ToList(), m_entityContainerMapping.EdmEntityContainer.BaseEntitySets.OfType<AssociationSet>()); // Collect the facts for the foreign key association sets that are 1:1 and affecting this wrapper foreach (var assocSet in oneToOneForeignKeyAssociationSetsForThisWrapper) { rightKB.CreateEquivalenceConstraintForOneToOneForeignKeyAssociation(assocSet, rightDomainMap); } }
// requires: this domainMap has been created for the C-side // effects: Fixes the mergedDomain map in this by merging entries // available in updateDomainMap internal static void PropagateUpdateDomainToQueryDomain( IEnumerable<Cell> cells, MemberDomainMap queryDomainMap, MemberDomainMap updateDomainMap) { foreach (var cell in cells) { var cQuery = cell.CQuery; var sQuery = cell.SQuery; for (var i = 0; i < cQuery.NumProjectedSlots; i++) { var cSlot = cQuery.ProjectedSlotAt(i) as MemberProjectedSlot; var sSlot = sQuery.ProjectedSlotAt(i) as MemberProjectedSlot; if (cSlot == null || sSlot == null) { continue; } // Get the domain for sSlot and merge with cSlot's var cPath = cSlot.MemberPath; var sPath = sSlot.MemberPath; var cDomain = queryDomainMap.GetDomainInternal(cPath); var sDomain = updateDomainMap.GetDomainInternal(sPath); // skip NULL because if c-side member is nullable, it's already there, and otherwise can't be taken // skip negated because negated values are translated in a special way cDomain.Unite(sDomain.Where(constant => !constant.IsNull() && !(constant is NegatedConstant))); if (updateDomainMap.IsConditionMember(sPath) && !queryDomainMap.IsConditionMember(cPath)) { // record this member so KB knows we have to generate constraints for it queryDomainMap.m_projectedConditionMembers.Add(cPath); } } } ExpandNegationsInDomainMap(queryDomainMap.m_conditionDomainMap); ExpandNegationsInDomainMap(queryDomainMap.m_nonConditionDomainMap); }
internal abstract BoolExpr <DomainConstraint <BoolLiteral, Constant> > FixRange( Set <Constant> range, MemberDomainMap memberDomainMap);
internal override BoolExpr <DomainConstraint <BoolLiteral, Constant> > FixRange(Set <Constant> range, MemberDomainMap memberDomainMap) { Debug.Assert(range.Count == 1, "For BoolLiterals, there should be precisely one value - true or false"); var scalar = (ScalarConstant)range.First(); var expr = GetDomainBoolExpression(memberDomainMap); if ((bool)scalar.Value == false) { // The range of the variable was "inverted". Return a NOT of // the expression expr = new NotExpr <DomainConstraint <BoolLiteral, Constant> >(expr); } return(expr); }
// requires: The CellConstantDomains in the OneOfConsts of the where // clause are partially done // effects: Given the domains of different variables in domainMap, // fixes the whereClause of this such that all the // CellConstantDomains in OneOfConsts are complete internal void UpdateWhereClause(MemberDomainMap domainMap) { var atoms = new List<BoolExpression>(); foreach (var atom in WhereClause.Atoms) { var literal = atom.AsLiteral; var restriction = literal as MemberRestriction; Debug.Assert(restriction != null, "All bool literals must be OneOfConst at this point"); // The oneOfConst needs to be fixed with the new possible values from the domainMap. var possibleValues = domainMap.GetDomain(restriction.RestrictedMemberSlot.MemberPath); var newOneOf = restriction.CreateCompleteMemberRestriction(possibleValues); // Prevent optimization of single constraint e.g: "300 in (300)" // But we want to optimize type constants e.g: "category in (Category)" // To prevent optimization of bool expressions we add a Sentinel OneOF var scalarConst = restriction as ScalarRestriction; var addSentinel = scalarConst != null && !scalarConst.Domain.Contains(Constant.Null) && !scalarConst.Domain.Contains(Constant.NotNull) && !scalarConst.Domain.Contains(Constant.Undefined); if (addSentinel) { domainMap.AddSentinel(newOneOf.RestrictedMemberSlot.MemberPath); } atoms.Add(BoolExpression.CreateLiteral(newOneOf, domainMap)); if (addSentinel) { domainMap.RemoveSentinel(newOneOf.RestrictedMemberSlot.MemberPath); } } // We create a new whereClause that has the memberDomainMap set if (atoms.Count > 0) { m_whereClause = BoolExpression.CreateAnd(atoms.ToArray()); } }
/// <summary> /// Find the Foreign Key Associations that relate EntitySets used in these left cell wrappers and /// add any equivalence facts between sets implied by 1:1 associations. /// We can collect other implication facts but we don't have a scenario that needs them( yet ). /// </summary> /// <param name="rightKB"></param> /// <param name="rightDomainMap"></param> private void CreateConstraintsForForeignKeyAssociationsAffectingThisWarapper( FragmentQueryKB rightKB, MemberDomainMap rightDomainMap) { //First find the entity types of the sets in these cell wrappers. var entityTypes = m_cellWrappers.Select(it => it.RightExtent).OfType<EntitySet>().Select(it => it.ElementType); //Get all the foreign key association sets in these entity sets var allForeignKeyAssociationSets = m_entityContainerMapping.EdmEntityContainer.BaseEntitySets.OfType<AssociationSet>().Where(it => it.ElementType.IsForeignKey); //Find all the foreign key associations that have corresponding sets var oneToOneForeignKeyAssociationsForThisWrapper = allForeignKeyAssociationSets.Select(it => it.ElementType); //Find all the 1:1 associations from the above list oneToOneForeignKeyAssociationsForThisWrapper = oneToOneForeignKeyAssociationsForThisWrapper.Where( it => (it.AssociationEndMembers.All(endMember => endMember.RelationshipMultiplicity == RelationshipMultiplicity.One))); //Filter the 1:1 foreign key associations to the ones relating the sets used in these cell wrappers. oneToOneForeignKeyAssociationsForThisWrapper = oneToOneForeignKeyAssociationsForThisWrapper.Where( it => (it.AssociationEndMembers.All(endMember => entityTypes.Contains(endMember.GetEntityType())))); //filter foreign key association sets to the sets that are 1:1 and affecting this wrapper. var oneToOneForeignKeyAssociationSetsForThisWrapper = allForeignKeyAssociationSets.Where(it => oneToOneForeignKeyAssociationsForThisWrapper.Contains(it.ElementType)); //Collect the facts for the foreign key association sets that are 1:1 and affecting this wrapper foreach (var assocSet in oneToOneForeignKeyAssociationSetsForThisWrapper) { rightKB.CreateEquivalenceConstraintForOneToOneForeignKeyAssociation(assocSet, rightDomainMap); } }
// effects: Given the extent cells and a map for the domains of all // variables in it, fixes the cell constant domains of the where // clauses in the left queries of cells (left is defined using viewTarget) private static void UpdateWhereClauseForEachCell( IEnumerable<Cell> extentCells, MemberDomainMap queryDomainMap, MemberDomainMap updateDomainMap, ConfigViewGenerator config) { foreach (var cell in extentCells) { cell.CQuery.UpdateWhereClause(queryDomainMap); cell.SQuery.UpdateWhereClause(updateDomainMap); } // Fix enumerable domains - currently it is only applicable to boolean type. Note that it is // not applicable to enumerated types since we allow any value of the underlying type of the enum type. queryDomainMap.ReduceEnumerableDomainToEnumeratedValues(config); updateDomainMap.ReduceEnumerableDomainToEnumeratedValues(config); }
internal static FragmentQuery CreateMemberConditionQuery( MemberPath currentPath, Constant domainValue, IEnumerable<MemberPath> keyAttributes, MemberDomainMap domainMap) { // construct WHERE clause for this value var domainWhereClause = FragmentQuery.CreateMemberCondition(currentPath, domainValue, domainMap); // get a rewriting for CASE statements by not requesting any attributes beyond key var attributes = keyAttributes; if (domainValue is NegatedConstant) { // we need the attribute value attributes = keyAttributes.Concat(new[] { currentPath }); } return FragmentQuery.Create(attributes, domainWhereClause); }
private static IEnumerable<MemberPath> GetConditionalScalarMembers( EdmType edmType, MemberPath currentPath, MemberDomainMap domainMap) { return currentPath.GetMembers(edmType, true /* isScalar */, true /* isConditional */, null /* isPartOfKey */, domainMap); }
/// <summary> /// Fixes the range of the literal using the new values provided in <paramref name="range" /> and returns a boolean expression corresponding to the new value. /// </summary> internal abstract DomainBoolExpr FixRange(Set <Constant> range, MemberDomainMap memberDomainMap);