private void AddCaseForOuterJoins( CaseStatement caseForOuterJoins, CqlBlock child, int slotNum, CqlIdentifiers identifiers) { ConstantProjectedSlot constantProjectedSlot = child.SlotValue(slotNum) as ConstantProjectedSlot; if (constantProjectedSlot != null && constantProjectedSlot.CellConstant.IsNull()) { return; } BoolExpression or = BoolExpression.False; for (int index = 0; index < this.NumBoolSlots; ++index) { int slot = this.BoolIndexToSlot(index); if (child.IsProjected(slot)) { QualifiedCellIdBoolean qualifiedCellIdBoolean = new QualifiedCellIdBoolean(child, identifiers, index); or = BoolExpression.CreateOr(or, BoolExpression.CreateLiteral((BoolLiteral)qualifiedCellIdBoolean, this.RightDomainMap)); } } QualifiedSlot qualifiedSlot = child.QualifySlotWithBlockAlias(slotNum); caseForOuterJoins.AddWhenThen(or, (ProjectedSlot)qualifiedSlot); }
private static int GetInnerJoinChildForSlot(List <CqlBlock> children, int slotNum) { int num = -1; for (int index = 0; index < children.Count; ++index) { CqlBlock child = children[index]; if (child.IsProjected(slotNum)) { ProjectedSlot projectedSlot = child.SlotValue(slotNum); ConstantProjectedSlot constantProjectedSlot = projectedSlot as ConstantProjectedSlot; if (projectedSlot is MemberProjectedSlot) { num = index; } else if (constantProjectedSlot != null && constantProjectedSlot.CellConstant.IsNull()) { if (num == -1) { num = index; } } else { num = index; } } } return(num); }
protected override bool IsEqualTo(ProjectedSlot right) { ConstantProjectedSlot constantProjectedSlot = right as ConstantProjectedSlot; if (constantProjectedSlot == null) { return(false); } return(Constant.EqualityComparer.Equals(this.m_constant, constantProjectedSlot.m_constant)); }
internal override CqlBlock ToCqlBlock( bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List <WithRelationship> withRelationships) { int length = requiredSlots.Length; CellQuery rightCellQuery = this.LeftCellWrapper.RightCellQuery; SlotInfo[] slotInfoArray = new SlotInfo[length]; for (int index = 0; index < rightCellQuery.NumProjectedSlots; ++index) { ProjectedSlot slotValue = rightCellQuery.ProjectedSlotAt(index); if (requiredSlots[index] && slotValue == null) { ConstantProjectedSlot slot = new ConstantProjectedSlot(Domain.GetDefaultValueForMemberPath(this.ProjectedSlotMap[index], (IEnumerable <LeftCellWrapper>) this.GetLeaves(), this.ViewgenContext.Config)); rightCellQuery.FixMissingSlotAsDefaultConstant(index, slot); slotValue = (ProjectedSlot)slot; } SlotInfo slotInfo = new SlotInfo(requiredSlots[index], slotValue != null, slotValue, this.ProjectedSlotMap[index]); slotInfoArray[index] = slotInfo; } for (int index = 0; index < rightCellQuery.NumBoolVars; ++index) { BoolExpression boolVar = rightCellQuery.GetBoolVar(index); BooleanProjectedSlot booleanProjectedSlot = boolVar == null ? new BooleanProjectedSlot(BoolExpression.False, identifiers, index) : new BooleanProjectedSlot(boolVar, identifiers, index); int slot = this.BoolIndexToSlot(index); SlotInfo slotInfo = new SlotInfo(requiredSlots[slot], boolVar != null, (ProjectedSlot)booleanProjectedSlot, (MemberPath)null); slotInfoArray[slot] = slotInfo; } IEnumerable <SlotInfo> source = (IEnumerable <SlotInfo>)slotInfoArray; if (rightCellQuery.Extent.EntityContainer.DataSpace == DataSpace.SSpace && this.m_cellWrapper.LeftExtent.BuiltInTypeKind == BuiltInTypeKind.EntitySet) { IEnumerable <AssociationSetMapping> relationshipSetMappingsFor = this.ViewgenContext.EntityContainerMapping.GetRelationshipSetMappingsFor(this.m_cellWrapper.LeftExtent, rightCellQuery.Extent); List <SlotInfo> foreignKeySlots = new List <SlotInfo>(); foreach (AssociationSetMapping colocatedAssociationSetMap in relationshipSetMappingsFor) { WithRelationship withRelationship; if (LeafCellTreeNode.TryGetWithRelationship(colocatedAssociationSetMap, this.m_cellWrapper.LeftExtent, rightCellQuery.SourceExtentMemberPath, ref foreignKeySlots, out withRelationship)) { withRelationships.Add(withRelationship); source = ((IEnumerable <SlotInfo>)slotInfoArray).Concat <SlotInfo>((IEnumerable <SlotInfo>)foreignKeySlots); } } } return((CqlBlock) new ExtentCqlBlock(rightCellQuery.Extent, rightCellQuery.SelectDistinctFlag, source.ToArray <SlotInfo>(), rightCellQuery.WhereClause, identifiers, ++blockAliasNum)); }
private static bool TryGetInstantiatedType(ProjectedSlot slot, out EdmType type) { type = (EdmType)null; ConstantProjectedSlot constantProjectedSlot = slot as ConstantProjectedSlot; if (constantProjectedSlot != null) { TypeConstant cellConstant = constantProjectedSlot.CellConstant as TypeConstant; if (cellConstant != null) { type = cellConstant.EdmType; return(true); } } return(false); }
internal void Simplify() { if (this.m_simplified) { return; } List <CaseStatement.WhenThen> whenThenList = new List <CaseStatement.WhenThen>(); bool flag = false; foreach (CaseStatement.WhenThen clause in this.m_clauses) { ConstantProjectedSlot constantProjectedSlot = clause.Value as ConstantProjectedSlot; if (constantProjectedSlot != null && (constantProjectedSlot.CellConstant.IsNull() || constantProjectedSlot.CellConstant.IsUndefined())) { flag = true; } else { whenThenList.Add(clause); if (clause.Condition.IsTrue) { break; } } } if (flag && whenThenList.Count == 0) { this.m_elseValue = (ProjectedSlot) new ConstantProjectedSlot(Constant.Null); } if (whenThenList.Count > 0 && !flag) { int index = whenThenList.Count - 1; this.m_elseValue = whenThenList[index].Value; whenThenList.RemoveAt(index); } this.m_clauses = whenThenList; this.m_simplified = true; }
internal void FixMissingSlotAsDefaultConstant(int slotNumber, ConstantProjectedSlot slot) { Debug.Assert(m_projectedSlots[slotNumber] == null, "Another attempt to plug in a default value"); m_projectedSlots[slotNumber] = slot; }
internal override CqlBlock ToCqlBlock( bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List <WithRelationship> withRelationships) { // Get the projected slots and the boolean expressions var totalSlots = requiredSlots.Length; var cellQuery = LeftCellWrapper.RightCellQuery; var projectedSlots = new SlotInfo[totalSlots]; Debug.Assert( cellQuery.NumProjectedSlots + cellQuery.NumBoolVars == totalSlots, "Wrong number of projected slots in node"); Debug.Assert( cellQuery.NumProjectedSlots == ProjectedSlotMap.Count, "Different number of slots in cell query and what we have mappings for"); // Add the regular fields for (var i = 0; i < cellQuery.NumProjectedSlots; i++) { var slot = cellQuery.ProjectedSlotAt(i); // If the slot is not null, we will project it // For extents, we say that all requiredlots are the only the // ones that are CLR non-null. Recall that "real" nulls are // handled by having a CellConstant.Null in ConstantSlot if (requiredSlots[i] && slot == null) { var memberPath = ProjectedSlotMap[i]; var defaultValue = new ConstantProjectedSlot(Domain.GetDefaultValueForMemberPath(memberPath, GetLeaves(), ViewgenContext.Config)); cellQuery.FixMissingSlotAsDefaultConstant(i, defaultValue); slot = defaultValue; } var slotInfo = new SlotInfo( requiredSlots[i], slot != null, slot, ProjectedSlotMap[i]); projectedSlots[i] = slotInfo; } // Add the boolean fields for (var boolNum = 0; boolNum < cellQuery.NumBoolVars; boolNum++) { var expr = cellQuery.GetBoolVar(boolNum); BooleanProjectedSlot boolSlot; if (expr != null) { boolSlot = new BooleanProjectedSlot(expr, identifiers, boolNum); } else { boolSlot = new BooleanProjectedSlot(BoolExpression.False, identifiers, boolNum); } var slotIndex = BoolIndexToSlot(boolNum); var slotInfo = new SlotInfo( requiredSlots[slotIndex], expr != null, boolSlot, null); projectedSlots[slotIndex] = slotInfo; } // See if we are generating a query view and whether there are any colocated foreign keys for which // we have to add With statements. IEnumerable <SlotInfo> totalProjectedSlots = projectedSlots; if ((cellQuery.Extent.EntityContainer.DataSpace == DataSpace.SSpace) && (m_cellWrapper.LeftExtent.BuiltInTypeKind == BuiltInTypeKind.EntitySet)) { var associationSetMaps = ViewgenContext.EntityContainerMapping.GetRelationshipSetMappingsFor(m_cellWrapper.LeftExtent, cellQuery.Extent); var foreignKeySlots = new List <SlotInfo>(); foreach (var colocatedAssociationSetMap in associationSetMaps) { WithRelationship withRelationship; if (TryGetWithRelationship( colocatedAssociationSetMap, m_cellWrapper.LeftExtent, cellQuery.SourceExtentMemberPath, ref foreignKeySlots, out withRelationship)) { withRelationships.Add(withRelationship); totalProjectedSlots = projectedSlots.Concat(foreignKeySlots); } } } var result = new ExtentCqlBlock( cellQuery.Extent, cellQuery.SelectDistinctFlag, totalProjectedSlots.ToArray(), cellQuery.WhereClause, identifiers, ++blockAliasNum); return(result); }
// returns true when the case statement is completed private bool AddRewritingToCaseStatement( Tile<FragmentQuery> rewriting, CaseStatement caseStatement, MemberPath currentPath, Constant domainValue) { var whenCondition = BoolExpression.True; // check whether the rewriting is always true or always false // if it's always true, we don't need any other WHEN clauses in the case statement // if it's always false, we don't need to add this WHEN clause to the case statement // given: domainQuery is satisfied. Check (domainQuery -> rewriting) var isAlwaysTrue = _qp.IsContainedIn(CreateTile(_domainQuery), rewriting); var isAlwaysFalse = _qp.IsDisjointFrom(CreateTile(_domainQuery), rewriting); Debug.Assert(!(isAlwaysTrue && isAlwaysFalse)); if (isAlwaysFalse) { return false; // don't need an unsatisfiable WHEN clause } if (isAlwaysTrue) { Debug.Assert(caseStatement.Clauses.Count == 0); } ProjectedSlot projectedSlot; if (domainValue.HasNotNull()) { projectedSlot = new MemberProjectedSlot(currentPath); } else { projectedSlot = new ConstantProjectedSlot(domainValue); } if (!isAlwaysTrue) { whenCondition = TileToBoolExpr(rewriting); } else { whenCondition = BoolExpression.True; } caseStatement.AddWhenThen(whenCondition, projectedSlot); return isAlwaysTrue; }
// effects: Generates a SlotInfo object for a slot of a join node. It // uses the type of the join operation (opType), whether the slot is // required by the parent or not (isRequiredSlot), the children of // this node (children) and the number of the slotNum private SlotInfo GetJoinSlotInfo( CellTreeOpType opType, bool isRequiredSlot, List <CqlBlock> children, int slotNum, CqlIdentifiers identifiers) { if (false == isRequiredSlot) { // The slot will not be used. So we can set the projected slot to be null var unrequiredSlotInfo = new SlotInfo(false, false, null, GetMemberPath(slotNum)); return(unrequiredSlotInfo); } // For a required slot, determine the child who is contributing to this value var childDefiningSlot = -1; CaseStatement caseForOuterJoins = null; for (var childNum = 0; childNum < children.Count; childNum++) { var 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) { var 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; } } var memberPath = GetMemberPath(slotNum); ProjectedSlot slot = null; // Generate the slot value -- case statement slot, or a qualified slot or null or false. // If case statement slot has nothing, treat it as null/empty. if (caseForOuterJoins != null && (caseForOuterJoins.Clauses.Count > 0 || caseForOuterJoins.ElseValue != null)) { caseForOuterJoins.Simplify(); slot = new CaseStatementProjectedSlot(caseForOuterJoins, null); } else if (childDefiningSlot >= 0) { slot = children[childDefiningSlot].QualifySlotWithBlockAlias(slotNum); } else { // need to produce output slot, but don't have a value // output NULL for fields or False for bools if (IsBoolSlot(slotNum)) { slot = new BooleanProjectedSlot(BoolExpression.False, identifiers, SlotToBoolIndex(slotNum)); } else { slot = new ConstantProjectedSlot(Domain.GetDefaultValueForMemberPath(memberPath, GetLeaves(), ViewgenContext.Config)); } } // 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. var 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 var slotInfo = new SlotInfo(true, true, slot, memberPath, enforceNotNull); return(slotInfo); }
internal void FixMissingSlotAsDefaultConstant(int slotNumber, ConstantProjectedSlot slot) { this.m_projectedSlots[slotNumber] = (ProjectedSlot)slot; }