// 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(); }
// 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()); }