Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Map / ViewGeneration / CqlGenerator.cs / 1305376 / CqlGenerator.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Data.Common;
using System.Data.Common.Utils;
using System.Data.Mapping.ViewGeneration.Structures;
using System.Collections.Generic;
using System.Data.Mapping.ViewGeneration.CqlGeneration;
using System.Text;
using System.Diagnostics;
using System.Data.Metadata.Edm;
namespace System.Data.Mapping.ViewGeneration
{
// This class is responsible for generation of CQL after the cell merging
// process has been done
internal class CqlGenerator : InternalBase
{
#region Constructor
// effects: Given the generated "view", the case statements for the
// multiconstant fields (caseStatements), a map that maps different
// paths of the entityset (for which the view is being generated) to
// slot indexes in the view, creates an object that is capable of
// generating the Cql for "view"
internal CqlGenerator(CellTreeNode view, Dictionary caseStatements,
CqlIdentifiers identifiers, MemberProjectionIndex projectedSlotMap,
int numCellsInView, BoolExpression topLevelWhereClause)
{
m_view = view;
m_caseStatements = caseStatements;
m_projectedSlotMap = projectedSlotMap;
m_numBools = numCellsInView; // We have that many booleans
m_topLevelWhereClause = topLevelWhereClause;
m_identifiers = identifiers;
}
#endregion
#region Fields
// The generated view from the cells (e.g., after cell merging)
private CellTreeNode m_view;
// Case statements for the multiconstant fields
private Dictionary m_caseStatements;
// Mapping from Memberpaths to slot indexes
private MemberProjectionIndex m_projectedSlotMap;
// No. of booleans in the view, one per cell (from0, from1, etc
private int m_numBools; // CHANGE_[....]_IMPROVE: Get this from view and cache. Not as a param to constructor
// A counter used to generate aliases for blocks
private int m_currentBlockNum;
private BoolExpression m_topLevelWhereClause;
// The prefixes for _from and block aliases (T)
private CqlIdentifiers m_identifiers;
#endregion
#region Properties
private int TotalSlots
{
get { return m_projectedSlotMap.Count + m_numBools; }
}
#endregion
#region CqlBlock Generation Methods for all node types
// effects: Returns a CQL query that represents a query/update
// mapping view for the view information that was supplied in the constructor
internal string GenerateCql()
{
// Generate a CqlBlock tree and then convert that to Cql
CqlBlock blockTree = GenerateCqlBlockTree();
// Create the string builder with 1K so that we don't have to
// keep growing it
StringBuilder builder = new StringBuilder(1024);
blockTree.AsCql(builder, true, 1);
return builder.ToString();
}
// effects: Generates a CqlBlock tree that is capable of generating
// the actual Cql strings
private CqlBlock GenerateCqlBlockTree()
{
// Essentially, we create a block for each CellTreeNode in the
// tree and then we layer case statements on top of that view --
// one case statement for each multiconstant entry
// Dertmine the slots that are projected by the whole tree. Tell
// the children that they need to produce those slots somehow --
// if they don't have it, they can produce null
bool[] requiredSlots = GetRequiredSlots();
Debug.Assert(requiredSlots.Length == TotalSlots, "Wrong number of requiredSlots");
List withStatements = new List();
CqlBlock viewBlock = m_view.ToCqlBlock(requiredSlots, m_identifiers, ref m_currentBlockNum, ref withStatements);
// Handle case statements for multiconstant entries
// Right now, we have a simplication step that removes one of the
// entries and adds ELSE instead
foreach (CaseStatement statement in m_caseStatements.Values)
{
statement.Simplify();
}
// Generate the case statements and get the top level block which
// must correspond to the entity set
CqlBlock finalViewBlock = ConstructCaseBlocks(viewBlock, withStatements);
return finalViewBlock;
}
private bool[] GetRequiredSlots()
{
bool[] requiredSlots = new bool[TotalSlots];
// union all slots that are required in case statements
foreach (CaseStatement caseStatement in m_caseStatements.Values)
{
int slotNum = m_projectedSlotMap.IndexOf(caseStatement.MemberPath);
GetRequiredSlotsForCaseMember(slotNum, caseStatement.MemberPath, requiredSlots);
}
// For now, make sure that all booleans are required
// Reason: OUTER JOINs may introduce an extra CASE statement (in OpCellTreeNode.cs/GetJoinSlotInfo)
// if a member is projected in both inputs to the join.
// This case statement may use boolean variables that may not be marked as "required"
// The problem is that this decision is made _after_ CqlBlocks for children get produced (in OpCellTreeNode.cs/JoinToCqlBlock)
for (int i = TotalSlots - m_numBools; i < TotalSlots; i++)
{
requiredSlots[i] = true;
}
// Because of the above we don't need to harvest used booleans from the top-level WHERE clause
// m_topLevelWhereClause.GetRequiredSlots(m_projectedSlotMap, requiredSlots);
// slot value is required for case statement?
foreach (CaseStatement caseStatement in m_caseStatements.Values)
{
if (!caseStatement.MemberPath.IsScalarType()
|| (!caseStatement.MemberPath.IsPartOfKey && !caseStatement.DependsOnMemberValue)) //IsCalarType=true (only then can we evaluate IsPartofKey)
{
requiredSlots[m_projectedSlotMap.IndexOf(caseStatement.MemberPath)] = false;
}
}
return requiredSlots;
}
#endregion
#region CaseStatement Block Methods
// effects: Given a CqlBlock tree, generates the case statements
// blocks on top of it (using m_casestatements) and returns the
// resulting tree
private CqlBlock ConstructCaseBlocks(CqlBlock viewBlock, IEnumerable withStatements)
{
// Get the 0th slot only, i.e., the extent
bool[] 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);
CqlBlock result = ConstructCaseBlocks(viewBlock, 0, topSlots, withStatements);
return result;
}
// effects: Given a CqlBlock tree generated by the cell merging
// process (viewBlock) and the required slots by the parent,
// generates the casestatement block tree starting from startSlotNum,
// i.e., only for case statements that are beyond startSlotNum
private CqlBlock ConstructCaseBlocks(CqlBlock viewBlock, int startSlotNum,
bool[] parentRequiredSlots, IEnumerable withStatements)
{
int numMembers = m_projectedSlotMap.Count;
// Find the next slot for which we have a case statement, i.e.,
// which was in the multiconstants
int 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
MemberPath thisMember = m_projectedSlotMap[foundSlot];
bool[] thisRequiredSlots = new bool[TotalSlots];
GetRequiredSlotsForCaseMember(foundSlot, 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 (int 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;
}
}
// we just filled foundSlot - mark it as non-required if it produces constants only
CaseStatement thisCaseStatement = m_caseStatements[thisMember];
thisRequiredSlots[foundSlot] = thisCaseStatement.DependsOnMemberValue;
// Recursively, determine the block tree for slots beyond
// foundSlot.
CqlBlock childBlock = ConstructCaseBlocks(viewBlock, foundSlot + 1, thisRequiredSlots, null);
// For each slot, create a SlotInfo object
SlotInfo[] slotInfos = CreateSlotInfosForCaseStatement(parentRequiredSlots, foundSlot,
childBlock, thisCaseStatement, withStatements);
m_currentBlockNum++;
// We have a where clause only at the top level
BoolExpression 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 (int i = 1; i < slotInfos.Length; i++)
{
slotInfos[i].ResetIsRequiredByParent();
}
}
CaseCqlBlock result = new CaseCqlBlock(slotInfos, foundSlot, childBlock, whereClause, m_identifiers, m_currentBlockNum);
return result;
}
// effects: Given the slot (foundSlot) and its corresponding case
// statements (thisCaseStatement), generates the slotinfos for the
// case statement block. Uses parentRequiredSlots and childblock to
// determine if the slot is required and if it is projected by the child
private SlotInfo[] CreateSlotInfosForCaseStatement(bool[] parentRequiredSlots, int foundSlot,
CqlBlock childBlock, CaseStatement thisCaseStatement,
IEnumerable withStatements)
{
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.ProjectedSlot(slotNum);
MemberPath memberPath = GetMemberPath(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.MakeCaseWithAliasedSlots(childBlock, memberPath, slotNum);
slot = new CaseStatementProjectedSlot(newCaseStatement, withStatements);
isProjected = true; // We are projecting this slot now
}
else if (slot != null && isProjected && isRequiredByParent)
{
// We only alias something that is needed and is being
// projected by the child
// It is an aliased slot into the child block
slot = new AliasedSlot(childBlock, slot, memberPath, 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, memberPath);
slotInfos[slotNum] = slotInfo;
}
for (int i = TotalSlots; i < TotalSlots + numSlotsAddedByChildBlock; i++)
{
SlotInfo slotInfo = childBlock.Slots[i];
AliasedSlot childAddedSlot = new AliasedSlot(childBlock, slotInfo.SlotValue, slotInfo.MemberPath, i);
slotInfos[i] = new SlotInfo(true, true, childAddedSlot, childAddedSlot.MemberPath);
}
return slotInfos;
}
// effects: Returns the next slot starting at startSlotNum that is present in
// the case statements
private int FindNextCaseStatementSlot(int startSlotNum, bool[] parentRequiredSlots, int numMembers)
{
int foundSlot = -1;
// Simply go through the slots and check the m_caseStatements map
for (int slotNum = startSlotNum; slotNum < numMembers; slotNum++)
{
MemberPath member = m_projectedSlotMap[slotNum];
if (parentRequiredSlots[slotNum] && m_caseStatements.ContainsKey(member))
{
foundSlot = slotNum;
break;
}
}
return foundSlot;
}
// requires: member is part of m_caseStatements
// effects: Returns an array of size TotalSlots which indicates the
// slots that are needed to constuct "member", e.g., CPerson may need
// pid and name (say slots 2 and 5 -- then bools[2] and bools[5] will
// be true
private void GetRequiredSlotsForCaseMember(int memberSlotNum, MemberPath member, bool[] requiredSlots)
{
Debug.Assert(true == m_caseStatements.ContainsKey(member),
"Constructing case for regular field?");
Debug.Assert(requiredSlots.Length == TotalSlots, "Invalid array size for populating required slots");
CaseStatement statement = m_caseStatements[member];
// Find the required slots from the when then clause conditions
// and values
bool mustRequireThisSlot = 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
mustRequireThisSlot = true;
}
}
EdmType edmType = member.EdmType;
bool isTypeMember = Helper.IsEntityType(edmType) || Helper.IsComplexType(edmType);
//// Non-scalar field
if (isTypeMember)
{
foreach (EdmType instantiatedType in statement.InstantiatedTypes)
{
foreach (EdmMember childMember in Helper.GetAllStructuralMembers(instantiatedType) )
{
int slotNum = GetSlotIndex(member, childMember);
requiredSlots[slotNum] = true;
}
}
return;
}
if (member.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 (mustRequireThisSlot)
{
requiredSlots[memberSlotNum] = true;
}
return;
}
// For an association, get the indices of the ends, e.g.,
// CProduct and CCategory in CProductCategory1
if (Helper.IsAssociationType(edmType))
{
// Need just it's ends
AssociationSet associationSet = (AssociationSet)member.Extent;
AssociationType associationType = associationSet.ElementType;
foreach (AssociationEndMember endMember in associationType.AssociationEndMembers)
{
int slotNum = GetSlotIndex(member, endMember);
requiredSlots[slotNum] = true;
}
return;
}
// 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)member.Extent,
(AssociationEndMember)member.LeafEdmMember);
foreach (EdmMember entityMember in refElementType.KeyMembers)
{
int slotNum = GetSlotIndex(member, entityMember);
requiredSlots[slotNum] = true;
}
return;
}
#endregion
#region Helper methods
// effects: Given a slot number, slotNum, returns the output member path
// that this slot contributes/corresponds to in the extent view. If
// the slot corresponds to one of the boolean variables, returns null
private MemberPath GetMemberPath(int slotNum)
{
return ProjectedSlot.GetMemberPath(slotNum, m_projectedSlotMap, TotalSlots - m_projectedSlotMap.Count);
}
// requires: "member.child" be present in m_projectedSlotMap
// effects: Returns the index where member.child "e.g., CPerson1.pid" exists.
// Returns -1 if no such entry found
private int GetSlotIndex(MemberPath member, EdmMember child)
{
MemberPath fullMember = new MemberPath(member, child);
int index = m_projectedSlotMap.IndexOf(fullMember);
Debug.Assert(index != -1, "Couldn't locate " + fullMember.ToString() + " in m_projectedSlotMap");
return index;
}
#endregion
#region String methods
internal override void ToCompactString(StringBuilder builder)
{
builder.Append("View: ");
m_view.ToCompactString(builder);
builder.Append("ProjectedSlotMap: ");
m_projectedSlotMap.ToCompactString(builder);
builder.Append("Case statements: ");
foreach (MemberPath member in m_caseStatements.Keys)
{
CaseStatement statement = m_caseStatements[member];
statement.ToCompactString(builder);
builder.AppendLine();
}
}
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Data.Common;
using System.Data.Common.Utils;
using System.Data.Mapping.ViewGeneration.Structures;
using System.Collections.Generic;
using System.Data.Mapping.ViewGeneration.CqlGeneration;
using System.Text;
using System.Diagnostics;
using System.Data.Metadata.Edm;
namespace System.Data.Mapping.ViewGeneration
{
// This class is responsible for generation of CQL after the cell merging
// process has been done
internal class CqlGenerator : InternalBase
{
#region Constructor
// effects: Given the generated "view", the case statements for the
// multiconstant fields (caseStatements), a map that maps different
// paths of the entityset (for which the view is being generated) to
// slot indexes in the view, creates an object that is capable of
// generating the Cql for "view"
internal CqlGenerator(CellTreeNode view, Dictionary caseStatements,
CqlIdentifiers identifiers, MemberProjectionIndex projectedSlotMap,
int numCellsInView, BoolExpression topLevelWhereClause)
{
m_view = view;
m_caseStatements = caseStatements;
m_projectedSlotMap = projectedSlotMap;
m_numBools = numCellsInView; // We have that many booleans
m_topLevelWhereClause = topLevelWhereClause;
m_identifiers = identifiers;
}
#endregion
#region Fields
// The generated view from the cells (e.g., after cell merging)
private CellTreeNode m_view;
// Case statements for the multiconstant fields
private Dictionary m_caseStatements;
// Mapping from Memberpaths to slot indexes
private MemberProjectionIndex m_projectedSlotMap;
// No. of booleans in the view, one per cell (from0, from1, etc
private int m_numBools; // CHANGE_[....]_IMPROVE: Get this from view and cache. Not as a param to constructor
// A counter used to generate aliases for blocks
private int m_currentBlockNum;
private BoolExpression m_topLevelWhereClause;
// The prefixes for _from and block aliases (T)
private CqlIdentifiers m_identifiers;
#endregion
#region Properties
private int TotalSlots
{
get { return m_projectedSlotMap.Count + m_numBools; }
}
#endregion
#region CqlBlock Generation Methods for all node types
// effects: Returns a CQL query that represents a query/update
// mapping view for the view information that was supplied in the constructor
internal string GenerateCql()
{
// Generate a CqlBlock tree and then convert that to Cql
CqlBlock blockTree = GenerateCqlBlockTree();
// Create the string builder with 1K so that we don't have to
// keep growing it
StringBuilder builder = new StringBuilder(1024);
blockTree.AsCql(builder, true, 1);
return builder.ToString();
}
// effects: Generates a CqlBlock tree that is capable of generating
// the actual Cql strings
private CqlBlock GenerateCqlBlockTree()
{
// Essentially, we create a block for each CellTreeNode in the
// tree and then we layer case statements on top of that view --
// one case statement for each multiconstant entry
// Dertmine the slots that are projected by the whole tree. Tell
// the children that they need to produce those slots somehow --
// if they don't have it, they can produce null
bool[] requiredSlots = GetRequiredSlots();
Debug.Assert(requiredSlots.Length == TotalSlots, "Wrong number of requiredSlots");
List withStatements = new List();
CqlBlock viewBlock = m_view.ToCqlBlock(requiredSlots, m_identifiers, ref m_currentBlockNum, ref withStatements);
// Handle case statements for multiconstant entries
// Right now, we have a simplication step that removes one of the
// entries and adds ELSE instead
foreach (CaseStatement statement in m_caseStatements.Values)
{
statement.Simplify();
}
// Generate the case statements and get the top level block which
// must correspond to the entity set
CqlBlock finalViewBlock = ConstructCaseBlocks(viewBlock, withStatements);
return finalViewBlock;
}
private bool[] GetRequiredSlots()
{
bool[] requiredSlots = new bool[TotalSlots];
// union all slots that are required in case statements
foreach (CaseStatement caseStatement in m_caseStatements.Values)
{
int slotNum = m_projectedSlotMap.IndexOf(caseStatement.MemberPath);
GetRequiredSlotsForCaseMember(slotNum, caseStatement.MemberPath, requiredSlots);
}
// For now, make sure that all booleans are required
// Reason: OUTER JOINs may introduce an extra CASE statement (in OpCellTreeNode.cs/GetJoinSlotInfo)
// if a member is projected in both inputs to the join.
// This case statement may use boolean variables that may not be marked as "required"
// The problem is that this decision is made _after_ CqlBlocks for children get produced (in OpCellTreeNode.cs/JoinToCqlBlock)
for (int i = TotalSlots - m_numBools; i < TotalSlots; i++)
{
requiredSlots[i] = true;
}
// Because of the above we don't need to harvest used booleans from the top-level WHERE clause
// m_topLevelWhereClause.GetRequiredSlots(m_projectedSlotMap, requiredSlots);
// slot value is required for case statement?
foreach (CaseStatement caseStatement in m_caseStatements.Values)
{
if (!caseStatement.MemberPath.IsScalarType()
|| (!caseStatement.MemberPath.IsPartOfKey && !caseStatement.DependsOnMemberValue)) //IsCalarType=true (only then can we evaluate IsPartofKey)
{
requiredSlots[m_projectedSlotMap.IndexOf(caseStatement.MemberPath)] = false;
}
}
return requiredSlots;
}
#endregion
#region CaseStatement Block Methods
// effects: Given a CqlBlock tree, generates the case statements
// blocks on top of it (using m_casestatements) and returns the
// resulting tree
private CqlBlock ConstructCaseBlocks(CqlBlock viewBlock, IEnumerable withStatements)
{
// Get the 0th slot only, i.e., the extent
bool[] 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);
CqlBlock result = ConstructCaseBlocks(viewBlock, 0, topSlots, withStatements);
return result;
}
// effects: Given a CqlBlock tree generated by the cell merging
// process (viewBlock) and the required slots by the parent,
// generates the casestatement block tree starting from startSlotNum,
// i.e., only for case statements that are beyond startSlotNum
private CqlBlock ConstructCaseBlocks(CqlBlock viewBlock, int startSlotNum,
bool[] parentRequiredSlots, IEnumerable withStatements)
{
int numMembers = m_projectedSlotMap.Count;
// Find the next slot for which we have a case statement, i.e.,
// which was in the multiconstants
int 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
MemberPath thisMember = m_projectedSlotMap[foundSlot];
bool[] thisRequiredSlots = new bool[TotalSlots];
GetRequiredSlotsForCaseMember(foundSlot, 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 (int 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;
}
}
// we just filled foundSlot - mark it as non-required if it produces constants only
CaseStatement thisCaseStatement = m_caseStatements[thisMember];
thisRequiredSlots[foundSlot] = thisCaseStatement.DependsOnMemberValue;
// Recursively, determine the block tree for slots beyond
// foundSlot.
CqlBlock childBlock = ConstructCaseBlocks(viewBlock, foundSlot + 1, thisRequiredSlots, null);
// For each slot, create a SlotInfo object
SlotInfo[] slotInfos = CreateSlotInfosForCaseStatement(parentRequiredSlots, foundSlot,
childBlock, thisCaseStatement, withStatements);
m_currentBlockNum++;
// We have a where clause only at the top level
BoolExpression 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 (int i = 1; i < slotInfos.Length; i++)
{
slotInfos[i].ResetIsRequiredByParent();
}
}
CaseCqlBlock result = new CaseCqlBlock(slotInfos, foundSlot, childBlock, whereClause, m_identifiers, m_currentBlockNum);
return result;
}
// effects: Given the slot (foundSlot) and its corresponding case
// statements (thisCaseStatement), generates the slotinfos for the
// case statement block. Uses parentRequiredSlots and childblock to
// determine if the slot is required and if it is projected by the child
private SlotInfo[] CreateSlotInfosForCaseStatement(bool[] parentRequiredSlots, int foundSlot,
CqlBlock childBlock, CaseStatement thisCaseStatement,
IEnumerable withStatements)
{
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.ProjectedSlot(slotNum);
MemberPath memberPath = GetMemberPath(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.MakeCaseWithAliasedSlots(childBlock, memberPath, slotNum);
slot = new CaseStatementProjectedSlot(newCaseStatement, withStatements);
isProjected = true; // We are projecting this slot now
}
else if (slot != null && isProjected && isRequiredByParent)
{
// We only alias something that is needed and is being
// projected by the child
// It is an aliased slot into the child block
slot = new AliasedSlot(childBlock, slot, memberPath, 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, memberPath);
slotInfos[slotNum] = slotInfo;
}
for (int i = TotalSlots; i < TotalSlots + numSlotsAddedByChildBlock; i++)
{
SlotInfo slotInfo = childBlock.Slots[i];
AliasedSlot childAddedSlot = new AliasedSlot(childBlock, slotInfo.SlotValue, slotInfo.MemberPath, i);
slotInfos[i] = new SlotInfo(true, true, childAddedSlot, childAddedSlot.MemberPath);
}
return slotInfos;
}
// effects: Returns the next slot starting at startSlotNum that is present in
// the case statements
private int FindNextCaseStatementSlot(int startSlotNum, bool[] parentRequiredSlots, int numMembers)
{
int foundSlot = -1;
// Simply go through the slots and check the m_caseStatements map
for (int slotNum = startSlotNum; slotNum < numMembers; slotNum++)
{
MemberPath member = m_projectedSlotMap[slotNum];
if (parentRequiredSlots[slotNum] && m_caseStatements.ContainsKey(member))
{
foundSlot = slotNum;
break;
}
}
return foundSlot;
}
// requires: member is part of m_caseStatements
// effects: Returns an array of size TotalSlots which indicates the
// slots that are needed to constuct "member", e.g., CPerson may need
// pid and name (say slots 2 and 5 -- then bools[2] and bools[5] will
// be true
private void GetRequiredSlotsForCaseMember(int memberSlotNum, MemberPath member, bool[] requiredSlots)
{
Debug.Assert(true == m_caseStatements.ContainsKey(member),
"Constructing case for regular field?");
Debug.Assert(requiredSlots.Length == TotalSlots, "Invalid array size for populating required slots");
CaseStatement statement = m_caseStatements[member];
// Find the required slots from the when then clause conditions
// and values
bool mustRequireThisSlot = 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
mustRequireThisSlot = true;
}
}
EdmType edmType = member.EdmType;
bool isTypeMember = Helper.IsEntityType(edmType) || Helper.IsComplexType(edmType);
//// Non-scalar field
if (isTypeMember)
{
foreach (EdmType instantiatedType in statement.InstantiatedTypes)
{
foreach (EdmMember childMember in Helper.GetAllStructuralMembers(instantiatedType) )
{
int slotNum = GetSlotIndex(member, childMember);
requiredSlots[slotNum] = true;
}
}
return;
}
if (member.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 (mustRequireThisSlot)
{
requiredSlots[memberSlotNum] = true;
}
return;
}
// For an association, get the indices of the ends, e.g.,
// CProduct and CCategory in CProductCategory1
if (Helper.IsAssociationType(edmType))
{
// Need just it's ends
AssociationSet associationSet = (AssociationSet)member.Extent;
AssociationType associationType = associationSet.ElementType;
foreach (AssociationEndMember endMember in associationType.AssociationEndMembers)
{
int slotNum = GetSlotIndex(member, endMember);
requiredSlots[slotNum] = true;
}
return;
}
// 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)member.Extent,
(AssociationEndMember)member.LeafEdmMember);
foreach (EdmMember entityMember in refElementType.KeyMembers)
{
int slotNum = GetSlotIndex(member, entityMember);
requiredSlots[slotNum] = true;
}
return;
}
#endregion
#region Helper methods
// effects: Given a slot number, slotNum, returns the output member path
// that this slot contributes/corresponds to in the extent view. If
// the slot corresponds to one of the boolean variables, returns null
private MemberPath GetMemberPath(int slotNum)
{
return ProjectedSlot.GetMemberPath(slotNum, m_projectedSlotMap, TotalSlots - m_projectedSlotMap.Count);
}
// requires: "member.child" be present in m_projectedSlotMap
// effects: Returns the index where member.child "e.g., CPerson1.pid" exists.
// Returns -1 if no such entry found
private int GetSlotIndex(MemberPath member, EdmMember child)
{
MemberPath fullMember = new MemberPath(member, child);
int index = m_projectedSlotMap.IndexOf(fullMember);
Debug.Assert(index != -1, "Couldn't locate " + fullMember.ToString() + " in m_projectedSlotMap");
return index;
}
#endregion
#region String methods
internal override void ToCompactString(StringBuilder builder)
{
builder.Append("View: ");
m_view.ToCompactString(builder);
builder.Append("ProjectedSlotMap: ");
m_projectedSlotMap.ToCompactString(builder);
builder.Append("Case statements: ");
foreach (MemberPath member in m_caseStatements.Keys)
{
CaseStatement statement = m_caseStatements[member];
statement.ToCompactString(builder);
builder.AppendLine();
}
}
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- StylusTip.cs
- BrowserCapabilitiesFactoryBase.cs
- MaterialCollection.cs
- UrlMappingsSection.cs
- Subtree.cs
- PositiveTimeSpanValidator.cs
- FileCodeGroup.cs
- XmlSchemaParticle.cs
- followingsibling.cs
- XmlnsDictionary.cs
- InternalDispatchObject.cs
- ErrorStyle.cs
- HtmlForm.cs
- Socket.cs
- CodeSnippetTypeMember.cs
- DropDownButton.cs
- ElementInit.cs
- ReadOnlyObservableCollection.cs
- ProgressBarBrushConverter.cs
- ToolStripScrollButton.cs
- OutputCache.cs
- ListManagerBindingsCollection.cs
- OrderedDictionary.cs
- XmlBaseWriter.cs
- XmlNodeChangedEventArgs.cs
- AppendHelper.cs
- TemplatedWizardStep.cs
- Int16AnimationBase.cs
- SecurityException.cs
- LogicalExpr.cs
- Point4DConverter.cs
- DiscoveryClientRequestChannel.cs
- CodeSnippetTypeMember.cs
- FixedTextSelectionProcessor.cs
- BufferedStream2.cs
- StringPropertyBuilder.cs
- ModifierKeysValueSerializer.cs
- PopupEventArgs.cs
- SqlBulkCopyColumnMapping.cs
- BooleanExpr.cs
- Types.cs
- hebrewshape.cs
- DataGridViewAdvancedBorderStyle.cs
- Tuple.cs
- _FixedSizeReader.cs
- SelectorAutomationPeer.cs
- QilTernary.cs
- BrowserInteropHelper.cs
- ErrorTolerantObjectWriter.cs
- TypeConverter.cs
- QueryLifecycle.cs
- WebPartDescriptionCollection.cs
- DataGridComponentEditor.cs
- OperatingSystem.cs
- IdentityNotMappedException.cs
- SafeSecurityHelper.cs
- SchemaConstraints.cs
- XmlNotation.cs
- TransportReplyChannelAcceptor.cs
- ElementUtil.cs
- ReadOnlyHierarchicalDataSource.cs
- LinqDataSource.cs
- VirtualizedCellInfoCollection.cs
- WebSysDescriptionAttribute.cs
- ServiceChannelProxy.cs
- ComponentSerializationService.cs
- ProjectionQueryOptionExpression.cs
- DynamicMetaObjectBinder.cs
- TransactionManager.cs
- TraceHelpers.cs
- SubclassTypeValidator.cs
- AmbientLight.cs
- QueryContinueDragEvent.cs
- SignatureHelper.cs
- PageRanges.cs
- IDReferencePropertyAttribute.cs
- TransformValueSerializer.cs
- RandomNumberGenerator.cs
- KeyEvent.cs
- keycontainerpermission.cs
- AssemblyAttributesGoHere.cs
- CodeDelegateCreateExpression.cs
- OverrideMode.cs
- Stack.cs
- PersonalizableAttribute.cs
- PersonalizationEntry.cs
- CacheVirtualItemsEvent.cs
- HtmlAnchor.cs
- Number.cs
- CompilerState.cs
- CompositeFontParser.cs
- DataGridItemEventArgs.cs
- FilterException.cs
- TreeViewItem.cs
- ProfilePropertyNameValidator.cs
- WebPartUtil.cs
- DataControlCommands.cs
- DataGridViewCell.cs
- ToolStripArrowRenderEventArgs.cs
- EntitySqlQueryCacheKey.cs