// requires: opTypeToIsolate must be LOJ, IJ, or Union
        // effects: Given a tree rooted at rootNode, determines if there
        // are any FOJs that can be replaced by opTypeToIsolate. If so,
        // does that and a returns a new tree with the replaced operators
        // Note: Method may modify rootNode's contents and children
        internal CellTreeNode IsolateByOperator(CellTreeNode rootNode, CellTreeOpType opTypeToIsolate)
        {
            Debug.Assert(
                opTypeToIsolate == CellTreeOpType.IJ || opTypeToIsolate == CellTreeOpType.LOJ
                || opTypeToIsolate == CellTreeOpType.Union,
                "IsolateJoins can only be called for IJs, LOJs, and Unions");

            var children = rootNode.Children;
            if (children.Count <= 1)
            {
                // No child or one child -  do nothing
                return rootNode;
            }

            // Replace the FOJs with IJs/LOJs/Unions in the children's subtrees first
            for (var i = 0; i < children.Count; i++)
            {
                // Method modifies input as well
                children[i] = IsolateByOperator(children[i], opTypeToIsolate);
            }
            // Only FOJs and LOJs can be coverted (to IJs, Unions, LOJs) --
            // so if the node is not that, we can ignore it (or if the node is already of
            // the same type that we want)
            if (rootNode.OpType != CellTreeOpType.FOJ && rootNode.OpType != CellTreeOpType.LOJ
                ||
                rootNode.OpType == opTypeToIsolate)
            {
                return rootNode;
            }

            // Create a new node with the same type as the input cell node type
            var newRootNode = new OpCellTreeNode(m_viewgenContext, rootNode.OpType);

            // We start a new "group" with one of the children X - we create
            // a newChildNode with type "opTypeToIsolate". Then we
            // determine if any of the remaining children should be in the
            // same group as X.

            // childrenSet keeps track of the children that need to be procesed/partitioned
            var childrenSet = new ModifiableIteratorCollection<CellTreeNode>(children);

            // Find groups with same or subsumed constants and create a join
            // or union node for them. We do this so that some of the FOJs
            // can be replaced by union and join nodes
            // 
            while (false == childrenSet.IsEmpty)
            {
                // Start a new "group" with some child  node (for the opTypeToIsolate node type)

                var groupNode = new OpCellTreeNode(m_viewgenContext, opTypeToIsolate);
                var someChild = childrenSet.RemoveOneElement();
                groupNode.Add(someChild);

                // Go through the remaining children and determine if their
                // constants are subsets/equal/disjoint w.r.t the joinNode
                // constants.

                foreach (var child in childrenSet.Elements())
                {
                    // Check if we can add the child as part of this
                    // groupNode (with opTypeToIsolate being LOJ, IJ, or Union)
                    if (TryAddChildToGroup(opTypeToIsolate, child, groupNode))
                    {
                        childrenSet.RemoveCurrentOfIterator();

                        // For LOJ, suppose that child A did not subsume B or
                        // vice-versa. But child C subsumes both. To ensure
                        // that we can get A, B, C in the same group, we
                        // reset the iterator so that when C is added in B's
                        // loop, we can reconsider A.
                        //
                        // For IJ, adding a child to groupNode does not change the range of it,
                        // so there is no need to reconsider previously skipped children.
                        //
                        // For Union, adding a child to groupNode increases the range of the groupNode,
                        // hence previously skipped (because they weren't disjoint with groupNode) children will continue 
                        // being ignored because they would still have an overlap with one of the nodes inside groupNode.

                        if (opTypeToIsolate == CellTreeOpType.LOJ)
                        {
                            childrenSet.ResetIterator();
                        }
                    }
                }
                // The new Union/LOJ/IJ node needs to be connected to the root
                newRootNode.Add(groupNode);
            }
            return newRootNode.Flatten();
        }
Exemple #2
0
        // requires: cellTreeNode has a tree such that all its intermediate nodes
        // are FOJ nodes only
        // effects: Converts the tree rooted at rootNode (recursively) in
        // following way and returns a new rootNode -- it partitions
        // rootNode's children such that no two different partitions have
        // any overlapping constants. These partitions are connected by Union
        // nodes (since there is no overlapping).
        // Note: Method may modify rootNode's contents and children
        private CellTreeNode IsolateUnions(CellTreeNode rootNode)
        {
            if (rootNode.Children.Count <= 1)
            {
                // No partitioning of children needs to be done
                return(rootNode);
            }

            Debug.Assert(rootNode.OpType == CellTreeOpType.FOJ, "So far, we have FOJs only");

            // Recursively, transform the subtrees rooted at cellTreeNode's children
            for (var i = 0; i < rootNode.Children.Count; i++)
            {
                // Method modifies input as well
                rootNode.Children[i] = IsolateUnions(rootNode.Children[i]);
            }

            // Different children groups are connected by a Union
            // node -- the secltion domain of one group is disjoint from
            // another group's selection domain, i.e., group A1 contributes
            // tuples to the extent which are disjoint from the tuples by
            // A2. So we can connect these groups by union alls.
            // Inside each group, we continue to connect children of the same
            // group using FOJ
            var unionNode = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.Union);

            // childrenSet keeps track of the children that need to be procesed/partitioned
            var childrenSet = new ModifiableIteratorCollection <CellTreeNode>(rootNode.Children);

            while (false == childrenSet.IsEmpty)
            {
                // Start a new group
                // Make an FOJ node to connect children of the same group
                var fojNode = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.FOJ);

                // Add one of the root's children as a child to the foj node
                var someChild = childrenSet.RemoveOneElement();
                fojNode.Add(someChild);

                // We now want a transitive closure of the overlap between the
                // the children node. We keep checking each child with the
                // fojNode and add it as a child of fojNode if there is an
                // overlap. Note that when a node is added to the fojNode,
                // its constants are propagated to the fojNode -- so we do
                // get transitive closure in terms of intersection
                foreach (var child in childrenSet.Elements())
                {
                    if (!IsDisjoint(fojNode, child))
                    {
                        fojNode.Add(child);
                        childrenSet.RemoveCurrentOfIterator();
                        // To ensure that we get all overlapping node, we
                        // need to restart checking all the children
                        childrenSet.ResetIterator();
                    }
                }
                // Now we have a group of children nodes rooted at
                // fojNode. Add this fojNode to the union
                unionNode.Add(fojNode);
            }

            // The union node as the root of the view
            var result = unionNode.Flatten();

            return(result);
        }
        // requires: cellTreeNode has a tree such that all its intermediate nodes
        // are FOJ nodes only
        // effects: Converts the tree rooted at rootNode (recursively) in
        // following way and returns a new rootNode -- it partitions
        // rootNode's children such that no two different partitions have
        // any overlapping constants. These partitions are connected by Union
        // nodes (since there is no overlapping).
        // Note: Method may modify rootNode's contents and children
        private CellTreeNode IsolateUnions(CellTreeNode rootNode)
        {
            if (rootNode.Children.Count <= 1)
            {
                // No partitioning of children needs to be done
                return rootNode;
            }

            Debug.Assert(rootNode.OpType == CellTreeOpType.FOJ, "So far, we have FOJs only");

            // Recursively, transform the subtrees rooted at cellTreeNode's children
            for (var i = 0; i < rootNode.Children.Count; i++)
            {
                // Method modifies input as well
                rootNode.Children[i] = IsolateUnions(rootNode.Children[i]);
            }

            // Different children groups are connected by a Union
            // node -- the secltion domain of one group is disjoint from
            // another group's selection domain, i.e., group A1 contributes
            // tuples to the extent which are disjoint from the tuples by
            // A2. So we can connect these groups by union alls.
            // Inside each group, we continue to connect children of the same
            // group using FOJ
            var unionNode = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.Union);

            // childrenSet keeps track of the children that need to be procesed/partitioned
            var childrenSet = new ModifiableIteratorCollection<CellTreeNode>(rootNode.Children);

            while (false == childrenSet.IsEmpty)
            {
                // Start a new group
                // Make an FOJ node to connect children of the same group
                var fojNode = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.FOJ);

                // Add one of the root's children as a child to the foj node
                var someChild = childrenSet.RemoveOneElement();
                fojNode.Add(someChild);

                // We now want a transitive closure of the overlap between the 
                // the children node. We keep checking each child with the
                // fojNode and add it as a child of fojNode if there is an
                // overlap. Note that when a node is added to the fojNode,
                // its constants are propagated to the fojNode -- so we do
                // get transitive closure in terms of intersection 
                foreach (var child in childrenSet.Elements())
                {
                    if (!IsDisjoint(fojNode, child))
                    {
                        fojNode.Add(child);
                        childrenSet.RemoveCurrentOfIterator();
                        // To ensure that we get all overlapping node, we
                        // need to restart checking all the children
                        childrenSet.ResetIterator();
                    }
                }
                // Now we have a group of children nodes rooted at
                // fojNode. Add this fojNode to the union
                unionNode.Add(fojNode);
            }

            // The union node as the root of the view
            var result = unionNode.Flatten();
            return result;
        }
        // requires: opTypeToIsolate must be LOJ, IJ, or Union
        // effects: Given a tree rooted at rootNode, determines if there
        // are any FOJs that can be replaced by opTypeToIsolate. If so,
        // does that and a returns a new tree with the replaced operators
        // Note: Method may modify rootNode's contents and children
        internal CellTreeNode IsolateByOperator(CellTreeNode rootNode, CellTreeOpType opTypeToIsolate)
        {
            Debug.Assert(
                opTypeToIsolate == CellTreeOpType.IJ || opTypeToIsolate == CellTreeOpType.LOJ ||
                opTypeToIsolate == CellTreeOpType.Union,
                "IsolateJoins can only be called for IJs, LOJs, and Unions");

            var children = rootNode.Children;

            if (children.Count <= 1)
            {
                // No child or one child -  do nothing
                return(rootNode);
            }

            // Replace the FOJs with IJs/LOJs/Unions in the children's subtrees first
            for (var i = 0; i < children.Count; i++)
            {
                // Method modifies input as well
                children[i] = IsolateByOperator(children[i], opTypeToIsolate);
            }
            // Only FOJs and LOJs can be coverted (to IJs, Unions, LOJs) --
            // so if the node is not that, we can ignore it (or if the node is already of
            // the same type that we want)
            if (rootNode.OpType != CellTreeOpType.FOJ && rootNode.OpType != CellTreeOpType.LOJ
                ||
                rootNode.OpType == opTypeToIsolate)
            {
                return(rootNode);
            }

            // Create a new node with the same type as the input cell node type
            var newRootNode = new OpCellTreeNode(m_viewgenContext, rootNode.OpType);

            // We start a new "group" with one of the children X - we create
            // a newChildNode with type "opTypeToIsolate". Then we
            // determine if any of the remaining children should be in the
            // same group as X.

            // childrenSet keeps track of the children that need to be procesed/partitioned
            var childrenSet = new ModifiableIteratorCollection <CellTreeNode>(children);

            // Find groups with same or subsumed constants and create a join
            // or union node for them. We do this so that some of the FOJs
            // can be replaced by union and join nodes
            //
            while (false == childrenSet.IsEmpty)
            {
                // Start a new "group" with some child  node (for the opTypeToIsolate node type)

                var groupNode = new OpCellTreeNode(m_viewgenContext, opTypeToIsolate);
                var someChild = childrenSet.RemoveOneElement();
                groupNode.Add(someChild);

                // Go through the remaining children and determine if their
                // constants are subsets/equal/disjoint w.r.t the joinNode
                // constants.

                foreach (var child in childrenSet.Elements())
                {
                    // Check if we can add the child as part of this
                    // groupNode (with opTypeToIsolate being LOJ, IJ, or Union)
                    if (TryAddChildToGroup(opTypeToIsolate, child, groupNode))
                    {
                        childrenSet.RemoveCurrentOfIterator();

                        // For LOJ, suppose that child A did not subsume B or
                        // vice-versa. But child C subsumes both. To ensure
                        // that we can get A, B, C in the same group, we
                        // reset the iterator so that when C is added in B's
                        // loop, we can reconsider A.
                        //
                        // For IJ, adding a child to groupNode does not change the range of it,
                        // so there is no need to reconsider previously skipped children.
                        //
                        // For Union, adding a child to groupNode increases the range of the groupNode,
                        // hence previously skipped (because they weren't disjoint with groupNode) children will continue
                        // being ignored because they would still have an overlap with one of the nodes inside groupNode.

                        if (opTypeToIsolate == CellTreeOpType.LOJ)
                        {
                            childrenSet.ResetIterator();
                        }
                    }
                }
                // The new Union/LOJ/IJ node needs to be connected to the root
                newRootNode.Add(groupNode);
            }
            return(newRootNode.Flatten());
        }