// <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); }
// 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 <WithRelationship> withRelationships) { int totalSlots = requiredSlots.Length; Debug.Assert(OpType == CellTreeOpType.IJ || OpType == CellTreeOpType.LOJ || OpType == CellTreeOpType.FOJ, "Only these join operations handled"); List <CqlBlock> children = new List <CqlBlock>(); List <Tuple <QualifiedSlot, MemberPath> > additionalChildSlots = new List <Tuple <QualifiedSlot, MemberPath> >(); // 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); CqlBlock childBlock = child.ToCqlBlock(childProjectedSlots, identifiers, ref blockAliasNum, ref withRelationships); children.Add(childBlock); for (int qualifiedSlotNumber = childProjectedSlots.Length; qualifiedSlotNumber < childBlock.Slots.Count; qualifiedSlotNumber++) { additionalChildSlots.Add(Tuple.Create(childBlock.QualifySlotWithBlockAlias(qualifiedSlotNumber), childBlock.MemberPath(qualifiedSlotNumber))); } 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 + additionalChildSlots.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 + additionalChildSlots.Count; slotNum++, i++) { slotInfos[slotNum] = new SlotInfo(true, true, additionalChildSlots[i].Item1, additionalChildSlots[i].Item2); } // Generate the ON conditions: For each child, generate an ON // clause with the 0th child on the key fields List <JoinCqlBlock.OnClause> onClauses = new List <JoinCqlBlock.OnClause>(); for (int i = 1; i < children.Count; i++) { CqlBlock child = children[i]; JoinCqlBlock.OnClause onClause = new JoinCqlBlock.OnClause(); foreach (int keySlotNum in this.KeySlots) { if (ViewgenContext.Config.IsValidationEnabled) { Debug.Assert(children[0].IsProjected(keySlotNum), "Key is not in 0th child"); Debug.Assert(child.IsProjected(keySlotNum), "Key is not in child"); } else { if (!child.IsProjected(keySlotNum) || !children[0].IsProjected(keySlotNum)) { ErrorLog errorLog = new ErrorLog(); errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.NoJoinKeyOrFKProvidedInMapping, Strings.Viewgen_NoJoinKeyOrFK, ViewgenContext.AllWrappersForExtent, String.Empty)); ExceptionHelpers.ThrowMappingException(errorLog, ViewgenContext.Config); } } var firstSlot = children[0].QualifySlotWithBlockAlias(keySlotNum); var secondSlot = child.QualifySlotWithBlockAlias(keySlotNum); var outputMember = slotInfos[keySlotNum].OutputMember; onClause.Add(firstSlot, outputMember, secondSlot, outputMember); } onClauses.Add(onClause); } CqlBlock result = new JoinCqlBlock(OpType, slotInfos, children, onClauses, identifiers, ++blockAliasNum); return(result); }
// 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 <WithRelationship> withRelationships) { Debug.Assert(OpType == CellTreeOpType.Union); List <CqlBlock> children = new List <CqlBlock>(); List <Tuple <CqlBlock, SlotInfo> > additionalChildSlots = new List <Tuple <CqlBlock, SlotInfo> >(); int totalSlots = requiredSlots.Length; foreach (CellTreeNode child in Children) { // Unlike Join, we pass the requiredSlots from the parent as the requirement. bool[] childProjectedSlots = child.GetProjectedSlots(); AndWith(childProjectedSlots, requiredSlots); CqlBlock childBlock = child.ToCqlBlock(childProjectedSlots, identifiers, ref blockAliasNum, ref withRelationships); for (int qualifiedSlotNumber = childProjectedSlots.Length; qualifiedSlotNumber < childBlock.Slots.Count; qualifiedSlotNumber++) { additionalChildSlots.Add(Tuple.Create(childBlock, childBlock.Slots[qualifiedSlotNumber])); } // if required, but not projected, add NULL SlotInfo[] paddedSlotInfo = new SlotInfo[childBlock.Slots.Count]; 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 MemberPath memberPath = childBlock.MemberPath(slotNum); paddedSlotInfo[slotNum] = new SlotInfo(true /* is required */, true /* is projected */, new ConstantProjectedSlot(Constant.Null, memberPath), memberPath); } } else { paddedSlotInfo[slotNum] = childBlock.Slots[slotNum]; } } childBlock.Slots = new ReadOnlyCollection <SlotInfo>(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 uniformly for others (as nulls) since this is a union operation. if (additionalChildSlots.Count != 0) { foreach (CqlBlock childBlock in children) { SlotInfo[] childSlots = new SlotInfo[totalSlots + additionalChildSlots.Count]; childBlock.Slots.CopyTo(childSlots, 0); int index = totalSlots; foreach (var addtionalChildSlotInfo in additionalChildSlots) { var slotInfo = addtionalChildSlotInfo.Item2; if (addtionalChildSlotInfo.Item1.Equals(childBlock)) { childSlots[index] = new SlotInfo(true /* is required */, true /* is projected */, slotInfo.SlotValue, slotInfo.OutputMember); } else { childSlots[index] = new SlotInfo(true /* is required */, true /* is projected */, new ConstantProjectedSlot(Constant.Null, slotInfo.OutputMember), slotInfo.OutputMember); } //move on to the next slot added by children. index++; } childBlock.Slots = new ReadOnlyCollection <SlotInfo>(childSlots); } } // Create the slotInfos and then Union CqlBlock SlotInfo[] slotInfos = new SlotInfo[totalSlots + additionalChildSlots.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++) { SlotInfo slotInfo = firstChild.Slots[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]; slotInfos[slotNum] = new SlotInfo(isRequired, isRequired, slotInfo.SlotValue, slotInfo.OutputMember); } for (int slotNum = totalSlots; slotNum < totalSlots + additionalChildSlots.Count; slotNum++) { var aslot = firstChild.Slots[slotNum]; slotInfos[slotNum] = new SlotInfo(true, true, aslot.SlotValue, aslot.OutputMember); } CqlBlock block = new UnionCqlBlock(slotInfos, children, identifiers, ++blockAliasNum); return(block); }
private SlotInfo[] CreateSlotInfosForCaseStatement( bool[] parentRequiredSlots, int foundSlot, CqlBlock childBlock, CaseStatement thisCaseStatement, IEnumerable <WithRelationship> withRelationships) { int num = childBlock.Slots.Count - this.TotalSlots; SlotInfo[] slotInfoArray = new SlotInfo[this.TotalSlots + num]; for (int slotNum = 0; slotNum < this.TotalSlots; ++slotNum) { bool isProjected = childBlock.IsProjected(slotNum); bool parentRequiredSlot = parentRequiredSlots[slotNum]; ProjectedSlot slotValue = childBlock.SlotValue(slotNum); MemberPath outputMemberPath = this.GetOutputMemberPath(slotNum); if (slotNum == foundSlot) { slotValue = (ProjectedSlot) new CaseStatementProjectedSlot(thisCaseStatement.DeepQualify(childBlock), withRelationships); isProjected = true; } else if (isProjected && parentRequiredSlot) { slotValue = (ProjectedSlot)childBlock.QualifySlotWithBlockAlias(slotNum); } SlotInfo slotInfo = new SlotInfo(parentRequiredSlot && isProjected, isProjected, slotValue, outputMemberPath); slotInfoArray[slotNum] = slotInfo; } for (int totalSlots = this.TotalSlots; totalSlots < this.TotalSlots + num; ++totalSlots) { QualifiedSlot qualifiedSlot = childBlock.QualifySlotWithBlockAlias(totalSlots); slotInfoArray[totalSlots] = new SlotInfo(true, true, (ProjectedSlot)qualifiedSlot, childBlock.MemberPath(totalSlots)); } return(slotInfoArray); }
private CqlBlock JoinToCqlBlock( bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List <WithRelationship> withRelationships) { int length1 = requiredSlots.Length; List <CqlBlock> children = new List <CqlBlock>(); List <Tuple <QualifiedSlot, MemberPath> > tupleList = new List <Tuple <QualifiedSlot, MemberPath> >(); foreach (CellTreeNode child in this.Children) { bool[] projectedSlots = child.GetProjectedSlots(); OpCellTreeNode.AndWith(projectedSlots, requiredSlots); CqlBlock cqlBlock = child.ToCqlBlock(projectedSlots, identifiers, ref blockAliasNum, ref withRelationships); children.Add(cqlBlock); for (int length2 = projectedSlots.Length; length2 < cqlBlock.Slots.Count; ++length2) { tupleList.Add(Tuple.Create <QualifiedSlot, MemberPath>(cqlBlock.QualifySlotWithBlockAlias(length2), cqlBlock.MemberPath(length2))); } } SlotInfo[] slotInfos = new SlotInfo[length1 + tupleList.Count]; for (int slotNum = 0; slotNum < length1; ++slotNum) { SlotInfo joinSlotInfo = this.GetJoinSlotInfo(this.OpType, requiredSlots[slotNum], children, slotNum, identifiers); slotInfos[slotNum] = joinSlotInfo; } int index1 = 0; int index2 = length1; while (index2 < length1 + tupleList.Count) { slotInfos[index2] = new SlotInfo(true, true, (ProjectedSlot)tupleList[index1].Item1, tupleList[index1].Item2); ++index2; ++index1; } List <JoinCqlBlock.OnClause> onClauses = new List <JoinCqlBlock.OnClause>(); for (int index3 = 1; index3 < children.Count; ++index3) { CqlBlock cqlBlock = children[index3]; JoinCqlBlock.OnClause onClause = new JoinCqlBlock.OnClause(); foreach (int keySlot in this.KeySlots) { if (!this.ViewgenContext.Config.IsValidationEnabled && (!cqlBlock.IsProjected(keySlot) || !children[0].IsProjected(keySlot))) { ErrorLog errorLog = new ErrorLog(); errorLog.AddEntry(new ErrorLog.Record(ViewGenErrorCode.NoJoinKeyOrFKProvidedInMapping, Strings.Viewgen_NoJoinKeyOrFK, (IEnumerable <LeftCellWrapper>) this.ViewgenContext.AllWrappersForExtent, string.Empty)); ExceptionHelpers.ThrowMappingException(errorLog, this.ViewgenContext.Config); } QualifiedSlot leftSlot = children[0].QualifySlotWithBlockAlias(keySlot); QualifiedSlot rightSlot = cqlBlock.QualifySlotWithBlockAlias(keySlot); MemberPath outputMember = slotInfos[keySlot].OutputMember; onClause.Add(leftSlot, outputMember, rightSlot, outputMember); } onClauses.Add(onClause); } return((CqlBlock) new JoinCqlBlock(this.OpType, slotInfos, children, onClauses, identifiers, ++blockAliasNum)); }
private CqlBlock UnionToCqlBlock( bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List <WithRelationship> withRelationships) { List <CqlBlock> children = new List <CqlBlock>(); List <Tuple <CqlBlock, SlotInfo> > tupleList = new List <Tuple <CqlBlock, SlotInfo> >(); int length1 = requiredSlots.Length; foreach (CellTreeNode child in this.Children) { bool[] projectedSlots = child.GetProjectedSlots(); OpCellTreeNode.AndWith(projectedSlots, requiredSlots); CqlBlock cqlBlock = child.ToCqlBlock(projectedSlots, identifiers, ref blockAliasNum, ref withRelationships); for (int length2 = projectedSlots.Length; length2 < cqlBlock.Slots.Count; ++length2) { tupleList.Add(Tuple.Create <CqlBlock, SlotInfo>(cqlBlock, cqlBlock.Slots[length2])); } SlotInfo[] slotInfoArray = new SlotInfo[cqlBlock.Slots.Count]; for (int slotNum = 0; slotNum < length1; ++slotNum) { if (requiredSlots[slotNum] && !projectedSlots[slotNum]) { if (this.IsBoolSlot(slotNum)) { slotInfoArray[slotNum] = new SlotInfo(true, true, (ProjectedSlot) new BooleanProjectedSlot(BoolExpression.False, identifiers, this.SlotToBoolIndex(slotNum)), (MemberPath)null); } else { MemberPath outputMember = cqlBlock.MemberPath(slotNum); slotInfoArray[slotNum] = new SlotInfo(true, true, (ProjectedSlot) new ConstantProjectedSlot(Constant.Null), outputMember); } } else { slotInfoArray[slotNum] = cqlBlock.Slots[slotNum]; } } cqlBlock.Slots = new ReadOnlyCollection <SlotInfo>((IList <SlotInfo>)slotInfoArray); children.Add(cqlBlock); } if (tupleList.Count != 0) { foreach (CqlBlock cqlBlock in children) { SlotInfo[] array = new SlotInfo[length1 + tupleList.Count]; cqlBlock.Slots.CopyTo(array, 0); int index = length1; foreach (Tuple <CqlBlock, SlotInfo> tuple in tupleList) { SlotInfo slotInfo = tuple.Item2; array[index] = !tuple.Item1.Equals((object)cqlBlock) ? new SlotInfo(true, true, (ProjectedSlot) new ConstantProjectedSlot(Constant.Null), slotInfo.OutputMember) : new SlotInfo(true, true, slotInfo.SlotValue, slotInfo.OutputMember); ++index; } cqlBlock.Slots = new ReadOnlyCollection <SlotInfo>((IList <SlotInfo>)array); } } SlotInfo[] slotInfos = new SlotInfo[length1 + tupleList.Count]; CqlBlock cqlBlock1 = children[0]; for (int index = 0; index < length1; ++index) { SlotInfo slot = cqlBlock1.Slots[index]; bool requiredSlot = requiredSlots[index]; slotInfos[index] = new SlotInfo(requiredSlot, requiredSlot, slot.SlotValue, slot.OutputMember); } for (int index = length1; index < length1 + tupleList.Count; ++index) { SlotInfo slot = cqlBlock1.Slots[index]; slotInfos[index] = new SlotInfo(true, true, slot.SlotValue, slot.OutputMember); } return((CqlBlock) new UnionCqlBlock(slotInfos, children, identifiers, ++blockAliasNum)); }