Пример #1
0
 /// <summary>
 /// Recursively qualifies all <see cref="ProjectedSlot"/>s and returns a new deeply qualified <see cref="CaseStatement"/>.
 /// </summary>
 internal CaseStatement DeepQualify(CqlBlock block)
 {
     // Go through the whenthens and else and make a new case statement with qualified slots as needed.
     var result = new CaseStatement(m_memberPath);
     foreach (var whenThen in m_clauses)
     {
         var newClause = whenThen.ReplaceWithQualifiedSlot(block);
         result.m_clauses.Add(newClause);
     }
     if (m_elseValue != null)
     {
         result.m_elseValue = m_elseValue.DeepQualify(block);
     }
     result.m_simplified = m_simplified;
     return result;
 }
Пример #2
0
        internal override DbExpression AsCqt(bool isTopLevel)
        {
            Debug.Assert(m_caseSlotInfo.OutputMember != null, "We only construct real slots not boolean slots");

            // The FROM part: FROM (childBlock)
            Debug.Assert(Children.Count == 1, "CaseCqlBlock can have exactly one child.");
            CqlBlock     childBlock = this.Children[0];
            DbExpression cqt        = childBlock.AsCqt(false);

            // Get the WHERE part only when the expression is not simply TRUE.
            if (!BoolExpression.EqualityComparer.Equals(this.WhereClause, BoolExpression.True))
            {
                cqt = cqt.Where(row => this.WhereClause.AsCqt(row));
            }

            // The SELECT part.
            return(cqt.Select(row => GenerateProjectionCqt(row, isTopLevel)));
        }
 internal override ProjectedSlot DeepQualify(CqlBlock block)
 {
     return this; // Nothing to create
 }
Пример #4
0
 /// <summary>
 /// Creates new <see cref="ProjectedSlot"/> that is qualified with <paramref name="block"/>.CqlAlias.
 /// If current slot is composite (such as <see cref="CaseStatementProjectedSlot"/>, then this method recursively qualifies all parts
 /// and returns a new deeply qualified slot (as opposed to <see cref="CqlBlock.QualifySlotWithBlockAlias"/>).
 /// </summary>
 internal override ProjectedSlot DeepQualify(CqlBlock block)
 {
     // We take the slot inside this and change the block
     QualifiedSlot result = new QualifiedSlot(block, m_slot);
     return result;
 }
Пример #5
0
 /// <summary>
 /// Creates a qualified slot "block_alias.slot_alias"
 /// </summary>
 internal QualifiedSlot(CqlBlock block, ProjectedSlot slot)
 {
     Debug.Assert(block != null && slot != null, "Null input to QualifiedSlot constructor");
     m_block = block;
     m_slot = slot; // Note: slot can be another qualified slot.
 }
Пример #6
0
 /// <summary>
 /// Creates a qualified slot "block_alias.slot_alias"
 /// </summary>
 internal QualifiedSlot(CqlBlock block, ProjectedSlot slot)
 {
     Debug.Assert(block != null && slot != null, "Null input to QualifiedSlot constructor");
     m_block = block;
     m_slot  = slot; // Note: slot can be another qualified slot.
 }
Пример #7
0
        /// <summary>
        /// Given the slot (<paramref name="foundSlot"/>) and its corresponding case statement (<paramref name="thisCaseStatement"/>),
        /// generates the slotinfos for the cql block producing the case statement.
        /// </summary>
        private SlotInfo[] CreateSlotInfosForCaseStatement(bool[] parentRequiredSlots, 
                                                           int foundSlot,
                                                           CqlBlock childBlock, 
                                                           CaseStatement thisCaseStatement,
                                                           IEnumerable<WithRelationship> withRelationships)
        {
            int numSlotsAddedByChildBlock = childBlock.Slots.Count - TotalSlots;
            SlotInfo[] slotInfos = new SlotInfo[TotalSlots + numSlotsAddedByChildBlock];
            for (int slotNum = 0; slotNum < TotalSlots; slotNum++)
            {
                bool isProjected = childBlock.IsProjected(slotNum);
                bool isRequiredByParent = parentRequiredSlots[slotNum];
                ProjectedSlot slot = childBlock.SlotValue(slotNum);
                MemberPath outputMember = GetOutputMemberPath(slotNum);
                if (slotNum == foundSlot)
                {
                    // We need a case statement instead for this slot that we
                    // are handling right now
                    Debug.Assert(isRequiredByParent, "Case result not needed by parent");

                    // Get a case statement with all slots replaced by aliases slots
                    CaseStatement newCaseStatement = thisCaseStatement.DeepQualify(childBlock);
                    slot = new CaseStatementProjectedSlot(newCaseStatement, withRelationships);
                    isProjected = true; // We are projecting this slot now
                }
                else if (isProjected && isRequiredByParent)
                {
                    // We only alias something that is needed and is being projected by the child.
                    // It is a qualified slot into the child block.
                    slot = childBlock.QualifySlotWithBlockAlias(slotNum);
                }
                // For slots, if it is not required by the parent, we want to
                // set the isRequiredByParent for this slot to be
                // false. Furthermore, we do not want to introduce any "NULL
                // AS something" at this stage for slots not being
                // projected. So if the child does not project that slot, we
                // declare it as not being required by the parent (if such a
                // NULL was needed, it would have been pushed all the way
                // down to a non-case block.
                // Essentially, from a Case statement's parent perspective,
                // it is saying "If you can produce a slot either by yourself
                // or your children, please do. Otherwise, do not concoct anything"
                SlotInfo slotInfo = new SlotInfo(isRequiredByParent && isProjected, isProjected, slot, outputMember);
                slotInfos[slotNum] = slotInfo;
            }
            for (int i = TotalSlots; i < TotalSlots + numSlotsAddedByChildBlock; i++)
            {
                QualifiedSlot childAddedSlot = childBlock.QualifySlotWithBlockAlias(i);
                slotInfos[i] = new SlotInfo(true, true, childAddedSlot, childBlock.MemberPath(i));
            }
            return slotInfos;
        }
Пример #8
0
        /// <summary>
        /// Given the <paramref name="viewBlock"/> tree generated by the cell merging process and the <paramref name="parentRequiredSlots"/>,
        /// generates the block tree for the case statement at or past the startSlotNum, i.e., only for case statements that are beyond startSlotNum.
        /// </summary>
        private CqlBlock ConstructCaseBlocks(CqlBlock viewBlock, int startSlotNum, bool[] parentRequiredSlots, IEnumerable<WithRelationship> withRelationships)
        {
            int numMembers = m_projectedSlotMap.Count;
            // Find the next slot for which we have a case statement, i.e.,
            // which was in the multiconstants
            int foundSlot = FindNextCaseStatementSlot(startSlotNum, parentRequiredSlots, numMembers);

            if (foundSlot == -1)
            {
                // We have bottomed out - no more slots to generate cases for
                // Just get the base view block
                return viewBlock;
            }

            // Compute the requiredSlots for this member, i.e., what slots are needed to produce this member.
            MemberPath thisMember = m_projectedSlotMap[foundSlot];
            bool[] thisRequiredSlots = new bool[TotalSlots];
            GetRequiredSlotsForCaseMember(thisMember, thisRequiredSlots);
            Debug.Assert(thisRequiredSlots.Length == parentRequiredSlots.Length &&
                         thisRequiredSlots.Length == TotalSlots,
                         "Number of slots in array should not vary across blocks");

            // Merge parent's requirements with this requirements
            for (int i = 0; i < TotalSlots; i++)
            {
                // We do ask the children to generate the slot that we are
                // producing if it is available
                if (parentRequiredSlots[i])
                {
                    thisRequiredSlots[i] = true;
                }
            }

            // If current case statement depends on its slot value, then make sure the value is produced by the child block.
            CaseStatement thisCaseStatement = m_caseStatements[thisMember];
            thisRequiredSlots[foundSlot] = thisCaseStatement.DependsOnMemberValue;

            // Recursively, determine the block tree for slots beyond foundSlot.
            CqlBlock childBlock = ConstructCaseBlocks(viewBlock, foundSlot + 1, thisRequiredSlots, null);

            // For each slot, create a SlotInfo object
            SlotInfo[] slotInfos = CreateSlotInfosForCaseStatement(parentRequiredSlots, foundSlot, childBlock, thisCaseStatement, withRelationships);
            m_currentBlockNum++;

            // We have a where clause only at the top level
            BoolExpression whereClause = startSlotNum == 0 ? m_topLevelWhereClause : BoolExpression.True;
            if (startSlotNum == 0)
            {
                // only slot #0 is required by parent; reset all 'required by parent' booleans introduced above
                for (int i = 1; i < slotInfos.Length; i++)
                {
                    slotInfos[i].ResetIsRequiredByParent();
                }
            }

            CaseCqlBlock result = new CaseCqlBlock(slotInfos, foundSlot, childBlock, whereClause, m_identifiers, m_currentBlockNum);
            return result;
        }
Пример #9
0
        /// <summary>
        /// Given the <paramref name="viewBlock"/> tree, generates the case statement blocks on top of it (using <see cref="m_caseStatements"/>) and returns the resulting tree.
        /// One block per case statement is generated. Generated blocks are nested, with the <paramref name="viewBlock"/> is the innermost input.
        /// </summary>
        private CqlBlock ConstructCaseBlocks(CqlBlock viewBlock, IEnumerable<WithRelationship> withRelationships)
        {
            // Get the 0th slot only, i.e., the extent
            bool[] topSlots = new bool[TotalSlots];
            topSlots[0] = true;

            // all booleans in the top-level WHERE clause are required and get bubbled up
            // this makes some _fromX booleans be marked as 'required by parent'
            m_topLevelWhereClause.GetRequiredSlots(m_projectedSlotMap, topSlots);
            CqlBlock result = ConstructCaseBlocks(viewBlock, 0, topSlots, withRelationships);
            return result;
        }
 /// <summary>
 /// Creates a boolean of the form "<paramref name="block"/>.<paramref name="originalCellNum"/>".
 /// </summary>
 internal QualifiedCellIdBoolean(CqlBlock block, CqlIdentifiers identifiers, int originalCellNum)
     : base(identifiers, originalCellNum)
 {
     m_block = block;
 }
Пример #11
0
 /// <summary>
 /// Creates a <see cref="CqlBlock"/> containing the case statememt for the <paramref name="caseSlot"/> and projecting other slots as is from its child (input). CqlBlock with SELECT (slots),
 /// </summary>
 /// <param name="caseSlot">indicates which slot in <paramref name="slots"/> corresponds to the case statement being generated by this block</param>
 internal CaseCqlBlock(SlotInfo[] slots, int caseSlot, CqlBlock child, BoolExpression whereClause, CqlIdentifiers identifiers, int blockAliasNum)
     : base(slots, new List <CqlBlock>(new CqlBlock[] { child }), whereClause, identifiers, blockAliasNum)
 {
     m_caseSlotInfo = slots[caseSlot];
 }
Пример #12
0
 /// <summary>
 /// Creates a <see cref="CqlBlock"/> containing the case statememt for the <paramref name="caseSlot"/> and projecting other slots as is from its child (input). CqlBlock with SELECT (slots),
 /// </summary>
 /// <param name="caseSlot">indicates which slot in <paramref name="slots"/> corresponds to the case statement being generated by this block</param>
 internal CaseCqlBlock(SlotInfo[] slots, int caseSlot, CqlBlock child, BoolExpression whereClause, CqlIdentifiers identifiers, int blockAliasNum)
     : base(slots, new List<CqlBlock>(new CqlBlock[] { child }), whereClause, identifiers, blockAliasNum)
 {
     m_caseSlotInfo = slots[caseSlot];
 }
 /// <summary>
 /// Creates new <see cref="ProjectedSlot"/> that is qualified with <paramref name="block"/>.CqlAlias.
 /// If current slot is composite (such as <see cref="CaseStatementProjectedSlot"/>, then this method recursively qualifies all parts
 /// and returns a new deeply qualified slot (as opposed to <see cref="CqlBlock.QualifySlotWithBlockAlias"/>).
 /// </summary>
 internal override ProjectedSlot DeepQualify(CqlBlock block)
 {
     CaseStatement newStatement = m_caseStatement.DeepQualify(block);
     return new CaseStatementProjectedSlot(newStatement, null);
 }
Пример #14
0
 internal WhenThen ReplaceWithQualifiedSlot(CqlBlock block)
 {
     // Change the THEN part
     var newValue = m_value.DeepQualify(block);
     return new WhenThen(m_condition, newValue);
 }