internal void CreateVariableConstraints(EntitySetBase extent, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
 {
     CreateVariableConstraintsRecursion(extent.ElementType, new MemberPath(extent), domainMap, edmItemCollection);
 }
        internal void CreateAssociationConstraints(EntitySetBase extent, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
        {
            var assocSet = extent as AssociationSet;

            if (assocSet != null)
            {
                var assocSetExpr = BoolExpression.CreateLiteral(new RoleBoolean(assocSet), domainMap);

                //Set of Keys for this Association Set
                //need to key on EdmMember and EdmType because A, B subtype of C, can have the same id (EdmMember) that is defined in C.
                var associationkeys = new HashSet <Pair <EdmMember, EntityType> >();

                //foreach end, add each Key
                foreach (var endMember in assocSet.ElementType.AssociationEndMembers)
                {
                    var type = (EntityType)((RefType)endMember.TypeUsage.EdmType).ElementType;
                    type.KeyMembers.All(
                        member => associationkeys.Add(new Pair <EdmMember, EntityType>(member, type)) || true /* prevent early termination */);
                }

                foreach (var end in assocSet.AssociationSetEnds)
                {
                    // construct type condition
                    var derivedTypes = new HashSet <EdmType>();
                    derivedTypes.UnionWith(
                        MetadataHelper.GetTypeAndSubtypesOf(
                            end.CorrespondingAssociationEndMember.TypeUsage.EdmType, edmItemCollection, false));

                    var typeCondition = CreateIsOfTypeCondition(
                        new MemberPath(end.EntitySet),
                        derivedTypes, domainMap);

                    var inRoleExpression = BoolExpression.CreateLiteral(new RoleBoolean(end), domainMap);
                    var inSetExpression  = BoolExpression.CreateAnd(
                        BoolExpression.CreateLiteral(new RoleBoolean(end.EntitySet), domainMap),
                        typeCondition);

                    // InRole -> (InSet AND type(Set)=T)
                    AddImplication(inRoleExpression.Tree, inSetExpression.Tree);

                    if (MetadataHelper.IsEveryOtherEndAtLeastOne(assocSet, end.CorrespondingAssociationEndMember))
                    {
                        AddImplication(inSetExpression.Tree, inRoleExpression.Tree);
                    }

                    // Add equivalence between association set an End/Role if necessary.
                    //   Equivalence is added when a given association end's keys subsumes keys for
                    //   all the other association end.

                    // For example: We have Entity Sets A[id1], B[id2, id3] and an association A_B between them.
                    // Ref Constraint A.id1 = B.id2
                    // In this case, the Association Set has Key <id1, id2, id3>
                    // id1 alone can not identify a unique tuple in the Association Set, but <id2, id3> can.
                    // Therefore we add a constraint: InSet(B) <=> InEnd(A_B.B)

                    if (MetadataHelper.DoesEndKeySubsumeAssociationSetKey(
                            assocSet,
                            end.CorrespondingAssociationEndMember,
                            associationkeys))
                    {
                        AddEquivalence(inRoleExpression.Tree, assocSetExpr.Tree);
                    }
                }

                // add rules for referential constraints (borrowed from LeftCellWrapper.cs)
                var assocType = assocSet.ElementType;

                foreach (var constraint in assocType.ReferentialConstraints)
                {
                    var toEndMember = (AssociationEndMember)constraint.ToRole;
                    var toEntitySet = MetadataHelper.GetEntitySetAtEnd(assocSet, toEndMember);
                    // Check if the keys of the entitySet's are equal to what is specified in the constraint
                    // How annoying that KeyMembers returns EdmMember and not EdmProperty
                    var toProperties = Helpers.AsSuperTypeList <EdmProperty, EdmMember>(constraint.ToProperties);
                    if (Helpers.IsSetEqual(toProperties, toEntitySet.ElementType.KeyMembers, EqualityComparer <EdmMember> .Default))
                    {
                        // Now check that the FromEnd is 1..1 (only then will all the Addresses be present in the assoc set)
                        if (constraint.FromRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One))
                        {
                            // Make sure that the ToEnd is not 0..* because then the schema is broken
                            Debug.Assert(constraint.ToRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.Many) == false);
                            // Equate the ends
                            var inRoleExpression1 = BoolExpression.CreateLiteral(new RoleBoolean(assocSet.AssociationSetEnds[0]), domainMap);
                            var inRoleExpression2 = BoolExpression.CreateLiteral(new RoleBoolean(assocSet.AssociationSetEnds[1]), domainMap);
                            AddEquivalence(inRoleExpression1.Tree, inRoleExpression2.Tree);
                        }
                    }
                }
            }
        }
        private void CreateVariableConstraintsRecursion(
            EdmType edmType, MemberPath currentPath, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
        {
            // Add the types can member have, i.e., its type and its subtypes
            var possibleTypes = new HashSet <EdmType>();

            possibleTypes.UnionWith(MetadataHelper.GetTypeAndSubtypesOf(edmType, edmItemCollection, true));

            foreach (var possibleType in possibleTypes)
            {
                // determine type domain

                var derivedTypes = new HashSet <EdmType>();
                derivedTypes.UnionWith(MetadataHelper.GetTypeAndSubtypesOf(possibleType, edmItemCollection, false));
                if (derivedTypes.Count != 0)
                {
                    var typeCondition           = CreateIsOfTypeCondition(currentPath, derivedTypes, domainMap);
                    var typeConditionComplement = BoolExpression.CreateNot(typeCondition);
                    if (false == typeConditionComplement.IsSatisfiable())
                    {
                        continue;
                    }

                    var structuralType = (StructuralType)possibleType;
                    foreach (var childProperty in structuralType.GetDeclaredOnlyMembers <EdmProperty>())
                    {
                        var childPath = new MemberPath(currentPath, childProperty);
                        var isScalar  = MetadataHelper.IsNonRefSimpleMember(childProperty);

                        if (domainMap.IsConditionMember(childPath) ||
                            domainMap.IsProjectedConditionMember(childPath))
                        {
                            BoolExpression nullCondition;
                            var            childDomain = new List <Constant>(domainMap.GetDomain(childPath));
                            if (isScalar)
                            {
                                nullCondition = BoolExpression.CreateLiteral(
                                    new ScalarRestriction(
                                        new MemberProjectedSlot(childPath),
                                        new Domain(Constant.Undefined, childDomain)), domainMap);
                            }
                            else
                            {
                                nullCondition = BoolExpression.CreateLiteral(
                                    new TypeRestriction(
                                        new MemberProjectedSlot(childPath),
                                        new Domain(Constant.Undefined, childDomain)), domainMap);
                            }
                            // Properties not occuring in type are UNDEFINED
                            AddEquivalence(typeConditionComplement.Tree, nullCondition.Tree);
                        }

                        // recurse into complex types
                        if (false == isScalar)
                        {
                            CreateVariableConstraintsRecursion(childPath.EdmType, childPath, domainMap, edmItemCollection);
                        }
                    }
                }
            }
        }
        internal void CreateEquivalenceConstraintForOneToOneForeignKeyAssociation(AssociationSet assocSet, MemberDomainMap domainMap)
        {
            var assocType = assocSet.ElementType;

            foreach (var constraint in assocType.ReferentialConstraints)
            {
                var toEndMember   = (AssociationEndMember)constraint.ToRole;
                var fromEndMember = (AssociationEndMember)constraint.FromRole;
                var toEntitySet   = MetadataHelper.GetEntitySetAtEnd(assocSet, toEndMember);
                var fromEntitySet = MetadataHelper.GetEntitySetAtEnd(assocSet, fromEndMember);

                // Check if the keys of the entitySet's are equal to what is specified in the constraint
                var toProperties = Helpers.AsSuperTypeList <EdmProperty, EdmMember>(constraint.ToProperties);
                if (Helpers.IsSetEqual(toProperties, toEntitySet.ElementType.KeyMembers, EqualityComparer <EdmMember> .Default))
                {
                    //make sure that the method called with a 1:1 association
                    Debug.Assert(constraint.FromRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One));
                    Debug.Assert(constraint.ToRole.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One));
                    // Create an Equivalence between the two Sets participating in this AssociationSet
                    var fromSetExpression = BoolExpression.CreateLiteral(new RoleBoolean(fromEntitySet), domainMap);
                    var toSetExpression   = BoolExpression.CreateLiteral(new RoleBoolean(toEntitySet), domainMap);
                    AddEquivalence(fromSetExpression.Tree, toSetExpression.Tree);
                }
            }
        }
        internal ViewgenContext(ViewTarget viewTarget, EntitySetBase extent, IEnumerable <Cell> extentCells,
                                CqlIdentifiers identifiers, ConfigViewGenerator config, MemberDomainMap queryDomainMap,
                                MemberDomainMap updateDomainMap, StorageEntityContainerMapping entityContainerMapping)
        {
            foreach (Cell 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
            MemberDomainMap 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
            FragmentQueryKB leftKB = new FragmentQueryKB();

            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
            FragmentQueryKB rightKB        = new FragmentQueryKB();
            MemberDomainMap rightDomainMap = viewTarget == ViewTarget.QueryView ? updateDomainMap : queryDomainMap;

            foreach (LeftCellWrapper leftCellWrapper in m_cellWrappers)
            {
                EntitySetBase rightExtent = leftCellWrapper.RightExtent;
                rightKB.CreateVariableConstraints(rightExtent, rightDomainMap, m_edmItemCollection);
                rightKB.CreateAssociationConstraints(rightExtent, rightDomainMap, m_edmItemCollection);
            }

            if (m_viewTarget == ViewTarget.UpdateView)
            {
                CreateConstraintsForForeignKeyAssociationsAffectingThisWarapper(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);
        }
        /// <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 = this.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, m_edmItemCollection);
            }
        }
Example #7
0
 // creates a condition member=value
 internal static BoolExpression CreateMemberCondition(MemberPath path, Constant domainValue, MemberDomainMap domainMap)
 {
     if (domainValue is TypeConstant)
     {
         return(BoolExpression.CreateLiteral(
                    new TypeRestriction(
                        new MemberProjectedSlot(path),
                        new Domain(domainValue, domainMap.GetDomain(path))), domainMap));
     }
     else
     {
         return(BoolExpression.CreateLiteral(
                    new ScalarRestriction(
                        new MemberProjectedSlot(path),
                        new Domain(domainValue, domainMap.GetDomain(path))), domainMap));
     }
 }