private void CheckImplication(
            SchemaConstraints <ViewKeyConstraint> cViewConstraints,
            SchemaConstraints <ViewKeyConstraint> sViewConstraints)
        {
            this.CheckImplicationKeyConstraints(cViewConstraints, sViewConstraints);
            KeyToListMap <CellGroupValidator.ExtentPair, ViewKeyConstraint> keyToListMap = new KeyToListMap <CellGroupValidator.ExtentPair, ViewKeyConstraint>((IEqualityComparer <CellGroupValidator.ExtentPair>)EqualityComparer <CellGroupValidator.ExtentPair> .Default);

            foreach (ViewKeyConstraint keyConstraint in cViewConstraints.KeyConstraints)
            {
                CellGroupValidator.ExtentPair key = new CellGroupValidator.ExtentPair(keyConstraint.Cell.CQuery.Extent, keyConstraint.Cell.SQuery.Extent);
                keyToListMap.Add(key, keyConstraint);
            }
            foreach (CellGroupValidator.ExtentPair key in keyToListMap.Keys)
            {
                ReadOnlyCollection <ViewKeyConstraint> readOnlyCollection = keyToListMap.ListForKey(key);
                bool flag = false;
                foreach (ViewKeyConstraint second in readOnlyCollection)
                {
                    foreach (ViewKeyConstraint keyConstraint in sViewConstraints.KeyConstraints)
                    {
                        if (keyConstraint.Implies(second))
                        {
                            flag = true;
                            break;
                        }
                    }
                }
                if (!flag)
                {
                    this.m_errorLog.AddEntry(ViewKeyConstraint.GetErrorRecord((IEnumerable <ViewKeyConstraint>)readOnlyCollection));
                }
            }
        }
        internal List <Set <Cell> > GroupRelatedCells()
        {
            UndirectedGraph <EntitySetBase>         undirectedGraph = new UndirectedGraph <EntitySetBase>((IEqualityComparer <EntitySetBase>)EqualityComparer <EntitySetBase> .Default);
            Dictionary <EntitySetBase, Set <Cell> > extentToCell    = new Dictionary <EntitySetBase, Set <Cell> >((IEqualityComparer <EntitySetBase>)EqualityComparer <EntitySetBase> .Default);

            foreach (Cell cell in this.m_cells)
            {
                EntitySetBase[] entitySetBaseArray = new EntitySetBase[2]
                {
                    cell.CQuery.Extent,
                    cell.SQuery.Extent
                };
                foreach (EntitySetBase index in entitySetBaseArray)
                {
                    Set <Cell> set;
                    if (!extentToCell.TryGetValue(index, out set))
                    {
                        extentToCell[index] = set = new Set <Cell>();
                    }
                    set.Add(cell);
                    undirectedGraph.AddVertex(index);
                }
                undirectedGraph.AddEdge(cell.CQuery.Extent, cell.SQuery.Extent);
                AssociationSet extent = cell.CQuery.Extent as AssociationSet;
                if (extent != null)
                {
                    foreach (AssociationSetEnd associationSetEnd in extent.AssociationSetEnds)
                    {
                        undirectedGraph.AddEdge((EntitySetBase)associationSetEnd.EntitySet, (EntitySetBase)extent);
                    }
                }
            }
            foreach (ForeignConstraint foreignKeyConstraint in this.m_foreignKeyConstraints)
            {
                undirectedGraph.AddEdge((EntitySetBase)foreignKeyConstraint.ChildTable, (EntitySetBase)foreignKeyConstraint.ParentTable);
            }
            KeyToListMap <int, EntitySetBase> connectedComponents = undirectedGraph.GenerateConnectedComponents();
            List <Set <Cell> > setList = new List <Set <Cell> >();

            foreach (int key in connectedComponents.Keys)
            {
                IEnumerable <Set <Cell> > sets = connectedComponents.ListForKey(key).Select <EntitySetBase, Set <Cell> >((Func <EntitySetBase, Set <Cell> >)(e => extentToCell[e]));
                Set <Cell> set1 = new Set <Cell>();
                foreach (Set <Cell> set2 in sets)
                {
                    set1.AddRange((IEnumerable <Cell>)set2);
                }
                setList.Add(set1);
            }
            return(setList);
        }
Exemple #3
0
        // effects: Given a graph of cell groups, returns a list of cellgroup
        // such that each cellgroup contains all the cells that are in the
        // same connected component
        private static List <CellGroup> GenerateConnectedComponents(UndirectedGraph <Cell> graph)
        {
            KeyToListMap <int, Cell> groupMap = graph.GenerateConnectedComponents();

            // Run through the list of groups and generate the merged groups
            List <CellGroup> result = new List <CellGroup>();

            foreach (int setNum in groupMap.Keys)
            {
                ReadOnlyCollection <Cell> cellsInComponent = groupMap.ListForKey(setNum);
                CellGroup component = new CellGroup(cellsInComponent);
                result.Add(component);
            }
            return(result);
        }
        // effects: A restrictive version of GroupLeafChildrenByExtent --
        // only for LASJ and LOJ nodes (works for LOJ only when A LOJ B LOJ C
        // s.t., B and C are subsets of A -- in our case that is how LOJs are constructed
        private static List <CellTreeNode> GroupNonAssociativeLeafChildren(List <CellTreeNode> nodes)
        {
            // Keep track of leaf cells for each extent ignoring the 0th child
            var extentMap =
                new KeyToListMap <EntitySetBase, CellTreeNode>(EqualityComparer <EntitySetBase> .Default);

            var newNodes     = new List <CellTreeNode>();
            var nonLeafNodes = new List <CellTreeNode>();

            // Add the 0th child
            newNodes.Add(nodes[0]);
            for (var i = 1; i < nodes.Count; i++)
            {
                var node     = nodes[i];
                var leafNode = node as LeafCellTreeNode;
                // All non-leaf nodes are added to the result now
                // leaf nodes are added outside the loop
                if (leafNode != null)
                {
                    extentMap.Add(leafNode.LeftCellWrapper.RightCellQuery.Extent, leafNode);
                }
                else
                {
                    nonLeafNodes.Add(node);
                }
            }
            // Go through the map and add the leaf children
            // If a group of nodes exists for the 0th node's extent -- place
            // that group first
            var firstNode = nodes[0] as LeafCellTreeNode;

            if (firstNode != null)
            {
                var firstExtent = firstNode.LeftCellWrapper.RightCellQuery.Extent;
                if (extentMap.ContainsKey(firstExtent))
                {
                    newNodes.AddRange(extentMap.ListForKey(firstExtent));
                    // Remove this set from the map
                    extentMap.RemoveKey(firstExtent);
                }
            }
            newNodes.AddRange(extentMap.AllValues);
            newNodes.AddRange(nonLeafNodes);
            return(newNodes);
        }
Exemple #5
0
        // effects: Checks if all sViewConstraints are implied by the
        // constraints in cViewConstraints. If some S-level constraints are
        // not implied, adds errors/warnings to m_errorLog
        private void CheckImplication(ViewSchemaConstraints cViewConstraints, ViewSchemaConstraints sViewConstraints)
        {
            // Check key constraints
            // i.e., if S has a key <k1, k2>, C must have a key that is a subset of this
            CheckImplicationKeyConstraints(cViewConstraints, sViewConstraints);

            // For updates, we need to ensure the following: for every
            // extent E, table T pair, some key of E is implied by T's key

            // Get all key constraints for each extent and each table
            var extentPairConstraints =
                new KeyToListMap <ExtentPair, ViewKeyConstraint>(EqualityComparer <ExtentPair> .Default);

            foreach (var cKeyConstraint in cViewConstraints.KeyConstraints)
            {
                var pair = new ExtentPair(cKeyConstraint.Cell.CQuery.Extent, cKeyConstraint.Cell.SQuery.Extent);
                extentPairConstraints.Add(pair, cKeyConstraint);
            }

            // Now check that we guarantee at least one constraint per
            // extent/table pair
            foreach (var extentPair in extentPairConstraints.Keys)
            {
                var cKeyConstraints = extentPairConstraints.ListForKey(extentPair);
                var sImpliesSomeC   = false;
                // Go through all key constraints for the extent/table pair, and find one that S implies
                foreach (var cKeyConstraint in cKeyConstraints)
                {
                    foreach (var sKeyConstraint in sViewConstraints.KeyConstraints)
                    {
                        if (sKeyConstraint.Implies(cKeyConstraint))
                        {
                            sImpliesSomeC = true;
                            break; // The implication holds - so no problem
                        }
                    }
                }
                if (sImpliesSomeC == false)
                {
                    // Indicate that at least one key must be ensured on the S-side
                    m_errorLog.AddEntry(ViewKeyConstraint.GetErrorRecord(cKeyConstraints));
                }
            }
        }
        internal ErrorLog.Record CheckForDuplicateFields(CellQuery cQuery, Cell sourceCell)
        {
            KeyToListMap <MemberProjectedSlot, int> keyToListMap = new KeyToListMap <MemberProjectedSlot, int>((IEqualityComparer <MemberProjectedSlot>)ProjectedSlot.EqualityComparer);

            for (int index = 0; index < this.m_projectedSlots.Length; ++index)
            {
                MemberProjectedSlot projectedSlot = this.m_projectedSlots[index] as MemberProjectedSlot;
                keyToListMap.Add(projectedSlot, index);
            }
            StringBuilder stringBuilder1 = (StringBuilder)null;
            bool          flag           = false;

            foreach (MemberProjectedSlot key in keyToListMap.Keys)
            {
                ReadOnlyCollection <int> cSideSlotIndexes = keyToListMap.ListForKey(key);
                if (cSideSlotIndexes.Count > 1 && !cQuery.AreSlotsEquivalentViaRefConstraints(cSideSlotIndexes))
                {
                    flag = true;
                    if (stringBuilder1 == null)
                    {
                        stringBuilder1 = new StringBuilder(Strings.ViewGen_Duplicate_CProperties((object)this.Extent.Name));
                        stringBuilder1.AppendLine();
                    }
                    StringBuilder stringBuilder2 = new StringBuilder();
                    for (int index1 = 0; index1 < cSideSlotIndexes.Count; ++index1)
                    {
                        int index2 = cSideSlotIndexes[index1];
                        if (index1 != 0)
                        {
                            stringBuilder2.Append(", ");
                        }
                        MemberProjectedSlot projectedSlot = (MemberProjectedSlot)cQuery.m_projectedSlots[index2];
                        stringBuilder2.Append(projectedSlot.ToUserString());
                    }
                    stringBuilder1.AppendLine(Strings.ViewGen_Duplicate_CProperties_IsMapped((object)key.ToUserString(), (object)stringBuilder2.ToString()));
                }
            }
            if (!flag)
            {
                return((ErrorLog.Record)null);
            }
            return(new ErrorLog.Record(ViewGenErrorCode.DuplicateCPropertiesMapped, stringBuilder1.ToString(), sourceCell, string.Empty));
        }
        // requires: The tree rooted at cellTreeNode is an FOJ tree of
        // LeafCellTreeNodes only, i.e., there is an FOJ node with the
        // children being LeafCellTreeNodes
        //
        // effects: Given a tree rooted at rootNode, ensures that cells
        // of the same right extent are placed in their own subtree below
        // cellTreeNode. That is, if there are 3 cells of extent A and 2 of
        // extent B (i.e., 5 cells with an FOJ on it), the resulting tree has
        // an FOJ node with two children -- FOJ nodes. These FOJ nodes have 2
        // and 3 children
        internal CellTreeNode GroupByRightExtent(CellTreeNode rootNode)
        {
            // A dictionary that maps an extent to the nodes are from that extent
            // We want a ref comparer here
            var extentMap =
                new KeyToListMap <EntitySetBase, LeafCellTreeNode>(EqualityComparer <EntitySetBase> .Default);

            // CR_Meek_Low: method can be simplified (Map<Extent, OpCellTreeNode>, populate as you go)
            // (becomes self-documenting)
            // For each leaf child, find the extent of the child and place it
            // in extentMap
            foreach (LeafCellTreeNode childNode in rootNode.Children)
            {
                // A cell may contain P, P.PA -- we return P
                // CHANGE_ADYA_FEATURE_COMPOSITION Need to fix for composition!!
                var extent = childNode.LeftCellWrapper.RightCellQuery.Extent; // relation or extent to group by
                Debug.Assert(extent != null, "Each cell must have a right extent");

                // Add the childNode as a child of the FOJ tree for "extent"
                extentMap.Add(extent, childNode);
            }
            // Now go through the extent map and create FOJ nodes for each extent
            // Place the nodes for that extent in the newly-created FOJ subtree
            // Also add the op node for every node as a child of the final result
            var result = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.FOJ);

            foreach (var extent in extentMap.Keys)
            {
                var extentFojNode = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.FOJ);
                foreach (var childNode in extentMap.ListForKey(extent))
                {
                    extentFojNode.Add(childNode);
                }
                result.Add(extentFojNode);
            }
            // We call Flatten to remove any unnecessary nestings
            // where an OpNode has only 1 child.
            return(result.Flatten());
        }
        internal CellTreeNode GroupByRightExtent(CellTreeNode rootNode)
        {
            KeyToListMap <EntitySetBase, LeafCellTreeNode> keyToListMap = new KeyToListMap <EntitySetBase, LeafCellTreeNode>((IEqualityComparer <EntitySetBase>)EqualityComparer <EntitySetBase> .Default);

            foreach (LeafCellTreeNode child in rootNode.Children)
            {
                EntitySetBase extent = child.LeftCellWrapper.RightCellQuery.Extent;
                keyToListMap.Add(extent, child);
            }
            OpCellTreeNode opCellTreeNode1 = new OpCellTreeNode(this.m_viewgenContext, CellTreeOpType.FOJ);

            foreach (EntitySetBase key in keyToListMap.Keys)
            {
                OpCellTreeNode opCellTreeNode2 = new OpCellTreeNode(this.m_viewgenContext, CellTreeOpType.FOJ);
                foreach (LeafCellTreeNode leafCellTreeNode in keyToListMap.ListForKey(key))
                {
                    opCellTreeNode2.Add((CellTreeNode)leafCellTreeNode);
                }
                opCellTreeNode1.Add((CellTreeNode)opCellTreeNode2);
            }
            return(opCellTreeNode1.Flatten());
        }
        private static List <CellTreeNode> GroupNonAssociativeLeafChildren(
            List <CellTreeNode> nodes)
        {
            KeyToListMap <EntitySetBase, CellTreeNode> keyToListMap = new KeyToListMap <EntitySetBase, CellTreeNode>((IEqualityComparer <EntitySetBase>)EqualityComparer <EntitySetBase> .Default);
            List <CellTreeNode> cellTreeNodeList1 = new List <CellTreeNode>();
            List <CellTreeNode> cellTreeNodeList2 = new List <CellTreeNode>();

            cellTreeNodeList1.Add(nodes[0]);
            for (int index = 1; index < nodes.Count; ++index)
            {
                CellTreeNode     node             = nodes[index];
                LeafCellTreeNode leafCellTreeNode = node as LeafCellTreeNode;
                if (leafCellTreeNode != null)
                {
                    keyToListMap.Add(leafCellTreeNode.LeftCellWrapper.RightCellQuery.Extent, (CellTreeNode)leafCellTreeNode);
                }
                else
                {
                    cellTreeNodeList2.Add(node);
                }
            }
            LeafCellTreeNode node1 = nodes[0] as LeafCellTreeNode;

            if (node1 != null)
            {
                EntitySetBase extent = node1.LeftCellWrapper.RightCellQuery.Extent;
                if (keyToListMap.ContainsKey(extent))
                {
                    cellTreeNodeList1.AddRange((IEnumerable <CellTreeNode>)keyToListMap.ListForKey(extent));
                    keyToListMap.RemoveKey(extent);
                }
            }
            cellTreeNodeList1.AddRange(keyToListMap.AllValues);
            cellTreeNodeList1.AddRange((IEnumerable <CellTreeNode>)cellTreeNodeList2);
            return(cellTreeNodeList1);
        }
Exemple #10
0
        // requires: All slots in this are join tree slots
        // This method is called for an S-side query
        // cQuery is the corresponding C-side query in the cell
        // sourceCell is the original cell for "this" and cQuery
        // effects: Checks if any of the columns in "this" are mapped to multiple properties in cQuery. If so,
        // returns an error record about the duplicated slots
        internal ErrorLog.Record CheckForDuplicateFields(CellQuery cQuery, Cell sourceCell)
        {
            // slotMap stores the slots on the S-side and the
            // C-side properties that it maps to
            var slotMap = new KeyToListMap <MemberProjectedSlot, int>(ProjectedSlot.EqualityComparer);

            // Note that this does work for self-association. In the manager
            // employee example, ManagerId and EmployeeId from the SEmployee
            // table map to the two ends -- Manager.ManagerId and
            // Employee.EmployeeId in the C Space

            for (var i = 0; i < m_projectedSlots.Length; i++)
            {
                var projectedSlot = m_projectedSlots[i];
                var slot          = projectedSlot as MemberProjectedSlot;
                Debug.Assert(slot != null, "All slots for this method must be JoinTreeSlots");
                slotMap.Add(slot, i);
            }

            StringBuilder builder = null;

            // Now determine the entries that have more than one integer per slot
            var isErrorSituation = false;

            foreach (var slot in slotMap.Keys)
            {
                var indexes = slotMap.ListForKey(slot);
                Debug.Assert(indexes.Count >= 1, "Each slot must have one index at least");

                if (indexes.Count > 1
                    &&
                    cQuery.AreSlotsEquivalentViaRefConstraints(indexes) == false)
                {
                    // The column is mapped to more than one property and it
                    // failed the "association corresponds to referential
                    // constraints" check

                    isErrorSituation = true;
                    if (builder == null)
                    {
                        builder = new StringBuilder(Strings.ViewGen_Duplicate_CProperties(Extent.Name));
                        builder.AppendLine();
                    }
                    var tmpBuilder = new StringBuilder();
                    for (var i = 0; i < indexes.Count; i++)
                    {
                        var index = indexes[i];
                        if (i != 0)
                        {
                            tmpBuilder.Append(", ");
                        }
                        // The slot must be a JoinTreeSlot. If it isn't it is an internal error
                        var cSlot = (MemberProjectedSlot)cQuery.m_projectedSlots[index];
                        tmpBuilder.Append(cSlot.ToUserString());
                    }
                    builder.AppendLine(Strings.ViewGen_Duplicate_CProperties_IsMapped(slot.ToUserString(), tmpBuilder.ToString()));
                }
            }

            if (false == isErrorSituation)
            {
                return(null);
            }

            var record = new ErrorLog.Record(ViewGenErrorCode.DuplicateCPropertiesMapped, builder.ToString(), sourceCell, String.Empty);

            return(record);
        }
        // requires: The tree rooted at cellTreeNode is an FOJ tree of
        // LeafCellTreeNodes only, i.e., there is an FOJ node with the
        // children being LeafCellTreeNodes
        // 
        // effects: Given a tree rooted at rootNode, ensures that cells
        // of the same right extent are placed in their own subtree below
        // cellTreeNode. That is, if there are 3 cells of extent A and 2 of
        // extent B (i.e., 5 cells with an FOJ on it), the resulting tree has
        // an FOJ node with two children -- FOJ nodes. These FOJ nodes have 2
        // and 3 children
        internal CellTreeNode GroupByRightExtent(CellTreeNode rootNode)
        {
            // A dictionary that maps an extent to the nodes are from that extent
            // We want a ref comparer here
            var extentMap =
                new KeyToListMap<EntitySetBase, LeafCellTreeNode>(EqualityComparer<EntitySetBase>.Default);

            // CR_Meek_Low: method can be simplified (Map<Extent, OpCellTreeNode>, populate as you go)
            // (becomes self-documenting)
            // For each leaf child, find the extent of the child and place it
            // in extentMap
            foreach (LeafCellTreeNode childNode in rootNode.Children)
            {
                // A cell may contain P, P.PA -- we return P
                // CHANGE_ADYA_FEATURE_COMPOSITION Need to fix for composition!!
                var extent = childNode.LeftCellWrapper.RightCellQuery.Extent; // relation or extent to group by
                Debug.Assert(extent != null, "Each cell must have a right extent");

                // Add the childNode as a child of the FOJ tree for "extent"
                extentMap.Add(extent, childNode);
            }
            // Now go through the extent map and create FOJ nodes for each extent
            // Place the nodes for that extent in the newly-created FOJ subtree
            // Also add the op node for every node as a child of the final result
            var result = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.FOJ);

            foreach (var extent in extentMap.Keys)
            {
                var extentFojNode = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.FOJ);
                foreach (var childNode in extentMap.ListForKey(extent))
                {
                    extentFojNode.Add(childNode);
                }
                result.Add(extentFojNode);
            }
            // We call Flatten to remove any unnecessary nestings
            // where an OpNode has only 1 child.
            return result.Flatten();
        }
Exemple #12
0
        // requires: All slots in this are join tree slots
        // This method is called for an S-side query
        // cQuery is the corresponding C-side query in the cell
        // sourceCell is the original cell for "this" and cQuery
        // effects: Checks if any of the columns in "this" are mapped to multiple properties in cQuery. If so,
        // returns an error record about the duplicated slots
        internal ErrorLog.Record CheckForDuplicateFields(CellQuery cQuery, Cell sourceCell)
        {
            // slotMap stores the slots on the S-side and the
            // C-side properties that it maps to
            var slotMap = new KeyToListMap<MemberProjectedSlot, int>(ProjectedSlot.EqualityComparer);

            // Note that this does work for self-association. In the manager
            // employee example, ManagerId and EmployeeId from the SEmployee
            // table map to the two ends -- Manager.ManagerId and
            // Employee.EmployeeId in the C Space

            for (var i = 0; i < m_projectedSlots.Length; i++)
            {
                var projectedSlot = m_projectedSlots[i];
                var slot = projectedSlot as MemberProjectedSlot;
                Debug.Assert(slot != null, "All slots for this method must be JoinTreeSlots");
                slotMap.Add(slot, i);
            }

            StringBuilder builder = null;

            // Now determine the entries that have more than one integer per slot
            var isErrorSituation = false;

            foreach (var slot in slotMap.Keys)
            {
                var indexes = slotMap.ListForKey(slot);
                Debug.Assert(indexes.Count >= 1, "Each slot must have one index at least");

                if (indexes.Count > 1
                    &&
                    cQuery.AreSlotsEquivalentViaRefConstraints(indexes) == false)
                {
                    // The column is mapped to more than one property and it
                    // failed the "association corresponds to referential
                    // constraints" check

                    isErrorSituation = true;
                    if (builder == null)
                    {
                        builder = new StringBuilder(Strings.ViewGen_Duplicate_CProperties(Extent.Name));
                        builder.AppendLine();
                    }
                    var tmpBuilder = new StringBuilder();
                    for (var i = 0; i < indexes.Count; i++)
                    {
                        var index = indexes[i];
                        if (i != 0)
                        {
                            tmpBuilder.Append(", ");
                        }
                        // The slot must be a JoinTreeSlot. If it isn't it is an internal error
                        var cSlot = (MemberProjectedSlot)cQuery.m_projectedSlots[index];
                        tmpBuilder.Append(cSlot.ToUserString());
                    }
                    builder.AppendLine(Strings.ViewGen_Duplicate_CProperties_IsMapped(slot.ToUserString(), tmpBuilder.ToString()));
                }
            }

            if (false == isErrorSituation)
            {
                return null;
            }

            var record = new ErrorLog.Record(ViewGenErrorCode.DuplicateCPropertiesMapped, builder.ToString(), sourceCell, String.Empty);
            return record;
        }
        // effects: Checks if all sViewConstraints are implied by the
        // constraints in cViewConstraints. If some S-level constraints are
        // not implied, adds errors/warnings to m_errorLog
        private void CheckImplication(ViewSchemaConstraints cViewConstraints, ViewSchemaConstraints sViewConstraints)
        {
            // Check key constraints
            // i.e., if S has a key <k1, k2>, C must have a key that is a subset of this
            CheckImplicationKeyConstraints(cViewConstraints, sViewConstraints);

            // For updates, we need to ensure the following: for every
            // extent E, table T pair, some key of E is implied by T's key

            // Get all key constraints for each extent and each table
            var extentPairConstraints =
                new KeyToListMap<ExtentPair, ViewKeyConstraint>(EqualityComparer<ExtentPair>.Default);

            foreach (var cKeyConstraint in cViewConstraints.KeyConstraints)
            {
                var pair = new ExtentPair(cKeyConstraint.Cell.CQuery.Extent, cKeyConstraint.Cell.SQuery.Extent);
                extentPairConstraints.Add(pair, cKeyConstraint);
            }

            // Now check that we guarantee at least one constraint per
            // extent/table pair
            foreach (var extentPair in extentPairConstraints.Keys)
            {
                var cKeyConstraints = extentPairConstraints.ListForKey(extentPair);
                var sImpliesSomeC = false;
                // Go through all key constraints for the extent/table pair, and find one that S implies
                foreach (var cKeyConstraint in cKeyConstraints)
                {
                    foreach (var sKeyConstraint in sViewConstraints.KeyConstraints)
                    {
                        if (sKeyConstraint.Implies(cKeyConstraint))
                        {
                            sImpliesSomeC = true;
                            break; // The implication holds - so no problem
                        }
                    }
                }
                if (sImpliesSomeC == false)
                {
                    // Indicate that at least one key must be ensured on the S-side
                    m_errorLog.AddEntry(ViewKeyConstraint.GetErrorRecord(cKeyConstraints));
                }
            }
        }
        // effects: A restrictive version of GroupLeafChildrenByExtent --
        // only for LASJ and LOJ nodes (works for LOJ only when A LOJ B LOJ C
        // s.t., B and C are subsets of A -- in our case that is how LOJs are constructed
        private static List<CellTreeNode> GroupNonAssociativeLeafChildren(List<CellTreeNode> nodes)
        {
            // Keep track of leaf cells for each extent ignoring the 0th child
            KeyToListMap<EntitySetBase, CellTreeNode> extentMap =
                new KeyToListMap<EntitySetBase, CellTreeNode>(EqualityComparer<EntitySetBase>.Default);

            List<CellTreeNode> newNodes = new List<CellTreeNode>();
            List<CellTreeNode> nonLeafNodes = new List<CellTreeNode>();
            // Add the 0th child
            newNodes.Add(nodes[0]);
            for (int i = 1; i < nodes.Count; i++)
            {
                CellTreeNode node = nodes[i];
                LeafCellTreeNode leafNode = node as LeafCellTreeNode;
                // All non-leaf nodes are added to the result now
                // leaf nodes are added outside the loop
                if (leafNode != null)
                {
                    extentMap.Add(leafNode.LeftCellWrapper.RightCellQuery.Extent, leafNode);
                }
                else
                {
                    nonLeafNodes.Add(node);
                }
            }
            // Go through the map and add the leaf children
            // If a group of nodes exists for the 0th node's extent -- place
            // that group first
            LeafCellTreeNode firstNode = nodes[0] as LeafCellTreeNode;
            if (firstNode != null)
            {
                EntitySetBase firstExtent = firstNode.LeftCellWrapper.RightCellQuery.Extent;
                if (extentMap.ContainsKey(firstExtent))
                {
                    newNodes.AddRange(extentMap.ListForKey(firstExtent));
                    // Remove this set from the map
                    extentMap.RemoveKey(firstExtent);
                }
            }
            newNodes.AddRange(extentMap.AllValues);
            newNodes.AddRange(nonLeafNodes);
            return newNodes;
        }