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); }
// <summary> // Adds an expression of the form "WHEN <paramref name="condition" /> THEN <paramref name="value" />". // This operation is not allowed after the <see cref="Simplify" /> call. // </summary> internal void AddWhenThen(BoolExpression condition, ProjectedSlot value) { Debug.Assert(!m_simplified, "Attempt to modify a simplified case statement"); DebugCheck.NotNull(value); condition.ExpensiveSimplify(); m_clauses.Add(new WhenThen(condition, value)); }
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)); }
private static DbExpression CaseSlotValueAsCqt( DbExpression row, ProjectedSlot slot, MemberPath outputMember, IEnumerable <WithRelationship> withRelationships) { DbExpression slotValueExpr = slot.AsCqt(row, outputMember); return(CaseStatement.WithRelationshipsClauseAsCqt(row, slotValueExpr, withRelationships, slot)); }
protected override bool IsEqualTo(ProjectedSlot right) { MemberProjectedSlot memberProjectedSlot = right as MemberProjectedSlot; if (memberProjectedSlot == null) { return(false); } return(MemberPath.EqualityComparer.Equals(this.m_memberPath, memberProjectedSlot.m_memberPath)); }
protected override bool IsEqualTo(ProjectedSlot right) { var rightSlot = right as MemberProjectedSlot; if (rightSlot == null) { return(false); } // We want equality of the paths return(MemberPath.EqualityComparer.Equals(m_memberPath, rightSlot.m_memberPath)); }
private static StringBuilder CaseSlotValueAsEsql( StringBuilder builder, ProjectedSlot slot, MemberPath outputMember, string blockAlias, IEnumerable <WithRelationship> withRelationships, int indentLevel) { // We should never have THEN as a BooleanProjectedSlot. Debug.Assert( slot is MemberProjectedSlot || slot is QualifiedSlot || slot is ConstantProjectedSlot, "Case statement THEN can only have constants or members."); slot.AsEsql(builder, outputMember, blockAlias, 1); WithRelationshipsClauseAsEsql(builder, withRelationships, blockAlias, indentLevel, slot); return(builder); }
private static StringBuilder CaseSlotValueAsEsql( StringBuilder builder, ProjectedSlot slot, MemberPath outputMember, string blockAlias, IEnumerable <WithRelationship> withRelationships, int indentLevel) { slot.AsEsql(builder, outputMember, blockAlias, 1); CaseStatement.WithRelationshipsClauseAsEsql(builder, withRelationships, blockAlias, indentLevel, slot); return(builder); }
private static DbExpression CaseSlotValueAsCqt( DbExpression row, ProjectedSlot slot, MemberPath outputMember, IEnumerable <WithRelationship> withRelationships) { // We should never have THEN as a BooleanProjectedSlot. Debug.Assert( slot is MemberProjectedSlot || slot is QualifiedSlot || slot is ConstantProjectedSlot, "Case statement THEN can only have constants or members."); var cqt = slot.AsCqt(row, outputMember); cqt = WithRelationshipsClauseAsCqt(row, cqt, withRelationships, slot); return(cqt); }
// <summary> // Simplifies the <see cref="CaseStatement" /> so that unnecessary WHEN/THENs for nulls/undefined values are eliminated. // Also, adds an ELSE clause if possible. // </summary> internal void Simplify() { if (m_simplified) { return; } var clauses = new List <WhenThen>(); // remove all WHEN clauses where the value gets set to "undefined" // We eliminate the last clause for now - we could determine the // "most complicated" WHEN clause and eliminate it var eliminatedNullClauses = false; foreach (var clause in m_clauses) { var constantSlot = clause.Value as ConstantProjectedSlot; // If null or undefined, remove it if (constantSlot != null && (constantSlot.CellConstant.IsNull() || constantSlot.CellConstant.IsUndefined())) { eliminatedNullClauses = true; } else { clauses.Add(clause); if (clause.Condition.IsTrue) { // none of subsequent case statements will be evaluated - ignore them break; } } } if (eliminatedNullClauses && clauses.Count == 0) { // There is nothing left -- we should add a null as the value m_elseValue = new ConstantProjectedSlot(Constant.Null); } // If we eliminated some undefined or null clauses, we do not want an else clause if (clauses.Count > 0 && false == eliminatedNullClauses) { // turn the last WHEN clause into an ELSE var lastIndex = clauses.Count - 1; m_elseValue = clauses[lastIndex].Value; clauses.RemoveAt(lastIndex); } m_clauses = clauses; m_simplified = true; }
private void GenerateCellRelations(int cellNumber) { List <ViewCellSlot> slots = new List <ViewCellSlot>(); for (int slotNum = 0; slotNum < this.CQuery.NumProjectedSlots; ++slotNum) { ProjectedSlot projectedSlot1 = this.CQuery.ProjectedSlotAt(slotNum); ProjectedSlot projectedSlot2 = this.SQuery.ProjectedSlotAt(slotNum); MemberProjectedSlot cSlot = (MemberProjectedSlot)projectedSlot1; MemberProjectedSlot sSlot = (MemberProjectedSlot)projectedSlot2; ViewCellSlot viewCellSlot = new ViewCellSlot(slotNum, cSlot, sSlot); slots.Add(viewCellSlot); } this.m_viewCellRelation = new ViewCellRelation(this, slots, cellNumber); }
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 = null; var constantSlot = slot as ConstantProjectedSlot; if (constantSlot != null) { var typeConstant = constantSlot.CellConstant as TypeConstant; if (typeConstant != null) { type = typeConstant.EdmType; return(true); } } return(false); }
private static DbExpression WithRelationshipsClauseAsCqt( DbExpression row, DbExpression slotValueExpr, IEnumerable <WithRelationship> withRelationships, ProjectedSlot slot) { List <DbRelatedEntityRef> relatedEntityRefs = new List <DbRelatedEntityRef>(); CaseStatement.WithRelationshipsClauseAsCql((Action <WithRelationship>)(withRelationship => relatedEntityRefs.Add(withRelationship.AsCqt(row))), withRelationships, slot); if (relatedEntityRefs.Count <= 0) { return(slotValueExpr); } DbNewInstanceExpression instanceExpression = slotValueExpr as DbNewInstanceExpression; return((DbExpression)DbExpressionBuilder.CreateNewEntityWithRelationshipsExpression((EntityType)instanceExpression.ResultType.EdmType, instanceExpression.Arguments, (IList <DbRelatedEntityRef>)relatedEntityRefs)); }
internal MemberProjectedSlot GetRightSideMappedSlotForLeftSideMember( MemberPath member) { int projectedPosition = this.LeftCellQuery.GetProjectedPosition(new MemberProjectedSlot(member)); if (projectedPosition == -1) { return((MemberProjectedSlot)null); } ProjectedSlot projectedSlot = this.RightCellQuery.ProjectedSlotAt(projectedPosition); if (projectedSlot == null || projectedSlot is ConstantProjectedSlot) { return((MemberProjectedSlot)null); } return(projectedSlot as MemberProjectedSlot); }
private static void WithRelationshipsClauseAsCql( Action <WithRelationship> emitWithRelationship, IEnumerable <WithRelationship> withRelationships, ProjectedSlot slot) { if (withRelationships == null || withRelationships.Count <WithRelationship>() <= 0) { return; } EdmType edmType = ((slot as ConstantProjectedSlot).CellConstant as TypeConstant).EdmType; foreach (WithRelationship withRelationship in withRelationships) { if (withRelationship.FromEndEntityType.IsAssignableFrom(edmType)) { emitWithRelationship(withRelationship); } } }
private static void WithRelationshipsClauseAsEsql( StringBuilder builder, IEnumerable <WithRelationship> withRelationships, string blockAlias, int indentLevel, ProjectedSlot slot) { bool first = true; CaseStatement.WithRelationshipsClauseAsCql((Action <WithRelationship>)(withRelationship => { if (first) { builder.Append(" WITH "); first = false; } withRelationship.AsEsql(builder, blockAlias, indentLevel); }), withRelationships, slot); }
// requires: projectedSlotMap which contains a mapping of the fields // for "this" to integers // effects: Align the fields of this cell query using the // projectedSlotMap and generates a new query into newMainQuery // Based on the re-aligned fields in this, re-aligns the // corresponding fields in otherQuery as well and modifies // newOtherQuery to contain it // Example: // input: Proj[A,B,"5"] = Proj[F,"7",G] // Proj[C,B] = Proj[H,I] // projectedSlotMap: A -> 0, B -> 1, C -> 2 // output: Proj[A,B,null] = Proj[F,"7",null] // Proj[null,B,C] = Proj[null,I,H] internal void CreateFieldAlignedCellQueries( CellQuery otherQuery, MemberProjectionIndex projectedSlotMap, out CellQuery newMainQuery, out CellQuery newOtherQuery) { // mainSlots and otherSlots hold the new slots for two queries var numAlignedSlots = projectedSlotMap.Count; var mainSlots = new ProjectedSlot[numAlignedSlots]; var otherSlots = new ProjectedSlot[numAlignedSlots]; // Go through the slots for this query and find the new slot for them for (var i = 0; i < m_projectedSlots.Length; i++) { var slot = m_projectedSlots[i] as MemberProjectedSlot; Debug.Assert(slot != null, "All slots during cell normalization must field slots"); // Get the the ith slot's variable and then get the // new slot number from the field map var newSlotNum = projectedSlotMap.IndexOf(slot.MemberPath); Debug.Assert(newSlotNum >= 0, "Field projected but not in projectedSlotMap"); mainSlots[newSlotNum] = m_projectedSlots[i]; otherSlots[newSlotNum] = otherQuery.m_projectedSlots[i]; // We ignore constants -- note that this is not the // isHighpriority or discriminator case. An example of this // is when (say) Address does not have zip but USAddress // does. Then the constraint looks like Pi_NULL, A, B(E) = // Pi_x, y, z(S) // We don't care about this null in the view generation of // the left side. Note that this could happen in inheritance // or in cases when say the S side has 20 fields but the C // side has only 3 - the other 17 are null or default. // NOTE: We allow such constants only on the C side and not // ont the S side. Otherwise, we can have a situation Pi_A, // B, C(E) = Pi_5, y, z(S) Then someone can set A to 7 and we // will not roundtrip. We check for this in validation } // Make the new cell queries with the new slots newMainQuery = new CellQuery(this, mainSlots); newOtherQuery = new CellQuery(otherQuery, otherSlots); }
internal void CreateFieldAlignedCellQueries( CellQuery otherQuery, MemberProjectionIndex projectedSlotMap, out CellQuery newMainQuery, out CellQuery newOtherQuery) { int count = projectedSlotMap.Count; ProjectedSlot[] newSlots1 = new ProjectedSlot[count]; ProjectedSlot[] newSlots2 = new ProjectedSlot[count]; for (int index1 = 0; index1 < this.m_projectedSlots.Length; ++index1) { MemberProjectedSlot projectedSlot = this.m_projectedSlots[index1] as MemberProjectedSlot; int index2 = projectedSlotMap.IndexOf(projectedSlot.MemberPath); newSlots1[index2] = this.m_projectedSlots[index1]; newSlots2[index2] = otherQuery.m_projectedSlots[index1]; } newMainQuery = new CellQuery(this, newSlots1); newOtherQuery = new CellQuery(otherQuery, newSlots2); }
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 AddWhenThen(BoolExpression condition, ProjectedSlot value) { condition.ExpensiveSimplify(); this.m_clauses.Add(new CaseStatement.WhenThen(condition, value)); }
// 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); }
// <summary> // Creates WHEN condition THEN value. // </summary> internal WhenThen(BoolExpression condition, ProjectedSlot value) { m_condition = condition; m_value = value; }
private static void WithRelationshipsClauseAsCql( Action <WithRelationship> emitWithRelationship, IEnumerable <WithRelationship> withRelationships, ProjectedSlot slot) { if (withRelationships != null && withRelationships.Count() > 0) { var constantSlot = slot as ConstantProjectedSlot; Debug.Assert(constantSlot != null, "WITH RELATIONSHIP clauses should be specified for type constant slots only."); var typeConstant = constantSlot.CellConstant as TypeConstant; Debug.Assert(typeConstant != null, "WITH RELATIONSHIP clauses should be there for type constants only."); var fromType = typeConstant.EdmType; foreach (var withRelationship in withRelationships) { // Add With statement for the types that participate in the association. if (withRelationship.FromEndEntityType.IsAssignableFrom(fromType)) { emitWithRelationship(withRelationship); } } } }
private static DbExpression WithRelationshipsClauseAsCqt( DbExpression row, DbExpression slotValueExpr, IEnumerable <WithRelationship> withRelationships, ProjectedSlot slot) { var relatedEntityRefs = new List <DbRelatedEntityRef>(); WithRelationshipsClauseAsCql( // emitWithRelationship action (withRelationship) => { relatedEntityRefs.Add(withRelationship.AsCqt(row)); }, withRelationships, slot); if (relatedEntityRefs.Count > 0) { var typeConstructor = slotValueExpr as DbNewInstanceExpression; Debug.Assert( typeConstructor != null && typeConstructor.ResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "WITH RELATIONSHIP clauses should be specified for entity type constructors only."); return(DbExpressionBuilder.CreateNewEntityWithRelationshipsExpression( (EntityType)typeConstructor.ResultType.EdmType, typeConstructor.Arguments, relatedEntityRefs)); } else { return(slotValueExpr); } }
private static void WithRelationshipsClauseAsEsql( StringBuilder builder, IEnumerable <WithRelationship> withRelationships, string blockAlias, int indentLevel, ProjectedSlot slot) { var first = true; WithRelationshipsClauseAsCql( // emitWithRelationship action (withRelationship) => { if (first) { builder.Append(" WITH "); first = false; } withRelationship.AsEsql(builder, blockAlias, indentLevel); }, withRelationships, slot); }