OpCellTreeNode.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / Map / ViewGeneration / Structures / OpCellTreeNode.cs / 2 / OpCellTreeNode.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System.Data.Common.Utils; 
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Mapping.ViewGeneration.CqlGeneration;
using System.Data.Mapping.ViewGeneration.QueryRewriting; 
using System.Text;
using System.Linq; 
using System.Diagnostics; 
using System.Data.Metadata.Edm;
 
namespace System.Data.Mapping.ViewGeneration.Structures {

    using AttributeSet = Set;
 
    // This class represents th intermediate nodes in the tree (non-leaf nodes)
    internal class OpCellTreeNode : CellTreeNode { 
 
        #region Constructors
        // effects: Creates a node with operation opType and no children 
        internal OpCellTreeNode(CellNormalizer normalizer, CellTreeOpType opType)
 			: base(normalizer) {
            m_opType = opType;
            m_attrs = new AttributeSet(MemberPath.EqualityComparer); 
            m_children = new List();
        } 
 
        internal OpCellTreeNode(CellNormalizer normalizer, CellTreeOpType opType, params CellTreeNode[] children)
            : this(normalizer, opType, (IEnumerable)children) { } 

        // effects: Given a sequence of children node and the opType, creates
        // an OpCellTreeNode and returns it
        internal OpCellTreeNode(CellNormalizer normalizer, CellTreeOpType opType, IEnumerable children) 
            : this(normalizer, opType) {
            // Add the children one by one so that we can get the attrs etc fixed 
            foreach (CellTreeNode child in children) { 
                Add(child);
            } 
        }

        #endregion
 
        #region Fields
        private Set m_attrs; // attributes from whole subtree below 
        private List m_children; 
        private CellTreeOpType m_opType;
        private FragmentQuery m_leftFragmentQuery; 
        private FragmentQuery m_rightFragmentQuery;
        #endregion

        #region Properties 
        // effects: See CellTreeNode.OpType
        internal override CellTreeOpType OpType { get { return m_opType; } } 
 
        // fragment query superseeds SelectionDomain
        internal override FragmentQuery LeftFragmentQuery 
        {
            get
            {
                if (m_leftFragmentQuery == null) 
                {
                    Debug.Assert(Children.Count > 0); 
                    FragmentQuery leftFragmentQuery = Children[0].LeftFragmentQuery; 
                    FragmentQueryProcessor leftQP = CellNormalizer.LeftFragmentQP;
                    for (int i = 1; i < Children.Count; i++) 
                    {
                        FragmentQuery nextLeftQuery = Children[i].LeftFragmentQuery;
                        switch (OpType)
                        { 
                            case CellTreeOpType.IJ:
                                leftFragmentQuery = leftQP.Intersect(leftFragmentQuery, nextLeftQuery); 
                                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
                                leftFragmentQuery = leftQP.Difference(leftFragmentQuery, nextLeftQuery); 
                                break;
                            default: 
                                // All other operators (Union, FOJ) require union of the domains 
                                leftFragmentQuery = leftQP.Union(leftFragmentQuery, nextLeftQuery);
                                break; 
                        }
                    }
                    m_leftFragmentQuery = leftFragmentQuery;
                } 
                return m_leftFragmentQuery;
            } 
        } 

        internal override FragmentQuery RightFragmentQuery 
        {
            get
            {
                if (m_rightFragmentQuery == null) 
                {
                    Debug.Assert(Children.Count > 0); 
                    FragmentQuery rightFragmentQuery = Children[0].RightFragmentQuery; 
                    FragmentQueryProcessor rightQP = CellNormalizer.RightFragmentQP;
                    for (int i = 1; i < Children.Count; i++) 
                    {
                        FragmentQuery nextRightQuery = Children[i].RightFragmentQuery;
                        switch (OpType)
                        { 
                            case CellTreeOpType.IJ:
                                rightFragmentQuery = rightQP.Intersect(rightFragmentQuery, nextRightQuery); 
                                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
                                rightFragmentQuery = rightQP.Difference(rightFragmentQuery, nextRightQuery); 
                                break;
                            default: 
                                // All other operators (Union, FOJ) require union of the domains 
                                rightFragmentQuery = rightQP.Union(rightFragmentQuery, nextRightQuery);
                                break; 
                        }
                    }
                    m_rightFragmentQuery = rightFragmentQuery;
                } 
                return m_rightFragmentQuery;
            } 
        } 

        // effects: See CellTreeNode.RightDomainMap 
        internal override MemberDomainMap RightDomainMap {
            get {
                // Get the information from one of the children
                Debug.Assert(m_children[0].RightDomainMap != null, "EdmMember domain map missing"); 
                return m_children[0].RightDomainMap;
            } 
        } 

        // effects: See CellTreeNode.Attributes 
        internal override Set Attributes { get { return m_attrs; } }

        // effects: See CellTreeNode.Children
        internal override List Children { get { return m_children; } } 

        internal override int NumProjectedSlots { 
            get { 
                // All children have the same number of slots
                Debug.Assert(m_children.Count > 1, "No children for op node?"); 
                return m_children[0].NumProjectedSlots;
            }
        }
 
        internal override int NumBoolSlots {
            get { 
                Debug.Assert(m_children.Count > 1, "No children for op node?"); 
                return m_children[0].NumBoolSlots;
            } 
        }
        #endregion

        #region Methods 
        internal override TOutput Accept(SimpleCellTreeVisitor visitor, TInput param) {
            return visitor.VisitOpNode(this, param); 
        } 

        internal override TOutput Accept(CellTreeVisitor visitor, TInput param) { 
            switch (OpType) {
                case CellTreeOpType.IJ:
                    return visitor.VisitInnerJoin(this, param);
                case CellTreeOpType.LOJ: 
                    return visitor.VisitLeftOuterJoin(this, param);
                case CellTreeOpType.Union: 
                    return visitor.VisitUnion(this, param); 
                case CellTreeOpType.FOJ:
                    return visitor.VisitFullOuterJoin(this, param); 
                case CellTreeOpType.LASJ:
                    return visitor.VisitLeftAntiSemiJoin(this, param);
                default:
                    Debug.Fail("Unexpected optype: " + OpType); 
                    // To satsfy the compiler
                    return visitor.VisitInnerJoin(this, param); 
            } 
        }
 
        // effects: Add child to the end of the current children list
        // while ensuring the constants and attributes of the child are
        // propagated into this (i.e., unioned)
        internal void Add(CellTreeNode child) { 
            Insert(m_children.Count, child);
        } 
 
        // effects: Add child at the beginning of the current children list
        // while ensuring the constants and attributes of the child are 
        // propagated into this (i.e., unioned)
        internal void AddFirst(CellTreeNode child) {
            Insert(0, child);
        } 

        // effects: Inserts child at "index" while ensuring the constants 
        // and attributes of the child are propagated into this 
        private void Insert(int index, CellTreeNode child) {
            m_attrs.Unite(child.Attributes); 
            m_children.Insert(index, child);
            // reset fragmentQuery so it's recomputed when property FragmentQuery is accessed
            m_leftFragmentQuery = null;
            m_rightFragmentQuery = null; 
        }
 
        // effects: Given the required slots by the parent, 
        // generates a CqlBlock tree for the tree rooted below node
        internal override CqlBlock ToCqlBlock(bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, 
            ref List withStatements)
        {
            // Dispatch depending on whether we have a union node or join node
            CqlBlock result; 
            if (OpType == CellTreeOpType.Union) {
                result = UnionToCqlBlock(requiredSlots, identifiers, ref blockAliasNum, ref withStatements); 
            } else { 
                result = JoinToCqlBlock(requiredSlots, identifiers, ref blockAliasNum, ref withStatements);
            } 
            return result;
        }

        internal override bool IsProjectedSlot(int slot) { 
            // If any childtree projects it, return true
            foreach (CellTreeNode childNode in Children) { 
                if (childNode.IsProjectedSlot(slot)) { 
                    return true;
                } 
            }
            return false;
        }
        #endregion 

		#region Union CqlBLock Methods 
		// requires: node corresponds to a Union node 
		// effects: Given a union node and the slots required by the parent,
 		// generates a CqlBlock for the subtree rooted at node 
        private CqlBlock UnionToCqlBlock(bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List withStatements)
        {
			Debug.Assert(OpType == CellTreeOpType.Union);
 
 			List children = new List();
            List aliasedSlotsForAddedByChildren = new List(); 
 
            int totalSlots = requiredSlots.Length;
 			foreach (CellTreeNode child in Children) { 
				// Unlike Join, we pass the requiredSlots from the parent as the requirement
                // CqlBlock childBlock = child.ToCqlBlock(requiredSlots, identifiers, ref blockAliasNum);
                bool[] childProjectedSlots = child.GetProjectedSlots();
                AndWith(childProjectedSlots, requiredSlots); 
                CqlBlock childBlock = child.ToCqlBlock(childProjectedSlots, identifiers, ref blockAliasNum, ref withStatements);
                for (int aliasedSlotNumber = childProjectedSlots.Length; aliasedSlotNumber < childBlock.Slots.Count; aliasedSlotNumber++) 
                { 
                    SlotInfo slotInfo = childBlock.Slots[aliasedSlotNumber];
                    aliasedSlotsForAddedByChildren.Add(new AliasedSlot(childBlock, slotInfo.SlotValue, slotInfo.MemberPath, aliasedSlotNumber)); 
                }


                // if required, but not projected, add NULL 
                SlotInfo[] paddedSlotInfo = new SlotInfo[childBlock.Slots.Count];
                ReadOnlyCollection childSlotInfo = childBlock.Slots; 
                for (int slotNum = 0; slotNum < totalSlots; slotNum++) 
                {
                    if (requiredSlots[slotNum] && !childProjectedSlots[slotNum]) 
                    {
                        if (IsBoolSlot(slotNum))
                        {
                            paddedSlotInfo[slotNum] = new SlotInfo(true /* is required */, true /* is projected */, 
                                                            new BooleanProjectedSlot(BoolExpression.False, identifiers, SlotToBoolIndex(slotNum)), null /* member path*/);
                        } 
                        else 
                        {
                            // NULL as projected slot 
                            paddedSlotInfo[slotNum] = new SlotInfo(true /* is required */, true /* is projected */,
                                                             new ConstantSlot(CellConstant.Null), childSlotInfo[slotNum].MemberPath);
                        }
                    } 
                    else
                    { 
                        paddedSlotInfo[slotNum] = childSlotInfo[slotNum]; 
                    }
                } 
                //Add the slots that were added by children
                //for (int slotNum = totalSlots; slotNum < childBlock.Slots.Count; slotNum++)
                //{
                //    paddedSlotInfo[slotNum] = childSlotInfo[slotNum]; 
                //}
                childBlock.Slots = new ReadOnlyCollection(paddedSlotInfo); 
 				children.Add(childBlock); 
				Debug.Assert(totalSlots == child.NumBoolSlots + child.NumProjectedSlots,
					"Number of required slots is different from what each node in the tree has?"); 
			}

            //We need to add the slots added by each child unformly for others( as nulls)
            //since this is a union operation 
            if (aliasedSlotsForAddedByChildren.Count != 0)
            { 
                foreach (CqlBlock childBlock in children) 
                {
                    SlotInfo[] childSlots = new SlotInfo[totalSlots + aliasedSlotsForAddedByChildren.Count]; 
                    childBlock.Slots.CopyTo(childSlots,0);
                    int index = totalSlots;
                    foreach (AliasedSlot aliasedSlot in aliasedSlotsForAddedByChildren)
                    { 
                        if (aliasedSlot.Block.Equals(childBlock))
                        { 
                            childSlots[index] = new SlotInfo(true /* is required */, true /* is projected */, 
                                 aliasedSlot.InnerSlot, aliasedSlot.MemberPath);
                        } 
                        else
                        {
                            childSlots[index] = new SlotInfo(true /* is required */, true /* is projected */,
                                 new ConstantSlot(CellConstant.Null), aliasedSlot.MemberPath); 

                        } 
                        //move on to the next slot added by children. 
                        index++;
                    } 
                    childBlock.Slots = new ReadOnlyCollection(childSlots);
                }
            }
 
 			// Create the slotInfos and then Union CqlBlock
            SlotInfo[] slotInfos = new SlotInfo[totalSlots + aliasedSlotsForAddedByChildren.Count]; 
			// We pick the slot references from the first child, just as convention 
 			// In a union, values come from both sides
 			CqlBlock firstChild = children[0]; 

			for (int slotNum = 0; slotNum < totalSlots; slotNum++) {
 				ProjectedSlot slot = firstChild.ProjectedSlot(slotNum);
				MemberPath memberPath = GetMemberPath(slotNum); 
				// A required slot is somehow projected by a child in Union
				// -- so set isProjected to be the same as isRequired 
 				bool isRequired = requiredSlots[slotNum]; 
				SlotInfo slotInfo = new SlotInfo(isRequired, isRequired, slot, memberPath);
 				slotInfos[slotNum] = slotInfo; 
 			}

            for (int i = 0, slotNum = totalSlots; slotNum < totalSlots + aliasedSlotsForAddedByChildren.Count; slotNum++, i++)
            { 
                slotInfos[slotNum] = new SlotInfo(true, true, aliasedSlotsForAddedByChildren[i], aliasedSlotsForAddedByChildren[i].MemberPath);
            } 
 

			CqlBlock block = new UnionCqlBlock(slotInfos, children, identifiers, ++blockAliasNum); 
 			return block;
		}
        private static void AndWith(bool[] boolArray, bool[] another)
        { 
            Debug.Assert(boolArray.Length == another.Length);
            for (int i = 0; i < boolArray.Length; i++) 
            { 
                boolArray[i] &= another[i];
            } 
        }
        #endregion

        #region Join CqlBLock Methods 
        // requires: node corresponds to an IJ, LOJ, FOJ node
        // effects: Given a union node and the slots required by the parent, 
        // generates a CqlBlock for the subtree rooted at node 
        private CqlBlock JoinToCqlBlock(bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List withStatements)
        { 
			int totalSlots = requiredSlots.Length;

            Debug.Assert(OpType == CellTreeOpType.IJ ||
                         OpType == CellTreeOpType.LOJ || 
                         OpType == CellTreeOpType.FOJ, "Only these join operations handled");
 
            List children = new List(); 
            List aliasedSlotsForAddedByChildren = new List();
 
            // First get the children nodes (FROM part)
            foreach (CellTreeNode child in Children) {
                // Determine the slots that are projected by this child.
                // These are the required slots as well - unlike Union, we do 
                // not need the child to project any extra nulls
                bool[] childProjectedSlots = child.GetProjectedSlots(); 
                AndWith(childProjectedSlots, requiredSlots); 
                //List subAddedSlotsByChild = new List();
                CqlBlock childBlock = child.ToCqlBlock(childProjectedSlots, identifiers, ref blockAliasNum, ref withStatements); 
                //addedSlotsByChild.AddRange(subAddedSlotsByChild);
                children.Add(childBlock);
                //foreach (SlotInfo slotInfo in subAddedSlotsByChild)
                for(int aliasedSlotNumber = childProjectedSlots.Length; aliasedSlotNumber < childBlock.Slots.Count;aliasedSlotNumber++) 
                {
                    SlotInfo slotInfo = childBlock.Slots[aliasedSlotNumber]; 
                    aliasedSlotsForAddedByChildren.Add(new AliasedSlot(childBlock, slotInfo.SlotValue, slotInfo.MemberPath, aliasedSlotNumber)); 
                }
				Debug.Assert(totalSlots == child.NumBoolSlots + child.NumProjectedSlots, 
 					"Number of required slots is different from what each node in the tree has?");
            }

            // Now get the slots that are projected out by this node (SELECT part) 
            SlotInfo[] slotInfos = new SlotInfo[totalSlots + aliasedSlotsForAddedByChildren.Count];
            for (int slotNum = 0; slotNum < totalSlots; slotNum++) 
            { 
                // Note: this call could create a CaseStatementSlot (i.e., slotInfo.SlotValue is CaseStatementSlot)
                // which uses "from" booleans that need to be projected by children 
                SlotInfo slotInfo = GetJoinSlotInfo(OpType, requiredSlots[slotNum], children, slotNum, identifiers);
                slotInfos[slotNum] = slotInfo;
            }
 

            for (int i = 0, slotNum = totalSlots; slotNum < totalSlots + aliasedSlotsForAddedByChildren.Count; slotNum++, i++) 
            { 
                slotInfos[slotNum] = new SlotInfo(true, true, aliasedSlotsForAddedByChildren[i], aliasedSlotsForAddedByChildren[i].MemberPath);
            } 

            // Generate the ON conditions: For each child, generate an ON
            // clause with the 0th child on the key fields
            List onClauses = new List(); 
            for (int i = 1; i < children.Count; i++) {
                CqlBlock child = children[i]; 
                JoinCqlBlock.OnClause onClause = new JoinCqlBlock.OnClause(); 
                foreach (int keySlotNum in KeySlots) {
                    SlotInfo slotInfo = slotInfos[keySlotNum]; 
                    Debug.Assert(child.IsProjected(keySlotNum), "Key is not in child");
                    Debug.Assert(children[0].IsProjected(keySlotNum), "Key is not in 0th child");
                    AliasedSlot first = new AliasedSlot(children[0], slotInfo.SlotValue,
                                                        slotInfo.MemberPath, keySlotNum); 
                    AliasedSlot second = new AliasedSlot(child, slotInfo.SlotValue, slotInfo.MemberPath,
                                                         keySlotNum); 
                    onClause.Add(first, second); 
                }
                onClauses.Add(onClause); 
            }

            CqlBlock result = new JoinCqlBlock(OpType, slotInfos, children, onClauses, identifiers, ++blockAliasNum);
            return result; 
        }
 
        // 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 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 an aliased 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 CaseStatementSlot(caseForOuterJoins, null);
            } else if (childDefiningSlot >= 0) { 
                slot = new AliasedSlot(children[childDefiningSlot], 
                                       children[childDefiningSlot].ProjectedSlot(slotNum), memberPath, 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 ConstantSlot(CellConstantDomain.GetDefaultValueForMemberPath(memberPath, GetLeaves(), CellNormalizer.Config)); 
                } 
            }
 
            // 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;
        }

        // requires: children to be a list of nodes that are children of an 
        // Inner Join node. slotNum does not correspond to the key slot
        // effects: Determines the child number from which the slot should be 
        // picked up. 
        private static int GetInnerJoinChildForSlot(List children, int slotNum) {
            // Picks the child with the non-constant slot first. If none, picks a non-null constant slot. 
            // If not een that, picks any one
            int result = -1;
            for (int i = 0; i < children.Count; i++) {
                CqlBlock child = children[i]; 
                if (false == child.IsProjected(slotNum)) {
                    continue; 
                } 
                ProjectedSlot slot = child.ProjectedSlot(slotNum);
                ConstantSlot constantSlot = slot as ConstantSlot; 
                JoinTreeSlot joinSlot = slot as JoinTreeSlot;
                if (joinSlot != null) { // Pick the non-constant slot
                    result = i;
                } else if (constantSlot != null && constantSlot.CellConstant.IsNull()) { 
                    if (result == -1) { // In case, all are null
                        result = i; 
                    } 
                } else {
                    // Just pick anything 
                    result = i;
                }
            }
            return result; 
        }
 
        // requires: caseForOuterJoins corresponds the slot "slotNum" 
        // effects: Adds a WhenThen corresponding to child to caseForOuterJoins.
        private void AddCaseForOuterJoins(CaseStatement caseForOuterJoins, CqlBlock child, int slotNum, CqlIdentifiers identifiers) { 
            // Determine the cells that the slot comes from
            // and make an OR expression, e.g., WHEN _from0 or _from2 or ... THEN child[slotNum]

            ProjectedSlot childSlot = child.ProjectedSlot(slotNum); 
            ConstantSlot constantSlot = childSlot as ConstantSlot;
            if (constantSlot != null && constantSlot.CellConstant.IsNull()) { 
                // NULL being generated by a child - don't need to project 
                return;
            } 

            BoolExpression originBool = BoolExpression.False;
            for (int i = 0; i < NumBoolSlots; i++) {
                int boolSlotNum = BoolIndexToSlot(i); 
                if (child.IsProjected(boolSlotNum)) {
                    // OR it to the expression 
                    QualifiedCellIdBoolean boolExpr = new QualifiedCellIdBoolean(child, identifiers, i); 
                    originBool = BoolExpression.CreateOr(originBool, BoolExpression.CreateLiteral(boolExpr, RightDomainMap));
                } 
            }
            // Make an aliased slot corresponding to child[slotNum] for the THEN
            MemberPath outputMember = GetMemberPath(slotNum);
            AliasedSlot slot = new AliasedSlot(child, childSlot, outputMember, slotNum); 
            caseForOuterJoins.AddWhenThen(originBool, slot);
        } 
        #endregion 

        #region String methods 
        // effects: Given an optype, returns a SQL-acceptable string
        // corresponding to the op
        internal static string OpToCql(CellTreeOpType opType) {
            switch (opType) { 
                case CellTreeOpType.FOJ: return "FULL OUTER JOIN";
                case CellTreeOpType.IJ: return "INNER JOIN"; 
                //case CellTreeOpType.LASJ: return "LEFT ANTISEMIJOIN"; 
                case CellTreeOpType.LOJ: return "LEFT OUTER JOIN";
                case CellTreeOpType.Union: return "UNION ALL"; 
            }
            Debug.Fail("Unknown operator");
            return null;
        } 

        internal override void ToCompactString(StringBuilder stringBuilder) { 
            //            Debug.Assert(m_children.Count > 1, "Tree not flattened?"); 
            stringBuilder.Append("(");
            for (int i = 0; i < m_children.Count; i++) { 
                CellTreeNode child = m_children[i];
                child.ToCompactString(stringBuilder);
                if (i != m_children.Count - 1) {
                    StringUtil.FormatStringBuilder(stringBuilder, " {0} ", OpType); 
                }
            } 
            stringBuilder.Append(")"); 
        }
        #endregion 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System.Data.Common.Utils; 
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Mapping.ViewGeneration.CqlGeneration;
using System.Data.Mapping.ViewGeneration.QueryRewriting; 
using System.Text;
using System.Linq; 
using System.Diagnostics; 
using System.Data.Metadata.Edm;
 
namespace System.Data.Mapping.ViewGeneration.Structures {

    using AttributeSet = Set;
 
    // This class represents th intermediate nodes in the tree (non-leaf nodes)
    internal class OpCellTreeNode : CellTreeNode { 
 
        #region Constructors
        // effects: Creates a node with operation opType and no children 
        internal OpCellTreeNode(CellNormalizer normalizer, CellTreeOpType opType)
 			: base(normalizer) {
            m_opType = opType;
            m_attrs = new AttributeSet(MemberPath.EqualityComparer); 
            m_children = new List();
        } 
 
        internal OpCellTreeNode(CellNormalizer normalizer, CellTreeOpType opType, params CellTreeNode[] children)
            : this(normalizer, opType, (IEnumerable)children) { } 

        // effects: Given a sequence of children node and the opType, creates
        // an OpCellTreeNode and returns it
        internal OpCellTreeNode(CellNormalizer normalizer, CellTreeOpType opType, IEnumerable children) 
            : this(normalizer, opType) {
            // Add the children one by one so that we can get the attrs etc fixed 
            foreach (CellTreeNode child in children) { 
                Add(child);
            } 
        }

        #endregion
 
        #region Fields
        private Set m_attrs; // attributes from whole subtree below 
        private List m_children; 
        private CellTreeOpType m_opType;
        private FragmentQuery m_leftFragmentQuery; 
        private FragmentQuery m_rightFragmentQuery;
        #endregion

        #region Properties 
        // effects: See CellTreeNode.OpType
        internal override CellTreeOpType OpType { get { return m_opType; } } 
 
        // fragment query superseeds SelectionDomain
        internal override FragmentQuery LeftFragmentQuery 
        {
            get
            {
                if (m_leftFragmentQuery == null) 
                {
                    Debug.Assert(Children.Count > 0); 
                    FragmentQuery leftFragmentQuery = Children[0].LeftFragmentQuery; 
                    FragmentQueryProcessor leftQP = CellNormalizer.LeftFragmentQP;
                    for (int i = 1; i < Children.Count; i++) 
                    {
                        FragmentQuery nextLeftQuery = Children[i].LeftFragmentQuery;
                        switch (OpType)
                        { 
                            case CellTreeOpType.IJ:
                                leftFragmentQuery = leftQP.Intersect(leftFragmentQuery, nextLeftQuery); 
                                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
                                leftFragmentQuery = leftQP.Difference(leftFragmentQuery, nextLeftQuery); 
                                break;
                            default: 
                                // All other operators (Union, FOJ) require union of the domains 
                                leftFragmentQuery = leftQP.Union(leftFragmentQuery, nextLeftQuery);
                                break; 
                        }
                    }
                    m_leftFragmentQuery = leftFragmentQuery;
                } 
                return m_leftFragmentQuery;
            } 
        } 

        internal override FragmentQuery RightFragmentQuery 
        {
            get
            {
                if (m_rightFragmentQuery == null) 
                {
                    Debug.Assert(Children.Count > 0); 
                    FragmentQuery rightFragmentQuery = Children[0].RightFragmentQuery; 
                    FragmentQueryProcessor rightQP = CellNormalizer.RightFragmentQP;
                    for (int i = 1; i < Children.Count; i++) 
                    {
                        FragmentQuery nextRightQuery = Children[i].RightFragmentQuery;
                        switch (OpType)
                        { 
                            case CellTreeOpType.IJ:
                                rightFragmentQuery = rightQP.Intersect(rightFragmentQuery, nextRightQuery); 
                                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
                                rightFragmentQuery = rightQP.Difference(rightFragmentQuery, nextRightQuery); 
                                break;
                            default: 
                                // All other operators (Union, FOJ) require union of the domains 
                                rightFragmentQuery = rightQP.Union(rightFragmentQuery, nextRightQuery);
                                break; 
                        }
                    }
                    m_rightFragmentQuery = rightFragmentQuery;
                } 
                return m_rightFragmentQuery;
            } 
        } 

        // effects: See CellTreeNode.RightDomainMap 
        internal override MemberDomainMap RightDomainMap {
            get {
                // Get the information from one of the children
                Debug.Assert(m_children[0].RightDomainMap != null, "EdmMember domain map missing"); 
                return m_children[0].RightDomainMap;
            } 
        } 

        // effects: See CellTreeNode.Attributes 
        internal override Set Attributes { get { return m_attrs; } }

        // effects: See CellTreeNode.Children
        internal override List Children { get { return m_children; } } 

        internal override int NumProjectedSlots { 
            get { 
                // All children have the same number of slots
                Debug.Assert(m_children.Count > 1, "No children for op node?"); 
                return m_children[0].NumProjectedSlots;
            }
        }
 
        internal override int NumBoolSlots {
            get { 
                Debug.Assert(m_children.Count > 1, "No children for op node?"); 
                return m_children[0].NumBoolSlots;
            } 
        }
        #endregion

        #region Methods 
        internal override TOutput Accept(SimpleCellTreeVisitor visitor, TInput param) {
            return visitor.VisitOpNode(this, param); 
        } 

        internal override TOutput Accept(CellTreeVisitor visitor, TInput param) { 
            switch (OpType) {
                case CellTreeOpType.IJ:
                    return visitor.VisitInnerJoin(this, param);
                case CellTreeOpType.LOJ: 
                    return visitor.VisitLeftOuterJoin(this, param);
                case CellTreeOpType.Union: 
                    return visitor.VisitUnion(this, param); 
                case CellTreeOpType.FOJ:
                    return visitor.VisitFullOuterJoin(this, param); 
                case CellTreeOpType.LASJ:
                    return visitor.VisitLeftAntiSemiJoin(this, param);
                default:
                    Debug.Fail("Unexpected optype: " + OpType); 
                    // To satsfy the compiler
                    return visitor.VisitInnerJoin(this, param); 
            } 
        }
 
        // effects: Add child to the end of the current children list
        // while ensuring the constants and attributes of the child are
        // propagated into this (i.e., unioned)
        internal void Add(CellTreeNode child) { 
            Insert(m_children.Count, child);
        } 
 
        // effects: Add child at the beginning of the current children list
        // while ensuring the constants and attributes of the child are 
        // propagated into this (i.e., unioned)
        internal void AddFirst(CellTreeNode child) {
            Insert(0, child);
        } 

        // effects: Inserts child at "index" while ensuring the constants 
        // and attributes of the child are propagated into this 
        private void Insert(int index, CellTreeNode child) {
            m_attrs.Unite(child.Attributes); 
            m_children.Insert(index, child);
            // reset fragmentQuery so it's recomputed when property FragmentQuery is accessed
            m_leftFragmentQuery = null;
            m_rightFragmentQuery = null; 
        }
 
        // effects: Given the required slots by the parent, 
        // generates a CqlBlock tree for the tree rooted below node
        internal override CqlBlock ToCqlBlock(bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, 
            ref List withStatements)
        {
            // Dispatch depending on whether we have a union node or join node
            CqlBlock result; 
            if (OpType == CellTreeOpType.Union) {
                result = UnionToCqlBlock(requiredSlots, identifiers, ref blockAliasNum, ref withStatements); 
            } else { 
                result = JoinToCqlBlock(requiredSlots, identifiers, ref blockAliasNum, ref withStatements);
            } 
            return result;
        }

        internal override bool IsProjectedSlot(int slot) { 
            // If any childtree projects it, return true
            foreach (CellTreeNode childNode in Children) { 
                if (childNode.IsProjectedSlot(slot)) { 
                    return true;
                } 
            }
            return false;
        }
        #endregion 

		#region Union CqlBLock Methods 
		// requires: node corresponds to a Union node 
		// effects: Given a union node and the slots required by the parent,
 		// generates a CqlBlock for the subtree rooted at node 
        private CqlBlock UnionToCqlBlock(bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List withStatements)
        {
			Debug.Assert(OpType == CellTreeOpType.Union);
 
 			List children = new List();
            List aliasedSlotsForAddedByChildren = new List(); 
 
            int totalSlots = requiredSlots.Length;
 			foreach (CellTreeNode child in Children) { 
				// Unlike Join, we pass the requiredSlots from the parent as the requirement
                // CqlBlock childBlock = child.ToCqlBlock(requiredSlots, identifiers, ref blockAliasNum);
                bool[] childProjectedSlots = child.GetProjectedSlots();
                AndWith(childProjectedSlots, requiredSlots); 
                CqlBlock childBlock = child.ToCqlBlock(childProjectedSlots, identifiers, ref blockAliasNum, ref withStatements);
                for (int aliasedSlotNumber = childProjectedSlots.Length; aliasedSlotNumber < childBlock.Slots.Count; aliasedSlotNumber++) 
                { 
                    SlotInfo slotInfo = childBlock.Slots[aliasedSlotNumber];
                    aliasedSlotsForAddedByChildren.Add(new AliasedSlot(childBlock, slotInfo.SlotValue, slotInfo.MemberPath, aliasedSlotNumber)); 
                }


                // if required, but not projected, add NULL 
                SlotInfo[] paddedSlotInfo = new SlotInfo[childBlock.Slots.Count];
                ReadOnlyCollection childSlotInfo = childBlock.Slots; 
                for (int slotNum = 0; slotNum < totalSlots; slotNum++) 
                {
                    if (requiredSlots[slotNum] && !childProjectedSlots[slotNum]) 
                    {
                        if (IsBoolSlot(slotNum))
                        {
                            paddedSlotInfo[slotNum] = new SlotInfo(true /* is required */, true /* is projected */, 
                                                            new BooleanProjectedSlot(BoolExpression.False, identifiers, SlotToBoolIndex(slotNum)), null /* member path*/);
                        } 
                        else 
                        {
                            // NULL as projected slot 
                            paddedSlotInfo[slotNum] = new SlotInfo(true /* is required */, true /* is projected */,
                                                             new ConstantSlot(CellConstant.Null), childSlotInfo[slotNum].MemberPath);
                        }
                    } 
                    else
                    { 
                        paddedSlotInfo[slotNum] = childSlotInfo[slotNum]; 
                    }
                } 
                //Add the slots that were added by children
                //for (int slotNum = totalSlots; slotNum < childBlock.Slots.Count; slotNum++)
                //{
                //    paddedSlotInfo[slotNum] = childSlotInfo[slotNum]; 
                //}
                childBlock.Slots = new ReadOnlyCollection(paddedSlotInfo); 
 				children.Add(childBlock); 
				Debug.Assert(totalSlots == child.NumBoolSlots + child.NumProjectedSlots,
					"Number of required slots is different from what each node in the tree has?"); 
			}

            //We need to add the slots added by each child unformly for others( as nulls)
            //since this is a union operation 
            if (aliasedSlotsForAddedByChildren.Count != 0)
            { 
                foreach (CqlBlock childBlock in children) 
                {
                    SlotInfo[] childSlots = new SlotInfo[totalSlots + aliasedSlotsForAddedByChildren.Count]; 
                    childBlock.Slots.CopyTo(childSlots,0);
                    int index = totalSlots;
                    foreach (AliasedSlot aliasedSlot in aliasedSlotsForAddedByChildren)
                    { 
                        if (aliasedSlot.Block.Equals(childBlock))
                        { 
                            childSlots[index] = new SlotInfo(true /* is required */, true /* is projected */, 
                                 aliasedSlot.InnerSlot, aliasedSlot.MemberPath);
                        } 
                        else
                        {
                            childSlots[index] = new SlotInfo(true /* is required */, true /* is projected */,
                                 new ConstantSlot(CellConstant.Null), aliasedSlot.MemberPath); 

                        } 
                        //move on to the next slot added by children. 
                        index++;
                    } 
                    childBlock.Slots = new ReadOnlyCollection(childSlots);
                }
            }
 
 			// Create the slotInfos and then Union CqlBlock
            SlotInfo[] slotInfos = new SlotInfo[totalSlots + aliasedSlotsForAddedByChildren.Count]; 
			// We pick the slot references from the first child, just as convention 
 			// In a union, values come from both sides
 			CqlBlock firstChild = children[0]; 

			for (int slotNum = 0; slotNum < totalSlots; slotNum++) {
 				ProjectedSlot slot = firstChild.ProjectedSlot(slotNum);
				MemberPath memberPath = GetMemberPath(slotNum); 
				// A required slot is somehow projected by a child in Union
				// -- so set isProjected to be the same as isRequired 
 				bool isRequired = requiredSlots[slotNum]; 
				SlotInfo slotInfo = new SlotInfo(isRequired, isRequired, slot, memberPath);
 				slotInfos[slotNum] = slotInfo; 
 			}

            for (int i = 0, slotNum = totalSlots; slotNum < totalSlots + aliasedSlotsForAddedByChildren.Count; slotNum++, i++)
            { 
                slotInfos[slotNum] = new SlotInfo(true, true, aliasedSlotsForAddedByChildren[i], aliasedSlotsForAddedByChildren[i].MemberPath);
            } 
 

			CqlBlock block = new UnionCqlBlock(slotInfos, children, identifiers, ++blockAliasNum); 
 			return block;
		}
        private static void AndWith(bool[] boolArray, bool[] another)
        { 
            Debug.Assert(boolArray.Length == another.Length);
            for (int i = 0; i < boolArray.Length; i++) 
            { 
                boolArray[i] &= another[i];
            } 
        }
        #endregion

        #region Join CqlBLock Methods 
        // requires: node corresponds to an IJ, LOJ, FOJ node
        // effects: Given a union node and the slots required by the parent, 
        // generates a CqlBlock for the subtree rooted at node 
        private CqlBlock JoinToCqlBlock(bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List withStatements)
        { 
			int totalSlots = requiredSlots.Length;

            Debug.Assert(OpType == CellTreeOpType.IJ ||
                         OpType == CellTreeOpType.LOJ || 
                         OpType == CellTreeOpType.FOJ, "Only these join operations handled");
 
            List children = new List(); 
            List aliasedSlotsForAddedByChildren = new List();
 
            // First get the children nodes (FROM part)
            foreach (CellTreeNode child in Children) {
                // Determine the slots that are projected by this child.
                // These are the required slots as well - unlike Union, we do 
                // not need the child to project any extra nulls
                bool[] childProjectedSlots = child.GetProjectedSlots(); 
                AndWith(childProjectedSlots, requiredSlots); 
                //List subAddedSlotsByChild = new List();
                CqlBlock childBlock = child.ToCqlBlock(childProjectedSlots, identifiers, ref blockAliasNum, ref withStatements); 
                //addedSlotsByChild.AddRange(subAddedSlotsByChild);
                children.Add(childBlock);
                //foreach (SlotInfo slotInfo in subAddedSlotsByChild)
                for(int aliasedSlotNumber = childProjectedSlots.Length; aliasedSlotNumber < childBlock.Slots.Count;aliasedSlotNumber++) 
                {
                    SlotInfo slotInfo = childBlock.Slots[aliasedSlotNumber]; 
                    aliasedSlotsForAddedByChildren.Add(new AliasedSlot(childBlock, slotInfo.SlotValue, slotInfo.MemberPath, aliasedSlotNumber)); 
                }
				Debug.Assert(totalSlots == child.NumBoolSlots + child.NumProjectedSlots, 
 					"Number of required slots is different from what each node in the tree has?");
            }

            // Now get the slots that are projected out by this node (SELECT part) 
            SlotInfo[] slotInfos = new SlotInfo[totalSlots + aliasedSlotsForAddedByChildren.Count];
            for (int slotNum = 0; slotNum < totalSlots; slotNum++) 
            { 
                // Note: this call could create a CaseStatementSlot (i.e., slotInfo.SlotValue is CaseStatementSlot)
                // which uses "from" booleans that need to be projected by children 
                SlotInfo slotInfo = GetJoinSlotInfo(OpType, requiredSlots[slotNum], children, slotNum, identifiers);
                slotInfos[slotNum] = slotInfo;
            }
 

            for (int i = 0, slotNum = totalSlots; slotNum < totalSlots + aliasedSlotsForAddedByChildren.Count; slotNum++, i++) 
            { 
                slotInfos[slotNum] = new SlotInfo(true, true, aliasedSlotsForAddedByChildren[i], aliasedSlotsForAddedByChildren[i].MemberPath);
            } 

            // Generate the ON conditions: For each child, generate an ON
            // clause with the 0th child on the key fields
            List onClauses = new List(); 
            for (int i = 1; i < children.Count; i++) {
                CqlBlock child = children[i]; 
                JoinCqlBlock.OnClause onClause = new JoinCqlBlock.OnClause(); 
                foreach (int keySlotNum in KeySlots) {
                    SlotInfo slotInfo = slotInfos[keySlotNum]; 
                    Debug.Assert(child.IsProjected(keySlotNum), "Key is not in child");
                    Debug.Assert(children[0].IsProjected(keySlotNum), "Key is not in 0th child");
                    AliasedSlot first = new AliasedSlot(children[0], slotInfo.SlotValue,
                                                        slotInfo.MemberPath, keySlotNum); 
                    AliasedSlot second = new AliasedSlot(child, slotInfo.SlotValue, slotInfo.MemberPath,
                                                         keySlotNum); 
                    onClause.Add(first, second); 
                }
                onClauses.Add(onClause); 
            }

            CqlBlock result = new JoinCqlBlock(OpType, slotInfos, children, onClauses, identifiers, ++blockAliasNum);
            return result; 
        }
 
        // 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 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 an aliased 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 CaseStatementSlot(caseForOuterJoins, null);
            } else if (childDefiningSlot >= 0) { 
                slot = new AliasedSlot(children[childDefiningSlot], 
                                       children[childDefiningSlot].ProjectedSlot(slotNum), memberPath, 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 ConstantSlot(CellConstantDomain.GetDefaultValueForMemberPath(memberPath, GetLeaves(), CellNormalizer.Config)); 
                } 
            }
 
            // 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;
        }

        // requires: children to be a list of nodes that are children of an 
        // Inner Join node. slotNum does not correspond to the key slot
        // effects: Determines the child number from which the slot should be 
        // picked up. 
        private static int GetInnerJoinChildForSlot(List children, int slotNum) {
            // Picks the child with the non-constant slot first. If none, picks a non-null constant slot. 
            // If not een that, picks any one
            int result = -1;
            for (int i = 0; i < children.Count; i++) {
                CqlBlock child = children[i]; 
                if (false == child.IsProjected(slotNum)) {
                    continue; 
                } 
                ProjectedSlot slot = child.ProjectedSlot(slotNum);
                ConstantSlot constantSlot = slot as ConstantSlot; 
                JoinTreeSlot joinSlot = slot as JoinTreeSlot;
                if (joinSlot != null) { // Pick the non-constant slot
                    result = i;
                } else if (constantSlot != null && constantSlot.CellConstant.IsNull()) { 
                    if (result == -1) { // In case, all are null
                        result = i; 
                    } 
                } else {
                    // Just pick anything 
                    result = i;
                }
            }
            return result; 
        }
 
        // requires: caseForOuterJoins corresponds the slot "slotNum" 
        // effects: Adds a WhenThen corresponding to child to caseForOuterJoins.
        private void AddCaseForOuterJoins(CaseStatement caseForOuterJoins, CqlBlock child, int slotNum, CqlIdentifiers identifiers) { 
            // Determine the cells that the slot comes from
            // and make an OR expression, e.g., WHEN _from0 or _from2 or ... THEN child[slotNum]

            ProjectedSlot childSlot = child.ProjectedSlot(slotNum); 
            ConstantSlot constantSlot = childSlot as ConstantSlot;
            if (constantSlot != null && constantSlot.CellConstant.IsNull()) { 
                // NULL being generated by a child - don't need to project 
                return;
            } 

            BoolExpression originBool = BoolExpression.False;
            for (int i = 0; i < NumBoolSlots; i++) {
                int boolSlotNum = BoolIndexToSlot(i); 
                if (child.IsProjected(boolSlotNum)) {
                    // OR it to the expression 
                    QualifiedCellIdBoolean boolExpr = new QualifiedCellIdBoolean(child, identifiers, i); 
                    originBool = BoolExpression.CreateOr(originBool, BoolExpression.CreateLiteral(boolExpr, RightDomainMap));
                } 
            }
            // Make an aliased slot corresponding to child[slotNum] for the THEN
            MemberPath outputMember = GetMemberPath(slotNum);
            AliasedSlot slot = new AliasedSlot(child, childSlot, outputMember, slotNum); 
            caseForOuterJoins.AddWhenThen(originBool, slot);
        } 
        #endregion 

        #region String methods 
        // effects: Given an optype, returns a SQL-acceptable string
        // corresponding to the op
        internal static string OpToCql(CellTreeOpType opType) {
            switch (opType) { 
                case CellTreeOpType.FOJ: return "FULL OUTER JOIN";
                case CellTreeOpType.IJ: return "INNER JOIN"; 
                //case CellTreeOpType.LASJ: return "LEFT ANTISEMIJOIN"; 
                case CellTreeOpType.LOJ: return "LEFT OUTER JOIN";
                case CellTreeOpType.Union: return "UNION ALL"; 
            }
            Debug.Fail("Unknown operator");
            return null;
        } 

        internal override void ToCompactString(StringBuilder stringBuilder) { 
            //            Debug.Assert(m_children.Count > 1, "Tree not flattened?"); 
            stringBuilder.Append("(");
            for (int i = 0; i < m_children.Count; i++) { 
                CellTreeNode child = m_children[i];
                child.ToCompactString(stringBuilder);
                if (i != m_children.Count - 1) {
                    StringUtil.FormatStringBuilder(stringBuilder, " {0} ", OpType); 
                }
            } 
            stringBuilder.Append(")"); 
        }
        #endregion 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK