private bool TryMergeCellQueries(
            CellTreeOpType opType,
            ref CellTreeNode node1,
            CellTreeNode node2)
        {
            LeafCellTreeNode leafCellTreeNode1 = node1 as LeafCellTreeNode;
            LeafCellTreeNode leafCellTreeNode2 = node2 as LeafCellTreeNode;
            CellQuery        mergedQuery1;
            CellQuery        mergedQuery2;

            if (!CellTreeSimplifier.TryMergeTwoCellQueries(leafCellTreeNode1.LeftCellWrapper.RightCellQuery, leafCellTreeNode2.LeftCellWrapper.RightCellQuery, opType, out mergedQuery1) || !CellTreeSimplifier.TryMergeTwoCellQueries(leafCellTreeNode1.LeftCellWrapper.LeftCellQuery, leafCellTreeNode2.LeftCellWrapper.LeftCellQuery, opType, out mergedQuery2))
            {
                return(false);
            }
            OpCellTreeNode opCellTreeNode = new OpCellTreeNode(this.m_viewgenContext, opType);

            opCellTreeNode.Add(node1);
            opCellTreeNode.Add(node2);
            if (opType != CellTreeOpType.FOJ)
            {
                ;
            }
            LeftCellWrapper cellWrapper = new LeftCellWrapper(this.m_viewgenContext.ViewTarget, opCellTreeNode.Attributes, opCellTreeNode.LeftFragmentQuery, mergedQuery2, mergedQuery1, this.m_viewgenContext.MemberMaps, leafCellTreeNode1.LeftCellWrapper.Cells.Concat <Cell>(leafCellTreeNode2.LeftCellWrapper.Cells));

            node1 = (CellTreeNode) new LeafCellTreeNode(this.m_viewgenContext, cellWrapper, opCellTreeNode.RightFragmentQuery);
            return(true);
        }
Exemple #2
0
 // effects: Creates a node with operation opType and no children
 internal OpCellTreeNode(ViewgenContext context, CellTreeOpType opType)
     : base(context)
 {
     m_opType   = opType;
     m_attrs    = new AttributeSet(MemberPath.EqualityComparer);
     m_children = new List <CellTreeNode>();
 }
        private static FragmentQuery GenerateFragmentQuery(
            IEnumerable <CellTreeNode> children,
            bool isLeft,
            ViewgenContext context,
            CellTreeOpType OpType)
        {
            FragmentQuery          fragmentQuery1         = isLeft ? children.First <CellTreeNode>().LeftFragmentQuery : children.First <CellTreeNode>().RightFragmentQuery;
            FragmentQueryProcessor fragmentQueryProcessor = isLeft ? context.LeftFragmentQP : context.RightFragmentQP;

            foreach (CellTreeNode cellTreeNode in children.Skip <CellTreeNode>(1))
            {
                FragmentQuery fragmentQuery2 = isLeft ? cellTreeNode.LeftFragmentQuery : cellTreeNode.RightFragmentQuery;
                switch (OpType)
                {
                case CellTreeOpType.LOJ:
                    continue;

                case CellTreeOpType.IJ:
                    fragmentQuery1 = fragmentQueryProcessor.Intersect(fragmentQuery1, fragmentQuery2);
                    continue;

                case CellTreeOpType.LASJ:
                    fragmentQuery1 = fragmentQueryProcessor.Difference(fragmentQuery1, fragmentQuery2);
                    continue;

                default:
                    fragmentQuery1 = fragmentQueryProcessor.Union(fragmentQuery1, fragmentQuery2);
                    continue;
                }
            }
            return(fragmentQuery1);
        }
 internal OpCellTreeNode(
     ViewgenContext context,
     CellTreeOpType opType,
     params CellTreeNode[] children)
     : this(context, opType, (IEnumerable <CellTreeNode>)children)
 {
 }
 internal OpCellTreeNode(ViewgenContext context, CellTreeOpType opType)
     : base(context)
 {
     this.m_opType   = opType;
     this.m_attrs    = new Set <MemberPath>(MemberPath.EqualityComparer);
     this.m_children = new List <CellTreeNode>();
 }
        // requires: node1 and node2 are two children of the same parent
        // connected by opType
        // effects: Given two cell tree nodes, node1 and node2, runs the
        // TM/SP rule on them to merge them (if they belong to the same
        // extent). Returns true if the merge succeeds
        private bool TryMergeCellQueries(
            CellTreeOpType opType, ref CellTreeNode node1,
            CellTreeNode node2)
        {
            var leaf1 = node1 as LeafCellTreeNode;
            var leaf2 = node2 as LeafCellTreeNode;

            Debug.Assert(leaf1 != null, "Merge only possible on leaf nodes (1)");
            Debug.Assert(leaf2 != null, "Merge only possible on leaf nodes (2)");

            CellQuery mergedLeftCellQuery;
            CellQuery mergedRightCellQuery;

            if (
                !TryMergeTwoCellQueries(
                    leaf1.LeftCellWrapper.RightCellQuery, leaf2.LeftCellWrapper.RightCellQuery, opType, out mergedRightCellQuery))
            {
                return(false);
            }

            if (
                !TryMergeTwoCellQueries(
                    leaf1.LeftCellWrapper.LeftCellQuery, leaf2.LeftCellWrapper.LeftCellQuery, opType, out mergedLeftCellQuery))
            {
                return(false);
            }

            // Create a temporary node and add the two children
            // so that we can get the merged selectiondomains and attributes
            // Note that temp.SelectionDomain below determines the domain
            // based on the opType, e.g., for IJ, it intersects the
            // multiconstants of all the children
            var temp = new OpCellTreeNode(m_viewgenContext, opType);

            temp.Add(node1);
            temp.Add(node2);
            // Note: We are losing the original cell number information here and the line number information
            // But we will not raise any

            // We do not create CellExpressions with LOJ, FOJ - canBooleansOverlap is true for validation
            var inputOpType = opType;

            if (opType == CellTreeOpType.FOJ ||
                opType == CellTreeOpType.LOJ)
            {
                inputOpType = CellTreeOpType.IJ;
            }

            var wrapper = new LeftCellWrapper(
                m_viewgenContext.ViewTarget, temp.Attributes,
                temp.LeftFragmentQuery,
                mergedLeftCellQuery,
                mergedRightCellQuery,
                m_viewgenContext.MemberMaps,
                leaf1.LeftCellWrapper.Cells.Concat(leaf2.LeftCellWrapper.Cells));

            node1 = new LeafCellTreeNode(m_viewgenContext, wrapper, temp.RightFragmentQuery);
            return(true);
        }
 internal static bool IsAssociativeOp(CellTreeOpType opType)
 {
     if (opType != CellTreeOpType.IJ && opType != CellTreeOpType.Union)
     {
         return(opType == CellTreeOpType.FOJ);
     }
     return(true);
 }
        // effects: Given a set of nodes, determines if all nodes are the exact same associative opType AND
        // there are leaf children that are common across the children "nodes". If there are any,
        // returns them. Else return null
        private static Set <LeafCellTreeNode> GetCommonGrandChildren(List <CellTreeNode> nodes)
        {
            Set <LeafCellTreeNode> commonLeaves = null;

            // We could make this general and apply recursively but we don't for now

            // Look for a tree of the form: (common op2 gc2) op1 (common op2 gc3) op1 (common op2 gc4)
            // e.g., (A IJ B IJ X IJ Y) UNION (A IJ B IJ Y IJ Z) UNION (A IJ B IJ R IJ S)
            // Where op1 and op2 are associative and common, gc2 etc are leaf nodes
            CellTreeOpType commonChildOpType = CellTreeOpType.Leaf;

            foreach (CellTreeNode node in nodes)
            {
                OpCellTreeNode opNode = node as OpCellTreeNode;
                if (opNode == null)
                {
                    return(null);
                }
                Debug.Assert(opNode.OpType != CellTreeOpType.Leaf, "Leaf type for op cell node?");
                // Now check for whether the op is associative and the same as the previous one
                if (commonChildOpType == CellTreeOpType.Leaf)
                {
                    commonChildOpType = opNode.OpType;
                }
                else if (CellTreeNode.IsAssociativeOp(opNode.OpType) == false || commonChildOpType != opNode.OpType)
                {
                    return(null);
                }

                // Make sure all the children are leaf children
                Set <LeafCellTreeNode> nodeChildrenSet = new Set <LeafCellTreeNode>(LeafCellTreeNode.EqualityComparer);
                foreach (CellTreeNode grandChild in opNode.Children)
                {
                    LeafCellTreeNode leafGrandChild = grandChild as LeafCellTreeNode;
                    if (leafGrandChild == null)
                    {
                        return(null);
                    }
                    nodeChildrenSet.Add(leafGrandChild);
                }

                if (commonLeaves == null)
                {
                    commonLeaves = nodeChildrenSet;
                }
                else
                {
                    commonLeaves.Intersect(nodeChildrenSet);
                }
            }

            if (commonLeaves.Count == 0)
            {
                // No restructuring possible
                return(null);
            }
            return(commonLeaves);
        }
Exemple #9
0
 // effects: Given a sequence of children node and the opType, creates
 // an OpCellTreeNode and returns it
 internal OpCellTreeNode(ViewgenContext context, CellTreeOpType opType, IEnumerable <CellTreeNode> children)
     : this(context, opType)
 {
     // Add the children one by one so that we can get the attrs etc fixed
     foreach (CellTreeNode child in children)
     {
         Add(child);
     }
 }
        private SlotInfo GetJoinSlotInfo(
            CellTreeOpType opType,
            bool isRequiredSlot,
            List <CqlBlock> children,
            int slotNum,
            CqlIdentifiers identifiers)
        {
            if (!isRequiredSlot)
            {
                return(new SlotInfo(false, false, (ProjectedSlot)null, this.GetMemberPath(slotNum)));
            }
            int           index1        = -1;
            CaseStatement caseStatement = (CaseStatement)null;

            for (int index2 = 0; index2 < children.Count; ++index2)
            {
                CqlBlock child = children[index2];
                if (child.IsProjected(slotNum))
                {
                    if (this.IsKeySlot(slotNum))
                    {
                        index1 = index2;
                        break;
                    }
                    if (opType == CellTreeOpType.IJ)
                    {
                        index1 = OpCellTreeNode.GetInnerJoinChildForSlot(children, slotNum);
                        break;
                    }
                    if (index1 != -1)
                    {
                        if (caseStatement == null)
                        {
                            caseStatement = new CaseStatement(this.GetMemberPath(slotNum));
                            this.AddCaseForOuterJoins(caseStatement, children[index1], slotNum, identifiers);
                        }
                        this.AddCaseForOuterJoins(caseStatement, child, slotNum, identifiers);
                    }
                    index1 = index2;
                }
            }
            MemberPath    memberPath = this.GetMemberPath(slotNum);
            ProjectedSlot slotValue;

            if (caseStatement != null && (caseStatement.Clauses.Count > 0 || caseStatement.ElseValue != null))
            {
                caseStatement.Simplify();
                slotValue = (ProjectedSlot) new CaseStatementProjectedSlot(caseStatement, (IEnumerable <WithRelationship>)null);
            }
            else
            {
                slotValue = index1 < 0 ? (!this.IsBoolSlot(slotNum) ? (ProjectedSlot) new ConstantProjectedSlot(Domain.GetDefaultValueForMemberPath(memberPath, (IEnumerable <LeftCellWrapper>) this.GetLeaves(), this.ViewgenContext.Config)) : (ProjectedSlot) new BooleanProjectedSlot(BoolExpression.False, identifiers, this.SlotToBoolIndex(slotNum))) : (ProjectedSlot)children[index1].QualifySlotWithBlockAlias(slotNum);
            }
            bool enforceNotNull = this.IsBoolSlot(slotNum) && (opType == CellTreeOpType.LOJ && index1 > 0 || opType == CellTreeOpType.FOJ);

            return(new SlotInfo(true, true, slotValue, memberPath, enforceNotNull));
        }
 /// <summary>
 /// Creates a join block (type given by <paramref name="opType"/>) with SELECT (<paramref name="slotInfos"/>), FROM (<paramref name="children"/>),
 /// ON (<paramref name="onClauses"/> - one for each child except 0th), WHERE (true), AS (<paramref name="blockAliasNum"/>).
 /// </summary>
 internal JoinCqlBlock(CellTreeOpType opType,
                       SlotInfo[] slotInfos,
                       List<CqlBlock> children,
                       List<OnClause> onClauses,
                       CqlIdentifiers identifiers,
                       int blockAliasNum)
     : base(slotInfos, children, BoolExpression.True, identifiers, blockAliasNum)
 {
     m_opType = opType;
     m_onClauses = onClauses;
 }
Exemple #12
0
 /// <summary>
 /// Creates a join block (type given by <paramref name="opType"/>) with SELECT (<paramref name="slotInfos"/>), FROM (<paramref name="children"/>),
 /// ON (<paramref name="onClauses"/> - one for each child except 0th), WHERE (true), AS (<paramref name="blockAliasNum"/>).
 /// </summary>
 internal JoinCqlBlock(CellTreeOpType opType,
                       SlotInfo[] slotInfos,
                       List <CqlBlock> children,
                       List <OnClause> onClauses,
                       CqlIdentifiers identifiers,
                       int blockAliasNum)
     : base(slotInfos, children, BoolExpression.True, identifiers, blockAliasNum)
 {
     m_opType    = opType;
     m_onClauses = onClauses;
 }
 internal OpCellTreeNode(
     ViewgenContext context,
     CellTreeOpType opType,
     IEnumerable <CellTreeNode> children)
     : this(context, opType)
 {
     foreach (CellTreeNode child in children)
     {
         this.Add(child);
     }
 }
        private static List <BoolExpression> MergeBoolExpressions(
            CellQuery query1,
            CellQuery query2,
            BoolExpression conjunct1,
            BoolExpression conjunct2,
            CellTreeOpType opType)
        {
            List <BoolExpression> bools1 = query1.BoolVars;
            List <BoolExpression> bools2 = query2.BoolVars;

            if (!conjunct1.IsTrue)
            {
                bools1 = BoolExpression.AddConjunctionToBools(bools1, conjunct1);
            }
            if (!conjunct2.IsTrue)
            {
                bools2 = BoolExpression.AddConjunctionToBools(bools2, conjunct2);
            }
            List <BoolExpression> boolExpressionList = new List <BoolExpression>();

            for (int index = 0; index < bools1.Count; ++index)
            {
                BoolExpression boolExpression = (BoolExpression)null;
                if (bools1[index] == null)
                {
                    boolExpression = bools2[index];
                }
                else if (bools2[index] == null)
                {
                    boolExpression = bools1[index];
                }
                else
                {
                    switch (opType)
                    {
                    case CellTreeOpType.Union:
                        boolExpression = BoolExpression.CreateOr(bools1[index], bools2[index]);
                        break;

                    case CellTreeOpType.IJ:
                        boolExpression = BoolExpression.CreateAnd(bools1[index], bools2[index]);
                        break;

                    case CellTreeOpType.LASJ:
                        boolExpression = BoolExpression.CreateAnd(bools1[index], BoolExpression.CreateNot(bools2[index]));
                        break;
                    }
                }
                boolExpression?.ExpensiveSimplify();
                boolExpressionList.Add(boolExpression);
            }
            return(boolExpressionList);
        }
Exemple #15
0
        // effects: Determines if the childNode can be added as a child of the
        // groupNode using te operation "opTypeToIsolate". E.g., if
        // opTypeToIsolate is inner join, we can add child to group node if
        // childNode and groupNode have the same multiconstantsets, i.e., they have
        // the same selection condition
        // Modifies groupNode to contain groupNode at the appropriate
        // position (for LOJs, the child could be added to the beginning)
        private bool TryAddChildToGroup(
            CellTreeOpType opTypeToIsolate, CellTreeNode childNode,
            OpCellTreeNode groupNode)
        {
            switch (opTypeToIsolate)
            {
            case CellTreeOpType.IJ:
                // For Inner join, the constants of the node and
                // the child must be the same, i.e., if the cells
                // are producing exactly same tuples (same selection)
                if (IsEquivalentTo(childNode, groupNode))
                {
                    groupNode.Add(childNode);
                    return(true);
                }
                break;

            case CellTreeOpType.LOJ:
                // If one cell's selection condition subsumes
                // another, we can use LOJ. We need to check for
                // "subsumes" on both sides
                if (IsContainedIn(childNode, groupNode))
                {
                    groupNode.Add(childNode);
                    return(true);
                }
                else if (IsContainedIn(groupNode, childNode))
                {
                    // child subsumes the whole group -- add it first
                    groupNode.AddFirst(childNode);
                    return(true);
                }
                break;

            case CellTreeOpType.Union:
                // If the selection conditions are disjoint, we can use UNION ALL
                // We cannot use active domain here; disjointness is guaranteed only
                // if we check the entire selection domain
                if (IsDisjoint(childNode, groupNode))
                {
                    groupNode.Add(childNode);
                    return(true);
                }
                break;
            }
            return(false);
        }
Exemple #16
0
        /// <summary>
        /// Given the <paramref name="opType"/>, returns eSQL string corresponding to the op.
        /// </summary>
        internal static string OpToEsql(CellTreeOpType opType)
        {
            switch (opType)
            {
            case CellTreeOpType.FOJ:    return("FULL OUTER JOIN");

            case CellTreeOpType.IJ:     return("INNER JOIN");

            case CellTreeOpType.LOJ:    return("LEFT OUTER JOIN");

            case CellTreeOpType.Union:  return("UNION ALL");

            default:
                Debug.Fail("Unknown operator");
                return(null);
            }
        }
        private static Set <LeafCellTreeNode> GetCommonGrandChildren(
            List <CellTreeNode> nodes)
        {
            Set <LeafCellTreeNode> set            = (Set <LeafCellTreeNode>)null;
            CellTreeOpType         cellTreeOpType = CellTreeOpType.Leaf;

            foreach (CellTreeNode node in nodes)
            {
                OpCellTreeNode opCellTreeNode = node as OpCellTreeNode;
                if (opCellTreeNode == null)
                {
                    return((Set <LeafCellTreeNode>)null);
                }
                if (cellTreeOpType == CellTreeOpType.Leaf)
                {
                    cellTreeOpType = opCellTreeNode.OpType;
                }
                else if (!CellTreeNode.IsAssociativeOp(opCellTreeNode.OpType) || cellTreeOpType != opCellTreeNode.OpType)
                {
                    return((Set <LeafCellTreeNode>)null);
                }
                Set <LeafCellTreeNode> other = new Set <LeafCellTreeNode>(LeafCellTreeNode.EqualityComparer);
                foreach (CellTreeNode child in opCellTreeNode.Children)
                {
                    LeafCellTreeNode element = child as LeafCellTreeNode;
                    if (element == null)
                    {
                        return((Set <LeafCellTreeNode>)null);
                    }
                    other.Add(element);
                }
                if (set == null)
                {
                    set = other;
                }
                else
                {
                    set.Intersect(other);
                }
            }
            if (set.Count == 0)
            {
                return((Set <LeafCellTreeNode>)null);
            }
            return(set);
        }
        internal static string OpToEsql(CellTreeOpType opType)
        {
            switch (opType)
            {
            case CellTreeOpType.Union:
                return("UNION ALL");

            case CellTreeOpType.FOJ:
                return("FULL OUTER JOIN");

            case CellTreeOpType.LOJ:
                return("LEFT OUTER JOIN");

            case CellTreeOpType.IJ:
                return("INNER JOIN");

            default:
                return((string)null);
            }
        }
        internal CellTreeNode IsolateByOperator(
            CellTreeNode rootNode,
            CellTreeOpType opTypeToIsolate)
        {
            List <CellTreeNode> children = rootNode.Children;

            if (children.Count <= 1)
            {
                return(rootNode);
            }
            for (int index = 0; index < children.Count; ++index)
            {
                children[index] = this.IsolateByOperator(children[index], opTypeToIsolate);
            }
            if (rootNode.OpType != CellTreeOpType.FOJ && rootNode.OpType != CellTreeOpType.LOJ || rootNode.OpType == opTypeToIsolate)
            {
                return(rootNode);
            }
            OpCellTreeNode opCellTreeNode = new OpCellTreeNode(this.m_viewgenContext, rootNode.OpType);
            ModifiableIteratorCollection <CellTreeNode> iteratorCollection = new ModifiableIteratorCollection <CellTreeNode>((IEnumerable <CellTreeNode>)children);

            while (!iteratorCollection.IsEmpty)
            {
                OpCellTreeNode groupNode = new OpCellTreeNode(this.m_viewgenContext, opTypeToIsolate);
                CellTreeNode   child     = iteratorCollection.RemoveOneElement();
                groupNode.Add(child);
                foreach (CellTreeNode element in iteratorCollection.Elements())
                {
                    if (this.TryAddChildToGroup(opTypeToIsolate, element, groupNode))
                    {
                        iteratorCollection.RemoveCurrentOfIterator();
                        if (opTypeToIsolate == CellTreeOpType.LOJ)
                        {
                            iteratorCollection.ResetIterator();
                        }
                    }
                }
                opCellTreeNode.Add((CellTreeNode)groupNode);
            }
            return(opCellTreeNode.Flatten());
        }
        private CellTreeNode RestructureTreeForMerges(CellTreeNode rootNode)
        {
            List <CellTreeNode> children = rootNode.Children;

            if (!CellTreeNode.IsAssociativeOp(rootNode.OpType) || children.Count <= 1)
            {
                return(rootNode);
            }
            Set <LeafCellTreeNode> commonGrandChildren = CellTreeSimplifier.GetCommonGrandChildren(children);

            if (commonGrandChildren == null)
            {
                return(rootNode);
            }
            CellTreeOpType        opType             = children[0].OpType;
            List <OpCellTreeNode> opCellTreeNodeList = new List <OpCellTreeNode>(children.Count);

            foreach (OpCellTreeNode opCellTreeNode1 in children)
            {
                List <LeafCellTreeNode> leafCellTreeNodeList = new List <LeafCellTreeNode>(opCellTreeNode1.Children.Count);
                foreach (LeafCellTreeNode child in opCellTreeNode1.Children)
                {
                    if (!commonGrandChildren.Contains(child))
                    {
                        leafCellTreeNodeList.Add(child);
                    }
                }
                OpCellTreeNode opCellTreeNode2 = new OpCellTreeNode(this.m_viewgenContext, opCellTreeNode1.OpType, Helpers.AsSuperTypeList <LeafCellTreeNode, CellTreeNode>((IEnumerable <LeafCellTreeNode>)leafCellTreeNodeList));
                opCellTreeNodeList.Add(opCellTreeNode2);
            }
            CellTreeNode cellTreeNode1 = (CellTreeNode) new OpCellTreeNode(this.m_viewgenContext, rootNode.OpType, Helpers.AsSuperTypeList <OpCellTreeNode, CellTreeNode>((IEnumerable <OpCellTreeNode>)opCellTreeNodeList));
            CellTreeNode cellTreeNode2 = (CellTreeNode) new OpCellTreeNode(this.m_viewgenContext, opType, Helpers.AsSuperTypeList <LeafCellTreeNode, CellTreeNode>((IEnumerable <LeafCellTreeNode>)commonGrandChildren));

            return(new OpCellTreeNode(this.m_viewgenContext, opType, new CellTreeNode[2]
            {
                cellTreeNode2,
                cellTreeNode1
            }).AssociativeFlatten());
        }
        private bool TryAddChildToGroup(
            CellTreeOpType opTypeToIsolate,
            CellTreeNode childNode,
            OpCellTreeNode groupNode)
        {
            switch (opTypeToIsolate)
            {
            case CellTreeOpType.Union:
                if (this.IsDisjoint(childNode, (CellTreeNode)groupNode))
                {
                    groupNode.Add(childNode);
                    return(true);
                }
                break;

            case CellTreeOpType.LOJ:
                if (this.IsContainedIn(childNode, (CellTreeNode)groupNode))
                {
                    groupNode.Add(childNode);
                    return(true);
                }
                if (this.IsContainedIn((CellTreeNode)groupNode, childNode))
                {
                    groupNode.AddFirst(childNode);
                    return(true);
                }
                break;

            case CellTreeOpType.IJ:
                if (this.IsEquivalentTo(childNode, (CellTreeNode)groupNode))
                {
                    groupNode.Add(childNode);
                    return(true);
                }
                break;
            }
            return(false);
        }
Exemple #22
0
        MergeBoolExpressions(
            CellQuery query1, CellQuery query2,
            BoolExpression conjunct1, BoolExpression conjunct2, CellTreeOpType opType)
        {
            var bools1 = query1.BoolVars;
            var bools2 = query2.BoolVars;

            // Add conjuncts to both sets if needed
            if (false == conjunct1.IsTrue)
            {
                bools1 = BoolExpression.AddConjunctionToBools(bools1, conjunct1);
            }

            if (false == conjunct2.IsTrue)
            {
                bools2 = BoolExpression.AddConjunctionToBools(bools2, conjunct2);
            }

            // Perform merge
            Debug.Assert(bools1.Count == bools2.Count);
            var bools = new List <BoolExpression>();

            // Both bools1[i] and bools2[i] be null for some of the i's. When
            // we merge two (leaf) cells (say), only one boolean each is set
            // in it; the rest are all nulls. If the SP/TM rules have been
            // applied, more than one boolean may be non-null in a cell query
            for (var i = 0; i < bools1.Count; i++)
            {
                BoolExpression merged = null;
                if (bools1[i] == null)
                {
                    merged = bools2[i];
                }
                else if (bools2[i] == null)
                {
                    merged = bools1[i];
                }
                else
                {
                    if (opType == CellTreeOpType.IJ)
                    {
                        merged = BoolExpression.CreateAnd(bools1[i], bools2[i]);
                    }
                    else if (opType == CellTreeOpType.Union)
                    {
                        merged = BoolExpression.CreateOr(bools1[i], bools2[i]);
                    }
                    else if (opType == CellTreeOpType.LASJ)
                    {
                        merged = BoolExpression.CreateAnd(
                            bools1[i],
                            BoolExpression.CreateNot(bools2[i]));
                    }
                    else
                    {
                        Debug.Fail("No other operation expected for boolean merge");
                    }
                }
                if (merged != null)
                {
                    merged.ExpensiveSimplify();
                }
                bools.Add(merged);
            }
            return(bools);
        }
Exemple #23
0
        // effects: Merges query2 with this according to the TM/SP rules for opType and
        // returns the merged result. canBooleansOverlap indicates whether the bools in this and query2 can overlap, i.e.
        // the same cells may have contributed to query2 and this earlier in the merge process
        internal static bool TryMergeTwoCellQueries(
            CellQuery query1, CellQuery query2, CellTreeOpType opType,
            out CellQuery mergedQuery)
        {
            mergedQuery = null;
            // Initialize g1 and g2 according to the TM/SP rules for IJ, LOJ, Union, FOJ cases
            BoolExpression g1 = null;
            BoolExpression g2 = null;

            switch (opType)
            {
            case CellTreeOpType.IJ:
                break;

            case CellTreeOpType.LOJ:
            case CellTreeOpType.LASJ:
                g2 = BoolExpression.True;
                break;

            case CellTreeOpType.FOJ:
            case CellTreeOpType.Union:
                g1 = BoolExpression.True;
                g2 = BoolExpression.True;
                break;

            default:
                Debug.Fail("Unsupported operator");
                break;
            }

            var remap =
                new Dictionary <MemberPath, MemberPath>(MemberPath.EqualityComparer);

            //Continue merging only if both queries are over the same source
            MemberPath newRoot;

            if (!query1.Extent.Equals(query2.Extent))
            {
                // could not merge
                return(false);
            }
            else
            {
                newRoot = query1.SourceExtentMemberPath;
            }

            // Conjuncts for ANDing with the previous whereClauses
            var            conjunct1   = BoolExpression.True;
            var            conjunct2   = BoolExpression.True;
            BoolExpression whereClause = null;

            switch (opType)
            {
            case CellTreeOpType.IJ:
                // Project[D1, D2, A, B, C] Select[cond1 and cond2] (T)
                // We simply merge the two lists of booleans -- no conjuct is added
                // conjunct1 and conjunct2 don't change

                // query1.WhereCaluse AND query2.WhereCaluse
                Debug.Assert(g1 == null && g2 == null, "IJ does not affect g1 and g2");
                whereClause = BoolExpression.CreateAnd(query1.WhereClause, query2.WhereClause);
                break;

            case CellTreeOpType.LOJ:
                // conjunct1 does not change since D1 remains as is
                // Project[D1, (expr2 and cond2 and G2) as D2, A, B, C] Select[cond1] (T)
                // D1 does not change. New d2 is the list of booleans expressions
                // for query2 ANDed with g2 AND query2.WhereClause
                Debug.Assert(g1 == null, "LOJ does not affect g1");
                conjunct2 = BoolExpression.CreateAnd(query2.WhereClause, g2);
                // Just query1's whereclause
                whereClause = query1.WhereClause;
                break;

            case CellTreeOpType.FOJ:
            case CellTreeOpType.Union:
                // Project[(expr1 and cond1 and G1) as D1, (expr2 and cond2 and G2) as D2, A, B, C] Select[cond1] (T)
                // New D1 is a list -- newD1 = D1 AND query1.WhereClause AND g1
                // New D1 is a list -- newD2 = D2 AND query2.WhereClause AND g2
                conjunct1 = BoolExpression.CreateAnd(query1.WhereClause, g1);
                conjunct2 = BoolExpression.CreateAnd(query2.WhereClause, g2);

                // The new whereClause -- g1 AND query1.WhereCaluse OR g2 AND query2.WhereClause
                whereClause = BoolExpression.CreateOr(
                    BoolExpression.CreateAnd(query1.WhereClause, g1),
                    BoolExpression.CreateAnd(query2.WhereClause, g2));
                break;

            case CellTreeOpType.LASJ:
                // conjunct1 does not change since D1 remains as is
                // Project[D1, (expr2 and cond2 and G2) as D2, A, B, C] Select[cond1] (T)
                // D1 does not change. New d2 is the list of booleans expressions
                // for query2 ANDed with g2 AND NOT query2.WhereClause
                Debug.Assert(g1 == null, "LASJ does not affect g1");
                conjunct2   = BoolExpression.CreateAnd(query2.WhereClause, g2);
                whereClause = BoolExpression.CreateAnd(query1.WhereClause, BoolExpression.CreateNot(conjunct2));
                break;

            default:
                Debug.Fail("Unsupported operator");
                break;
            }

            // Create the various remapped parts for the cell query --
            // boolean expressions, merged slots, whereclause, duplicate
            // elimination, join tree
            var boolExprs =
                MergeBoolExpressions(query1, query2, conjunct1, conjunct2, opType);

            //BoolExpression.RemapBools(boolExprs, remap);

            ProjectedSlot[] mergedSlots;
            if (false == ProjectedSlot.TryMergeRemapSlots(query1.ProjectedSlots, query2.ProjectedSlots, out mergedSlots))
            {
                // merging failed because two different right slots go to same left slot
                return(false);
            }

            whereClause = whereClause.RemapBool(remap);

            var elimDupl = MergeDupl(query1.SelectDistinctFlag, query2.SelectDistinctFlag);

            whereClause.ExpensiveSimplify();
            mergedQuery = new CellQuery(
                mergedSlots, whereClause,
                boolExprs, elimDupl, newRoot);
            return(true);
        }
Exemple #24
0
        private static FragmentQuery GenerateFragmentQuery(IEnumerable <CellTreeNode> children, bool isLeft, ViewgenContext context, CellTreeOpType OpType)
        {
            Debug.Assert(children.Any());
            FragmentQuery fragmentQuery = isLeft ? children.First().LeftFragmentQuery : children.First().RightFragmentQuery;

            FragmentQueryProcessor qp = isLeft ? context.LeftFragmentQP : context.RightFragmentQP;

            foreach (var child in children.Skip(1))
            {
                FragmentQuery nextQuery = isLeft ? child.LeftFragmentQuery : child.RightFragmentQuery;
                switch (OpType)
                {
                case CellTreeOpType.IJ:
                    fragmentQuery = qp.Intersect(fragmentQuery, nextQuery);
                    break;

                case CellTreeOpType.LOJ:
                    // Left outer join means keeping the domain of the leftmost child
                    break;

                case CellTreeOpType.LASJ:
                    // not used in basic view generation but current validation calls Simplify, so add this for debugging
                    fragmentQuery = qp.Difference(fragmentQuery, nextQuery);
                    break;

                default:
                    // All other operators (Union, FOJ) require union of the domains
                    fragmentQuery = qp.Union(fragmentQuery, nextQuery);
                    break;
                }
            }
            return(fragmentQuery);
        }
        // effects: Merges query2 with this according to the TM/SP rules for opType and
        // returns the merged result. canBooleansOverlap indicates whether the bools in this and query2 can overlap, i.e.
        // the same cells may have contributed to query2 and this earlier in the merge process
        internal bool TryMergeTwoCellQueries(CellQuery query1, CellQuery query2, CellTreeOpType opType,
                               MemberDomainMap memberDomainMap, out CellQuery mergedQuery)
        {

            mergedQuery = null;
            // Initialize g1 and g2 according to the TM/SP rules for IJ, LOJ, Union, FOJ cases
            BoolExpression g1 = null;
            BoolExpression g2 = null;
            switch (opType)
            {
                case CellTreeOpType.IJ:
                    break;
                case CellTreeOpType.LOJ:
                case CellTreeOpType.LASJ:
                    g2 = BoolExpression.True;
                    break;
                case CellTreeOpType.FOJ:
                case CellTreeOpType.Union:
                    g1 = BoolExpression.True;
                    g2 = BoolExpression.True;
                    break;
                default:
                    Debug.Fail("Unsupported operator");
                    break;
            }

            Dictionary<MemberPath, MemberPath> remap =
                new Dictionary<MemberPath, MemberPath>(MemberPath.EqualityComparer);

            //Continue merging only if both queries are over the same source
            MemberPath newRoot;
            if (!query1.Extent.Equals(query2.Extent))
            { // could not merge
                return false;
            }
            else
            {
                newRoot = query1.SourceExtentMemberPath;
            }

            // Conjuncts for ANDing with the previous whereClauses
            BoolExpression conjunct1 = BoolExpression.True;
            BoolExpression conjunct2 = BoolExpression.True;
            BoolExpression whereClause = null;

            switch (opType)
            {
                case CellTreeOpType.IJ:
                    // Project[D1, D2, A, B, C] Select[cond1 and cond2] (T)
                    // We simply merge the two lists of booleans -- no conjuct is added
                    // conjunct1 and conjunct2 don't change

                    // query1.WhereCaluse AND query2.WhereCaluse
                    Debug.Assert(g1 == null && g2 == null, "IJ does not affect g1 and g2");
                    whereClause = BoolExpression.CreateAnd(query1.WhereClause, query2.WhereClause);
                    break;

                case CellTreeOpType.LOJ:
                    // conjunct1 does not change since D1 remains as is
                    // Project[D1, (expr2 and cond2 and G2) as D2, A, B, C] Select[cond1] (T)
                    // D1 does not change. New d2 is the list of booleans expressions
                    // for query2 ANDed with g2 AND query2.WhereClause
                    Debug.Assert(g1 == null, "LOJ does not affect g1");
                    conjunct2 = BoolExpression.CreateAnd(query2.WhereClause, g2);
                    // Just query1's whereclause
                    whereClause = query1.WhereClause;
                    break;

                case CellTreeOpType.FOJ:
                case CellTreeOpType.Union:
                    // Project[(expr1 and cond1 and G1) as D1, (expr2 and cond2 and G2) as D2, A, B, C] Select[cond1] (T)
                    // New D1 is a list -- newD1 = D1 AND query1.WhereClause AND g1
                    // New D1 is a list -- newD2 = D2 AND query2.WhereClause AND g2
                    conjunct1 = BoolExpression.CreateAnd(query1.WhereClause, g1);
                    conjunct2 = BoolExpression.CreateAnd(query2.WhereClause, g2);

                    // The new whereClause -- g1 AND query1.WhereCaluse OR g2 AND query2.WhereClause
                    whereClause = BoolExpression.CreateOr(BoolExpression.CreateAnd(query1.WhereClause, g1),
                                                          BoolExpression.CreateAnd(query2.WhereClause, g2));
                    break;

                case CellTreeOpType.LASJ:
                    // conjunct1 does not change since D1 remains as is
                    // Project[D1, (expr2 and cond2 and G2) as D2, A, B, C] Select[cond1] (T)
                    // D1 does not change. New d2 is the list of booleans expressions
                    // for query2 ANDed with g2 AND NOT query2.WhereClause
                    Debug.Assert(g1 == null, "LASJ does not affect g1");
                    conjunct2 = BoolExpression.CreateAnd(query2.WhereClause, g2);
                    whereClause = BoolExpression.CreateAnd(query1.WhereClause, BoolExpression.CreateNot(conjunct2));
                    break;
                default:
                    Debug.Fail("Unsupported operator");
                    break;
            }

            // Create the various remapped parts for the cell query --
            // boolean expressions, merged slots, whereclause, duplicate
            // elimination, join tree
            List<BoolExpression> boolExprs =
                MergeBoolExpressions(query1, query2, conjunct1, conjunct2, opType);
            //BoolExpression.RemapBools(boolExprs, remap);

            ProjectedSlot[] mergedSlots;
            if (false == ProjectedSlot.TryMergeRemapSlots(query1.ProjectedSlots, query2.ProjectedSlots, out mergedSlots))
            {
                // merging failed because two different right slots go to same left slot
                return false;
            }

            whereClause = whereClause.RemapBool(remap);

            CellQuery.SelectDistinct elimDupl = MergeDupl(query1.SelectDistinctFlag, query2.SelectDistinctFlag);

            whereClause.ExpensiveSimplify();
            mergedQuery = new CellQuery(mergedSlots, whereClause,
                                                  boolExprs, elimDupl, newRoot);
            return true;
        }
Exemple #26
0
        // 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());
        }
        // effects: Restructure tree so that it is better positioned for merges
        private CellTreeNode RestructureTreeForMerges(CellTreeNode rootNode)
        {
            List <CellTreeNode> children = rootNode.Children;

            if (CellTreeNode.IsAssociativeOp(rootNode.OpType) == false || children.Count <= 1)
            {
                return(rootNode);
            }

            // If this node's operator is associative and each child's
            // operator is also associative, check if there is a common set
            // of leaf nodes across all grandchildren

            Set <LeafCellTreeNode> commonGrandChildren = GetCommonGrandChildren(children);

            if (commonGrandChildren == null)
            {
                return(rootNode);
            }

            CellTreeOpType commonChildOpType = children[0].OpType;

            //  We do have the structure that we are looking for
            // (common op2 gc2) op1 (common op2 gc3) op1 (common op2 gc4) becomes
            // common op2 (gc2 op1 gc3 op1 gc4)
            // e.g., (A IJ B IJ X IJ Y) UNION (A IJ B IJ Y IJ Z) UNION (A IJ B IJ R IJ S)
            // becomes A IJ B IJ ((X IJ Y) UNION (Y IJ Z) UNION (R IJ S))

            // From each child in children, get the nodes other than commonGrandChildren - these are gc2, gc3, ...
            // Each gc2 must be connected by op2 as before, i.e., ABC + ACD = A(BC + CD)

            // All children must be OpCellTreeNodes!
            List <OpCellTreeNode> newChildren = new List <OpCellTreeNode>(children.Count);

            foreach (OpCellTreeNode child in children)
            {
                // Remove all children in child that belong to commonGrandChildren
                // All grandChildren must be leaf nodes at this point
                List <LeafCellTreeNode> newGrandChildren = new List <LeafCellTreeNode>(child.Children.Count);
                foreach (LeafCellTreeNode grandChild in child.Children)
                {
                    if (commonGrandChildren.Contains(grandChild) == false)
                    {
                        newGrandChildren.Add(grandChild);
                    }
                }
                // In the above example, child.OpType is IJ
                Debug.Assert(child.OpType == commonChildOpType);
                OpCellTreeNode newChild = new OpCellTreeNode(m_viewgenContext, child.OpType,
                                                             Helpers.AsSuperTypeList <LeafCellTreeNode, CellTreeNode>(newGrandChildren));
                newChildren.Add(newChild);
            }
            // Connect gc2 op1 gc3 op1 gc4 - op1 is UNION in this
            // ((X IJ Y) UNION (Y IJ Z) UNION (R IJ S))
            // rootNode.Type is UNION
            CellTreeNode remainingNodes = new OpCellTreeNode(m_viewgenContext, rootNode.OpType,
                                                             Helpers.AsSuperTypeList <OpCellTreeNode, CellTreeNode>(newChildren));
            // Take the common grandchildren and connect via commonChildType
            // i.e., A IJ B
            CellTreeNode commonNodes = new OpCellTreeNode(m_viewgenContext, commonChildOpType,
                                                          Helpers.AsSuperTypeList <LeafCellTreeNode, CellTreeNode>(commonGrandChildren));

            // Connect both by commonChildType
            CellTreeNode result = new OpCellTreeNode(m_viewgenContext, commonChildOpType,
                                                     new CellTreeNode[] { commonNodes, remainingNodes });

            result = result.AssociativeFlatten();
            return(result);
        }
        internal static bool TryMergeTwoCellQueries(
            CellQuery query1,
            CellQuery query2,
            CellTreeOpType opType,
            out CellQuery mergedQuery)
        {
            mergedQuery = (CellQuery)null;
            BoolExpression boolExpression1 = (BoolExpression)null;
            BoolExpression boolExpression2 = (BoolExpression)null;

            switch (opType)
            {
            case CellTreeOpType.Union:
            case CellTreeOpType.FOJ:
                boolExpression1 = BoolExpression.True;
                boolExpression2 = BoolExpression.True;
                break;

            case CellTreeOpType.LOJ:
            case CellTreeOpType.LASJ:
                boolExpression2 = BoolExpression.True;
                break;
            }
            Dictionary <MemberPath, MemberPath> remap = new Dictionary <MemberPath, MemberPath>(MemberPath.EqualityComparer);

            if (!query1.Extent.Equals((object)query2.Extent))
            {
                return(false);
            }
            MemberPath     extentMemberPath = query1.SourceExtentMemberPath;
            BoolExpression and1             = BoolExpression.True;
            BoolExpression and2             = BoolExpression.True;
            BoolExpression boolExpression3  = (BoolExpression)null;

            switch (opType)
            {
            case CellTreeOpType.Union:
            case CellTreeOpType.FOJ:
                and1            = BoolExpression.CreateAnd(query1.WhereClause, boolExpression1);
                and2            = BoolExpression.CreateAnd(query2.WhereClause, boolExpression2);
                boolExpression3 = BoolExpression.CreateOr(BoolExpression.CreateAnd(query1.WhereClause, boolExpression1), BoolExpression.CreateAnd(query2.WhereClause, boolExpression2));
                break;

            case CellTreeOpType.LOJ:
                and2            = BoolExpression.CreateAnd(query2.WhereClause, boolExpression2);
                boolExpression3 = query1.WhereClause;
                break;

            case CellTreeOpType.IJ:
                boolExpression3 = BoolExpression.CreateAnd(query1.WhereClause, query2.WhereClause);
                break;

            case CellTreeOpType.LASJ:
                and2            = BoolExpression.CreateAnd(query2.WhereClause, boolExpression2);
                boolExpression3 = BoolExpression.CreateAnd(query1.WhereClause, BoolExpression.CreateNot(and2));
                break;
            }
            List <BoolExpression> boolExprs = CellTreeSimplifier.MergeBoolExpressions(query1, query2, and1, and2, opType);

            ProjectedSlot[] result;
            if (!ProjectedSlot.TryMergeRemapSlots(query1.ProjectedSlots, query2.ProjectedSlots, out result))
            {
                return(false);
            }
            BoolExpression whereClause = boolExpression3.RemapBool(remap);

            CellQuery.SelectDistinct elimDupl = CellTreeSimplifier.MergeDupl(query1.SelectDistinctFlag, query2.SelectDistinctFlag);
            whereClause.ExpensiveSimplify();
            mergedQuery = new CellQuery(result, whereClause, boolExprs, elimDupl, extentMemberPath);
            return(true);
        }
Exemple #29
0
 // effects: Returns true iff the Op (e.g., IJ) is associative, i.e.,
 // A OP (B OP C) is the same as (A OP B) OP C or A OP B OP C
 internal static bool IsAssociativeOp(CellTreeOpType opType)
 {
     // This is not true for LOJ and LASJ
     return(opType == CellTreeOpType.IJ || opType == CellTreeOpType.Union ||
            opType == CellTreeOpType.FOJ);
 }
        // 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();
        }
        // effects: Determines if the childNode can be added as a child of the
        // groupNode using te operation "opTypeToIsolate". E.g., if
        // opTypeToIsolate is inner join, we can add child to group node if
        // childNode and groupNode have the same multiconstantsets, i.e., they have
        // the same selection condition
        // Modifies groupNode to contain groupNode at the appropriate
        // position (for LOJs, the child could be added to the beginning)
        private bool TryAddChildToGroup(
            CellTreeOpType opTypeToIsolate, CellTreeNode childNode,
            OpCellTreeNode groupNode)
        {
            switch (opTypeToIsolate)
            {
                case CellTreeOpType.IJ:
                    // For Inner join, the constants of the node and
                    // the child must be the same, i.e., if the cells
                    // are producing exactly same tuples (same selection)
                    if (IsEquivalentTo(childNode, groupNode))
                    {
                        groupNode.Add(childNode);
                        return true;
                    }
                    break;

                case CellTreeOpType.LOJ:
                    // If one cell's selection condition subsumes
                    // another, we can use LOJ. We need to check for
                    // "subsumes" on both sides
                    if (IsContainedIn(childNode, groupNode))
                    {
                        groupNode.Add(childNode);
                        return true;
                    }
                    else if (IsContainedIn(groupNode, childNode))
                    {
                        // child subsumes the whole group -- add it first
                        groupNode.AddFirst(childNode);
                        return true;
                    }
                    break;

                case CellTreeOpType.Union:
                    // If the selection conditions are disjoint, we can use UNION ALL
                    // We cannot use active domain here; disjointness is guaranteed only
                    // if we check the entire selection domain
                    if (IsDisjoint(childNode, groupNode))
                    {
                        groupNode.Add(childNode);
                        return true;
                    }
                    break;
            }
            return false;
        }
Exemple #32
0
        // effects: Generates a SlotInfo object for a slot of a join node. It
        // uses the type of the join operation (opType), whether the slot is
        // required by the parent or not (isRequiredSlot), the children of
        // this node (children) and the number of the slotNum
        private SlotInfo GetJoinSlotInfo(CellTreeOpType opType, bool isRequiredSlot,
                                         List <CqlBlock> children, int slotNum, CqlIdentifiers identifiers)
        {
            if (false == isRequiredSlot)
            {
                // The slot will not be used. So we can set the projected slot to be null
                SlotInfo unrequiredSlotInfo = new SlotInfo(false, false, null, GetMemberPath(slotNum));
                return(unrequiredSlotInfo);
            }

            // For a required slot, determine the child who is contributing to this value
            int           childDefiningSlot = -1;
            CaseStatement caseForOuterJoins = null;

            for (int childNum = 0; childNum < children.Count; childNum++)
            {
                CqlBlock child = children[childNum];
                if (false == child.IsProjected(slotNum))
                {
                    continue;
                }
                // For keys, we can pick any child block. So the first
                // one that we find is fine as well
                if (IsKeySlot(slotNum))
                {
                    childDefiningSlot = childNum;
                    break;
                }
                else if (opType == CellTreeOpType.IJ)
                {
                    // For Inner Joins, most of the time, the entries will be
                    // the same in all the children. However, in some cases,
                    // we will end up with NULL in one child and an actual
                    // value in another -- we should pick up the actual value in that case
                    childDefiningSlot = GetInnerJoinChildForSlot(children, slotNum);
                    break;
                }
                else
                {
                    // For LOJs, we generate a case statement if more than
                    // one child generates the value - until then we do not
                    // create the caseForOuterJoins object
                    if (childDefiningSlot != -1)
                    {
                        // We really need a case statement now
                        // We have the value being generated by another child
                        // We need to fetch the variable from the appropriate child
                        Debug.Assert(false == IsBoolSlot(slotNum), "Boolean slots cannot come from two children");
                        if (caseForOuterJoins == null)
                        {
                            MemberPath outputMember = GetMemberPath(slotNum);
                            caseForOuterJoins = new CaseStatement(outputMember);
                            // Add the child that we had not added in the first shot
                            AddCaseForOuterJoins(caseForOuterJoins, children[childDefiningSlot], slotNum, identifiers);
                        }
                        AddCaseForOuterJoins(caseForOuterJoins, child, slotNum, identifiers);
                    }
                    childDefiningSlot = childNum;
                }
            }

            MemberPath    memberPath = GetMemberPath(slotNum);
            ProjectedSlot slot       = null;

            // Generate the slot value -- case statement slot, or a qualified slot or null or false.
            // If case statement slot has nothing, treat it as null/empty.
            if (caseForOuterJoins != null && (caseForOuterJoins.Clauses.Count > 0 || caseForOuterJoins.ElseValue != null))
            {
                caseForOuterJoins.Simplify();
                slot = new CaseStatementProjectedSlot(caseForOuterJoins, null);
            }
            else if (childDefiningSlot >= 0)
            {
                slot = children[childDefiningSlot].QualifySlotWithBlockAlias(slotNum);
            }
            else
            {
                // need to produce output slot, but don't have a value
                // output NULL for fields or False for bools
                if (IsBoolSlot(slotNum))
                {
                    slot = new BooleanProjectedSlot(BoolExpression.False, identifiers, SlotToBoolIndex(slotNum));
                }
                else
                {
                    slot = new ConstantProjectedSlot(Domain.GetDefaultValueForMemberPath(memberPath, GetLeaves(), ViewgenContext.Config), memberPath);
                }
            }

            // We need to ensure that _from variables are never null since
            // view generation uses 2-valued boolean logic.
            // They can become null in outer joins. We compensate for it by
            // adding AND NOT NULL condition on boolean slots coming from outer joins.
            bool enforceNotNull = IsBoolSlot(slotNum) &&
                                  ((opType == CellTreeOpType.LOJ && childDefiningSlot > 0) ||
                                   opType == CellTreeOpType.FOJ);
            // We set isProjected to be true since we have come up with some value for it
            SlotInfo slotInfo = new SlotInfo(true, true, slot, memberPath, enforceNotNull);

            return(slotInfo);
        }
        MergeBoolExpressions(CellQuery query1, CellQuery query2,
                             BoolExpression conjunct1, BoolExpression conjunct2, CellTreeOpType opType)
        {

            List<BoolExpression> bools1 = query1.BoolVars;
            List<BoolExpression> bools2 = query2.BoolVars;

            // Add conjuncts to both sets if needed
            if (false == conjunct1.IsTrue)
            {
                bools1 = BoolExpression.AddConjunctionToBools(bools1, conjunct1);
            }

            if (false == conjunct2.IsTrue)
            {
                bools2 = BoolExpression.AddConjunctionToBools(bools2, conjunct2);
            }

            // Perform merge
            Debug.Assert(bools1.Count == bools2.Count);
            List<BoolExpression> bools = new List<BoolExpression>();
            // Both bools1[i] and bools2[i] be null for some of the i's. When
            // we merge two (leaf) cells (say), only one boolean each is set
            // in it; the rest are all nulls. If the SP/TM rules have been
            // applied, more than one boolean may be non-null in a cell query
            for (int i = 0; i < bools1.Count; i++)
            {
                BoolExpression merged = null;
                if (bools1[i] == null)
                {
                    merged = bools2[i];
                }
                else if (bools2[i] == null)
                {
                    merged = bools1[i];
                }
                else
                {
                    if (opType == CellTreeOpType.IJ)
                    {
                        merged = BoolExpression.CreateAnd(bools1[i], bools2[i]);
                    }
                    else if (opType == CellTreeOpType.Union)
                    {
                        merged = BoolExpression.CreateOr(bools1[i], bools2[i]);
                    }
                    else if (opType == CellTreeOpType.LASJ)
                    {
                        merged = BoolExpression.CreateAnd(bools1[i],
                                                          BoolExpression.CreateNot(bools2[i]));
                    }
                    else
                    {
                        Debug.Fail("No other operation expected for boolean merge");
                    }
                }
                if (merged != null)
                {
                    merged.ExpensiveSimplify();
                }
                bools.Add(merged);
            }
            return bools;
        }
        // requires: node1 and node2 are two children of the same parent
        // connected by opType
        // effects: Given two cell tree nodes, node1 and node2, runs the
        // TM/SP rule on them to merge them (if they belong to the same
        // extent). Returns true if the merge succeeds
        private bool TryMergeCellQueries(CellTreeOpType opType, ref CellTreeNode node1,
                                         CellTreeNode node2)
        {

            LeafCellTreeNode leaf1 = node1 as LeafCellTreeNode;
            LeafCellTreeNode leaf2 = node2 as LeafCellTreeNode;

            Debug.Assert(leaf1 != null, "Merge only possible on leaf nodes (1)");
            Debug.Assert(leaf2 != null, "Merge only possible on leaf nodes (2)");

            CellQuery mergedLeftCellQuery;
            CellQuery mergedRightCellQuery;
            if (!TryMergeTwoCellQueries(leaf1.LeftCellWrapper.RightCellQuery, leaf2.LeftCellWrapper.RightCellQuery, opType, m_viewgenContext.MemberMaps.RightDomainMap, out mergedRightCellQuery))
            {
                return false;
            }

            if (!TryMergeTwoCellQueries(leaf1.LeftCellWrapper.LeftCellQuery, leaf2.LeftCellWrapper.LeftCellQuery, opType, m_viewgenContext.MemberMaps.LeftDomainMap, out mergedLeftCellQuery))
            {
                return false;
            }

            // Create a temporary node and add the two children
            // so that we can get the merged selectiondomains and attributes
            // Note that temp.SelectionDomain below determines the domain
            // based on the opType, e.g., for IJ, it intersects the
            // multiconstants of all the children
            OpCellTreeNode temp = new OpCellTreeNode(m_viewgenContext, opType);
            temp.Add(node1);
            temp.Add(node2);
            // Note: We are losing the original cell number information here and the line number information
            // But we will not raise any

            // We do not create CellExpressions with LOJ, FOJ - canBooleansOverlap is true for validation
            CellTreeOpType inputOpType = opType;
            if (opType == CellTreeOpType.FOJ || opType == CellTreeOpType.LOJ)
            {
                inputOpType = CellTreeOpType.IJ;
            }

            LeftCellWrapper wrapper = new LeftCellWrapper(m_viewgenContext.ViewTarget, temp.Attributes,
                                                          temp.LeftFragmentQuery,
                                                          mergedLeftCellQuery,
                                                          mergedRightCellQuery,
                                                          m_viewgenContext.MemberMaps,
                                                          leaf1.LeftCellWrapper.Cells.Concat(leaf2.LeftCellWrapper.Cells));
            node1 = new LeafCellTreeNode(m_viewgenContext, wrapper, temp.RightFragmentQuery);
            return true;
        }