// <summary> // Creates a qualified slot "block_alias.slot_alias" // </summary> internal QualifiedSlot(CqlBlock block, ProjectedSlot slot) { DebugCheck.NotNull(block); DebugCheck.NotNull(slot); m_block = block; m_slot = slot; // Note: slot can be another qualified slot. }
internal CaseCqlBlock( SlotInfo[] slots, int caseSlot, CqlBlock child, BoolExpression whereClause, CqlIdentifiers identifiers, int blockAliasNum) : base(slots, new List <CqlBlock>((IEnumerable <CqlBlock>) new CqlBlock[1] { child }), whereClause, identifiers, blockAliasNum) { this.m_caseSlotInfo = slots[caseSlot]; }
/// <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; }
internal override DbExpression AsCqt(bool isTopLevel) { CqlBlock child1 = this.Children[0]; DbExpression dbExpression = child1.AsCqt(false); List <string> stringList = new List <string>(); for (int index = 1; index < this.Children.Count; ++index) { CqlBlock child2 = this.Children[index]; DbExpression right = child2.AsCqt(false); Func <DbExpression, DbExpression, DbExpression> joinCondition = new Func <DbExpression, DbExpression, DbExpression>(this.m_onClauses[index - 1].AsCqt); DbJoinExpression dbJoinExpression; switch (this.m_opType) { case CellTreeOpType.FOJ: dbJoinExpression = dbExpression.FullOuterJoin(right, joinCondition); break; case CellTreeOpType.LOJ: dbJoinExpression = dbExpression.LeftOuterJoin(right, joinCondition); break; case CellTreeOpType.IJ: dbJoinExpression = dbExpression.InnerJoin(right, joinCondition); break; default: return((DbExpression)null); } if (index == 1) { child1.SetJoinTreeContext((IList <string>)stringList, dbJoinExpression.Left.VariableName); } else { stringList.Add(dbJoinExpression.Left.VariableName); } child2.SetJoinTreeContext((IList <string>)stringList, dbJoinExpression.Right.VariableName); dbExpression = (DbExpression)dbJoinExpression; } return((DbExpression)dbExpression.Select <DbExpression>((Func <DbExpression, DbExpression>)(row => this.GenerateProjectionCqt(row, false)))); }
/// <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 var 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); var result = ConstructCaseBlocks(viewBlock, 0, topSlots, withRelationships); return result; }
// <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 var result = new QualifiedSlot(block, m_slot); return result; }
internal CaseCqlBlock( SlotInfo[] slots, int caseSlot, CqlBlock child, BoolExpression whereClause, CqlIdentifiers identifiers, int blockAliasNum) : base(slots, new List<CqlBlock>(new[] { child }), whereClause, identifiers, blockAliasNum) { m_caseSlotInfo = slots[caseSlot]; }
/// <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. }
internal QualifiedSlot(CqlBlock block, ProjectedSlot slot) { this.m_block = block; this.m_slot = slot; }
internal override ProjectedSlot DeepQualify(CqlBlock block) { return this; // Nothing to create }
// <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) { var newStatement = m_caseStatement.DeepQualify(block); return new CaseStatementProjectedSlot(newStatement, null); }
internal CaseCqlBlock( SlotInfo[] slots, int caseSlot, CqlBlock child, BoolExpression whereClause, CqlIdentifiers identifiers, int blockAliasNum) : base(slots, new List <CqlBlock>(new[] { child }), whereClause, identifiers, blockAliasNum) { m_caseSlotInfo = slots[caseSlot]; }
/// <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; }
internal override ProjectedSlot DeepQualify(CqlBlock block) { return((ProjectedSlot) new QualifiedSlot(block, this.m_slot)); }
/// <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) { var numMembers = m_projectedSlotMap.Count; // Find the next slot for which we have a case statement, i.e., // which was in the multiconstants var 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. var thisMember = m_projectedSlotMap[foundSlot]; var 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 (var 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. var thisCaseStatement = m_caseStatements[thisMember]; thisRequiredSlots[foundSlot] = thisCaseStatement.DependsOnMemberValue; // Recursively, determine the block tree for slots beyond foundSlot. var childBlock = ConstructCaseBlocks(viewBlock, foundSlot + 1, thisRequiredSlots, null); // For each slot, create a SlotInfo object var slotInfos = CreateSlotInfosForCaseStatement( parentRequiredSlots, foundSlot, childBlock, thisCaseStatement, withRelationships); m_currentBlockNum++; // We have a where clause only at the top level var 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 (var i = 1; i < slotInfos.Length; i++) { slotInfos[i].ResetIsRequiredByParent(); } } var result = new CaseCqlBlock(slotInfos, foundSlot, childBlock, whereClause, m_identifiers, m_currentBlockNum); return result; }
/// <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) { var numSlotsAddedByChildBlock = childBlock.Slots.Count - TotalSlots; var slotInfos = new SlotInfo[TotalSlots + numSlotsAddedByChildBlock]; for (var slotNum = 0; slotNum < TotalSlots; slotNum++) { var isProjected = childBlock.IsProjected(slotNum); var isRequiredByParent = parentRequiredSlots[slotNum]; var slot = childBlock.SlotValue(slotNum); var 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 var 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" var slotInfo = new SlotInfo(isRequiredByParent && isProjected, isProjected, slot, outputMember); slotInfos[slotNum] = slotInfo; } for (var i = TotalSlots; i < TotalSlots + numSlotsAddedByChildBlock; i++) { var childAddedSlot = childBlock.QualifySlotWithBlockAlias(i); slotInfos[i] = new SlotInfo(true, true, childAddedSlot, childBlock.MemberPath(i)); } return slotInfos; }
internal WhenThen ReplaceWithQualifiedSlot(CqlBlock block) { // Change the THEN part var newValue = m_value.DeepQualify(block); return new WhenThen(m_condition, newValue); }