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); }
// <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 SlotInfo( bool isRequiredByParent, bool isProjected, ProjectedSlot slotValue, MemberPath outputMember) : this(isRequiredByParent, isProjected, slotValue, outputMember, false) { }
// <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. }
protected override bool IsEqualTo(ProjectedSlot right) { ConstantProjectedSlot rightSlot = right as ConstantProjectedSlot; if (rightSlot == null) { return false; } return Constant.EqualityComparer.Equals(m_constant, rightSlot.m_constant); }
protected override bool IsEqualTo(ProjectedSlot right) { ViewCellSlot viewCellSlot = right as ViewCellSlot; if (viewCellSlot == null || this.m_slotNum != viewCellSlot.m_slotNum || !ProjectedSlot.EqualityComparer.Equals((ProjectedSlot)this.m_cSlot, (ProjectedSlot)viewCellSlot.m_cSlot)) { return(false); } return(ProjectedSlot.EqualityComparer.Equals((ProjectedSlot)this.m_sSlot, (ProjectedSlot)viewCellSlot.m_sSlot)); }
protected override bool IsEqualTo(ProjectedSlot right) { ViewCellSlot rightSlot = right as ViewCellSlot; if (rightSlot == null) { return false; } return m_slotNum == rightSlot.m_slotNum && MemberProjectedSlot.EqualityComparer.Equals(m_cSlot, rightSlot.m_cSlot) && MemberProjectedSlot.EqualityComparer.Equals(m_sSlot, rightSlot.m_sSlot); }
/// <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); }
protected override bool IsEqualTo(ProjectedSlot right) { ViewCellSlot rightSlot = right as ViewCellSlot; if (rightSlot == null) { return(false); } return(m_slotNum == rightSlot.m_slotNum && MemberProjectedSlot.EqualityComparer.Equals(m_cSlot, rightSlot.m_cSlot) && MemberProjectedSlot.EqualityComparer.Equals(m_sSlot, rightSlot.m_sSlot)); }
// effects: Given all the fields, just sets them. internal CellQuery( ProjectedSlot[] projectedSlots, BoolExpression whereClause, List<BoolExpression> boolExprs, SelectDistinct elimDupl, MemberPath rootMember) { m_boolExprs = boolExprs; m_projectedSlots = projectedSlots; m_whereClause = whereClause; m_originalWhereClause = whereClause; m_selectDistinct = elimDupl; m_extentMemberPath = rootMember; }
internal SlotInfo( bool isRequiredByParent, bool isProjected, ProjectedSlot slotValue, MemberPath outputMember, bool enforceNotNull) { this.m_isRequiredByParent = isRequiredByParent; this.m_isProjected = isProjected; this.m_slotValue = slotValue; this.m_outputMember = outputMember; this.m_enforceNotNull = enforceNotNull; }
/// <summary> /// Creates a <see cref="SlotInfo"/> for a <see cref="CqlBlock"/> X with information about whether this slot is needed by X's parent /// (<paramref name="isRequiredByParent"/>), whether X projects it (<paramref name="isProjected"/>) along with the slot value (<paramref name="slotValue"/>) and /// the output member path (<paramref name="outputMember"/> (for regular/non-boolean slots) for the slot. /// </summary> /// <param name="enforceNotNull">We need to ensure that _from variables are never null since view generation uses 2-valued boolean logic. /// If <paramref name="enforceNotNull"/>=true, the generated Cql adds a condition (AND <paramref name="slotValue"/> NOT NULL). /// This flag is used only for boolean slots.</param> internal SlotInfo(bool isRequiredByParent, bool isProjected, ProjectedSlot slotValue, MemberPath outputMember, bool enforceNotNull) { m_isRequiredByParent = isRequiredByParent; m_isProjected = isProjected; m_slotValue = slotValue; m_outputMember = outputMember; m_enforceNotNull = enforceNotNull; Debug.Assert(false == m_isRequiredByParent || m_slotValue != null, "Required slots cannot be null"); Debug.Assert(m_slotValue is QualifiedSlot || (m_slotValue == null && m_outputMember == null) || // unused boolean slot (m_slotValue is BooleanProjectedSlot) == (m_outputMember == null), "If slot is boolean slot, there is no member path for it and vice-versa"); }
/// <summary> /// Creates a <see cref="SlotInfo"/> for a <see cref="CqlBlock"/> X with information about whether this slot is needed by X's parent /// (<paramref name="isRequiredByParent"/>), whether X projects it (<paramref name="isProjected"/>) along with the slot value (<paramref name="slotValue"/>) and /// the output member path (<paramref name="outputMember"/> (for regular/non-boolean slots) for the slot. /// </summary> /// <param name="enforceNotNull">We need to ensure that _from variables are never null since view generation uses 2-valued boolean logic. /// If <paramref name="enforceNotNull"/>=true, the generated Cql adds a condition (AND <paramref name="slotValue"/> NOT NULL). /// This flag is used only for boolean slots.</param> internal SlotInfo(bool isRequiredByParent, bool isProjected, ProjectedSlot slotValue, MemberPath outputMember, bool enforceNotNull) { m_isRequiredByParent = isRequiredByParent; m_isProjected = isProjected; m_slotValue = slotValue; m_outputMember = outputMember; m_enforceNotNull = enforceNotNull; Debug.Assert(false == m_isRequiredByParent || m_slotValue != null, "Required slots cannot be null"); Debug.Assert(m_slotValue is QualifiedSlot || (m_slotValue == null && m_outputMember == null) || // unused boolean slot (m_slotValue is BooleanProjectedSlot) == (m_outputMember == null), "If slot is boolean slot, there is no member path for it and vice-versa"); }
/// <summary> /// Walks the chain of <see cref="QualifiedSlot"/>s starting from the current one and returns the original slot. /// </summary> internal ProjectedSlot GetOriginalSlot() { ProjectedSlot slot = m_slot; while (true) { QualifiedSlot qualifiedSlot = slot as QualifiedSlot; if (qualifiedSlot == null) { break; } slot = qualifiedSlot.m_slot; } return(slot); }
internal ProjectedSlot GetOriginalSlot() { ProjectedSlot slot = this.m_slot; while (true) { QualifiedSlot qualifiedSlot = slot as QualifiedSlot; if (qualifiedSlot != null) { slot = qualifiedSlot.m_slot; } else { break; } } return(slot); }
private bool AddRewritingToCaseStatement( Tile <FragmentQuery> rewriting, CaseStatement caseStatement, MemberPath currentPath, Constant domainValue) { BoolExpression boolExpression = BoolExpression.True; bool flag = this._qp.IsContainedIn((Tile <FragmentQuery>)QueryRewriter.CreateTile(this._domainQuery), rewriting); if (this._qp.IsDisjointFrom((Tile <FragmentQuery>)QueryRewriter.CreateTile(this._domainQuery), rewriting)) { return(false); } int num = flag ? 1 : 0; ProjectedSlot projectedSlot = !domainValue.HasNotNull() ? (ProjectedSlot) new ConstantProjectedSlot(domainValue) : (ProjectedSlot) new MemberProjectedSlot(currentPath); BoolExpression condition = flag ? BoolExpression.True : QueryRewriter.TileToBoolExpr(rewriting); caseStatement.AddWhenThen(condition, projectedSlot); return(flag); }
/// <summary> /// Returns an array of size <see cref="TotalSlots"/> which indicates the slots that are needed to constuct value at <paramref name="caseMemberPath"/>, /// e.g., CPerson may need pid and name (say slots 2 and 5 - then bools[2] and bools[5] will be true. /// </summary> /// <param name="caseMemberPath">must be part of <see cref="m_caseStatements"/></param> private void GetRequiredSlotsForCaseMember(MemberPath caseMemberPath, bool[] requiredSlots) { Debug.Assert(true == m_caseStatements.ContainsKey(caseMemberPath), "Constructing case for regular field?"); Debug.Assert(requiredSlots.Length == TotalSlots, "Invalid array size for populating required slots"); CaseStatement statement = m_caseStatements[caseMemberPath]; // Find the required slots from the when then clause conditions // and values bool requireThisSlot = false; foreach (CaseStatement.WhenThen clause in statement.Clauses) { clause.Condition.GetRequiredSlots(m_projectedSlotMap, requiredSlots); ProjectedSlot slot = clause.Value; if (!(slot is ConstantProjectedSlot)) { // If this slot is a scalar and a non-constant, // we need the lower down blocks to generate it for us requireThisSlot = true; } } EdmType edmType = caseMemberPath.EdmType; if (Helper.IsEntityType(edmType) || Helper.IsComplexType(edmType)) { foreach (EdmType instantiatedType in statement.InstantiatedTypes) { foreach (EdmMember childMember in Helper.GetAllStructuralMembers(instantiatedType)) { int slotNum = GetSlotIndex(caseMemberPath, childMember); requiredSlots[slotNum] = true; } } } else if (caseMemberPath.IsScalarType()) { // A scalar does not need anything per se to be constructed // unless it is referring to a field in the tree below, i.e., the THEN // slot is not a constant slot if (requireThisSlot) { int caseMemberSlotNum = m_projectedSlotMap.IndexOf(caseMemberPath); requiredSlots[caseMemberSlotNum] = true; } } else if (Helper.IsAssociationType(edmType)) { // For an association, get the indices of the ends, e.g., // CProduct and CCategory in CProductCategory1 // Need just it's ends AssociationSet associationSet = (AssociationSet)caseMemberPath.Extent; AssociationType associationType = associationSet.ElementType; foreach (AssociationEndMember endMember in associationType.AssociationEndMembers) { int slotNum = GetSlotIndex(caseMemberPath, endMember); requiredSlots[slotNum] = true; } } else { // For a reference, all we need are the keys RefType refType = edmType as RefType; Debug.Assert(refType != null, "What other non scalars do we have? Relation end must be a reference type"); EntityTypeBase refElementType = refType.ElementType; // Go through all the members of elementType and get the key properties EntitySet entitySet = MetadataHelper.GetEntitySetAtEnd((AssociationSet)caseMemberPath.Extent, (AssociationEndMember)caseMemberPath.LeafEdmMember); foreach (EdmMember entityMember in refElementType.KeyMembers) { int slotNum = GetSlotIndex(caseMemberPath, entityMember); requiredSlots[slotNum] = true; } } }
// <summary> // Creates a <see cref="SlotInfo" /> for a <see cref="CqlBlock" /> X with information about whether this slot is needed by X's parent // (<paramref name="isRequiredByParent" />), whether X projects it (<paramref name="isProjected" />) along with the slot value ( // <paramref // name="slotValue" /> // ) and // the output member path (<paramref name="outputMember" /> (for regular/non-boolean slots) for the slot. // </summary> internal SlotInfo(bool isRequiredByParent, bool isProjected, ProjectedSlot slotValue, MemberPath outputMember) : this(isRequiredByParent, isProjected, slotValue, outputMember, false /* enforceNotNull */) { }
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; }
// effects: Merges query2 with this according to the TM/SP rules for opType and // returns the merged result. canBooleansOverlap indicates whether the bools in this and query2 can overlap, i.e. // the same cells may have contributed to query2 and this earlier in the merge process internal static bool TryMergeTwoCellQueries( CellQuery query1, CellQuery query2, CellTreeOpType opType, out CellQuery mergedQuery) { mergedQuery = null; // Initialize g1 and g2 according to the TM/SP rules for IJ, LOJ, Union, FOJ cases BoolExpression g1 = null; BoolExpression g2 = null; switch (opType) { case CellTreeOpType.IJ: break; case CellTreeOpType.LOJ: case CellTreeOpType.LASJ: g2 = BoolExpression.True; break; case CellTreeOpType.FOJ: case CellTreeOpType.Union: g1 = BoolExpression.True; g2 = BoolExpression.True; break; default: Debug.Fail("Unsupported operator"); break; } var remap = new Dictionary <MemberPath, MemberPath>(MemberPath.EqualityComparer); //Continue merging only if both queries are over the same source MemberPath newRoot; if (!query1.Extent.Equals(query2.Extent)) { // could not merge return(false); } else { newRoot = query1.SourceExtentMemberPath; } // Conjuncts for ANDing with the previous whereClauses var conjunct1 = BoolExpression.True; var conjunct2 = BoolExpression.True; BoolExpression whereClause = null; switch (opType) { case CellTreeOpType.IJ: // Project[D1, D2, A, B, C] Select[cond1 and cond2] (T) // We simply merge the two lists of booleans -- no conjuct is added // conjunct1 and conjunct2 don't change // query1.WhereCaluse AND query2.WhereCaluse Debug.Assert(g1 == null && g2 == null, "IJ does not affect g1 and g2"); whereClause = BoolExpression.CreateAnd(query1.WhereClause, query2.WhereClause); break; case CellTreeOpType.LOJ: // conjunct1 does not change since D1 remains as is // Project[D1, (expr2 and cond2 and G2) as D2, A, B, C] Select[cond1] (T) // D1 does not change. New d2 is the list of booleans expressions // for query2 ANDed with g2 AND query2.WhereClause Debug.Assert(g1 == null, "LOJ does not affect g1"); conjunct2 = BoolExpression.CreateAnd(query2.WhereClause, g2); // Just query1's whereclause whereClause = query1.WhereClause; break; case CellTreeOpType.FOJ: case CellTreeOpType.Union: // Project[(expr1 and cond1 and G1) as D1, (expr2 and cond2 and G2) as D2, A, B, C] Select[cond1] (T) // New D1 is a list -- newD1 = D1 AND query1.WhereClause AND g1 // New D1 is a list -- newD2 = D2 AND query2.WhereClause AND g2 conjunct1 = BoolExpression.CreateAnd(query1.WhereClause, g1); conjunct2 = BoolExpression.CreateAnd(query2.WhereClause, g2); // The new whereClause -- g1 AND query1.WhereCaluse OR g2 AND query2.WhereClause whereClause = BoolExpression.CreateOr( BoolExpression.CreateAnd(query1.WhereClause, g1), BoolExpression.CreateAnd(query2.WhereClause, g2)); break; case CellTreeOpType.LASJ: // conjunct1 does not change since D1 remains as is // Project[D1, (expr2 and cond2 and G2) as D2, A, B, C] Select[cond1] (T) // D1 does not change. New d2 is the list of booleans expressions // for query2 ANDed with g2 AND NOT query2.WhereClause Debug.Assert(g1 == null, "LASJ does not affect g1"); conjunct2 = BoolExpression.CreateAnd(query2.WhereClause, g2); whereClause = BoolExpression.CreateAnd(query1.WhereClause, BoolExpression.CreateNot(conjunct2)); break; default: Debug.Fail("Unsupported operator"); break; } // Create the various remapped parts for the cell query -- // boolean expressions, merged slots, whereclause, duplicate // elimination, join tree var boolExprs = MergeBoolExpressions(query1, query2, conjunct1, conjunct2, opType); //BoolExpression.RemapBools(boolExprs, remap); ProjectedSlot[] mergedSlots; if (false == ProjectedSlot.TryMergeRemapSlots(query1.ProjectedSlots, query2.ProjectedSlots, out mergedSlots)) { // merging failed because two different right slots go to same left slot return(false); } whereClause = whereClause.RemapBool(remap); var elimDupl = MergeDupl(query1.SelectDistinctFlag, query2.SelectDistinctFlag); whereClause.ExpensiveSimplify(); mergedQuery = new CellQuery( mergedSlots, whereClause, boolExprs, elimDupl, newRoot); return(true); }
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); } } } }
/// <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; }
// 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 static bool TryMergeTwoCellQueries( CellQuery query1, CellQuery query2, CellTreeOpType opType, out CellQuery mergedQuery) { mergedQuery = (CellQuery)null; BoolExpression boolExpression1 = (BoolExpression)null; BoolExpression boolExpression2 = (BoolExpression)null; switch (opType) { case CellTreeOpType.Union: case CellTreeOpType.FOJ: boolExpression1 = BoolExpression.True; boolExpression2 = BoolExpression.True; break; case CellTreeOpType.LOJ: case CellTreeOpType.LASJ: boolExpression2 = BoolExpression.True; break; } Dictionary <MemberPath, MemberPath> remap = new Dictionary <MemberPath, MemberPath>(MemberPath.EqualityComparer); if (!query1.Extent.Equals((object)query2.Extent)) { return(false); } MemberPath extentMemberPath = query1.SourceExtentMemberPath; BoolExpression and1 = BoolExpression.True; BoolExpression and2 = BoolExpression.True; BoolExpression boolExpression3 = (BoolExpression)null; switch (opType) { case CellTreeOpType.Union: case CellTreeOpType.FOJ: and1 = BoolExpression.CreateAnd(query1.WhereClause, boolExpression1); and2 = BoolExpression.CreateAnd(query2.WhereClause, boolExpression2); boolExpression3 = BoolExpression.CreateOr(BoolExpression.CreateAnd(query1.WhereClause, boolExpression1), BoolExpression.CreateAnd(query2.WhereClause, boolExpression2)); break; case CellTreeOpType.LOJ: and2 = BoolExpression.CreateAnd(query2.WhereClause, boolExpression2); boolExpression3 = query1.WhereClause; break; case CellTreeOpType.IJ: boolExpression3 = BoolExpression.CreateAnd(query1.WhereClause, query2.WhereClause); break; case CellTreeOpType.LASJ: and2 = BoolExpression.CreateAnd(query2.WhereClause, boolExpression2); boolExpression3 = BoolExpression.CreateAnd(query1.WhereClause, BoolExpression.CreateNot(and2)); break; } List <BoolExpression> boolExprs = CellTreeSimplifier.MergeBoolExpressions(query1, query2, and1, and2, opType); ProjectedSlot[] result; if (!ProjectedSlot.TryMergeRemapSlots(query1.ProjectedSlots, query2.ProjectedSlots, out result)) { return(false); } BoolExpression whereClause = boolExpression3.RemapBool(remap); CellQuery.SelectDistinct elimDupl = CellTreeSimplifier.MergeDupl(query1.SelectDistinctFlag, query2.SelectDistinctFlag); whereClause.ExpensiveSimplify(); mergedQuery = new CellQuery(result, whereClause, boolExprs, elimDupl, extentMemberPath); return(true); }
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; }
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); }
/// <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. }
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; } }
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); }
/// <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. }
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; }
internal QualifiedSlot(CqlBlock block, ProjectedSlot slot) { this.m_block = block; this.m_slot = slot; }
// effects: Given an existing cellquery, makes a new one based on it // but uses the slots as specified with newSlots private CellQuery(CellQuery existing, ProjectedSlot[] newSlots) : this(newSlots, existing.m_whereClause, existing.m_boolExprs, existing.m_selectDistinct, existing.m_extentMemberPath) { }
/// <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)); }
/// <summary> /// Creates WHEN condition THEN value. /// </summary> internal WhenThen(BoolExpression condition, ProjectedSlot value) { m_condition = condition; m_value = value; }