Code:
/ 4.0 / 4.0 / untmp / 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, DictionarycaseStatements, 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
- Utils.cs
- documentsequencetextpointer.cs
- UserControlCodeDomTreeGenerator.cs
- NodeLabelEditEvent.cs
- QilPatternFactory.cs
- PropertyChangedEventManager.cs
- StreamWriter.cs
- DbConnectionStringCommon.cs
- WebHttpEndpoint.cs
- DuplexChannel.cs
- SQLInt64.cs
- SqlDataSourceQueryConverter.cs
- SqlTypesSchemaImporter.cs
- MultiTouchSystemGestureLogic.cs
- SystemThemeKey.cs
- IInstanceTable.cs
- UIElement3DAutomationPeer.cs
- NetTcpBindingElement.cs
- HttpResponseInternalWrapper.cs
- DescriptionAttribute.cs
- RTLAwareMessageBox.cs
- MetadataItemCollectionFactory.cs
- PhoneCall.cs
- RemotingConfigParser.cs
- SchemaComplexType.cs
- GregorianCalendarHelper.cs
- FontWeight.cs
- ReadOnlyDictionary.cs
- SecurityManager.cs
- ManagementObjectCollection.cs
- PerformanceCounterNameAttribute.cs
- GeometryModel3D.cs
- DataGridDefaultColumnWidthTypeConverter.cs
- SqlConnectionStringBuilder.cs
- MouseButtonEventArgs.cs
- DataBoundControlHelper.cs
- DebuggerService.cs
- securitycriticaldataClass.cs
- EditorZone.cs
- XmlSchemas.cs
- CaseInsensitiveOrdinalStringComparer.cs
- EntitySqlQueryBuilder.cs
- TextFindEngine.cs
- WindowsGraphics2.cs
- TargetException.cs
- SystemColors.cs
- FontDriver.cs
- UInt64.cs
- RemoteWebConfigurationHost.cs
- GeneratedView.cs
- EntityFunctions.cs
- WindowsRichEditRange.cs
- DrawingCollection.cs
- DataGridBeginningEditEventArgs.cs
- EntityViewGenerationConstants.cs
- SourceFileBuildProvider.cs
- InputMethodStateTypeInfo.cs
- WebPartZone.cs
- DataListItemCollection.cs
- FirstMatchCodeGroup.cs
- DataControlLinkButton.cs
- ValidationEventArgs.cs
- SurrogateEncoder.cs
- DefaultPropertyAttribute.cs
- ToolStripArrowRenderEventArgs.cs
- Button.cs
- SocketPermission.cs
- WMICapabilities.cs
- IProvider.cs
- SqlTriggerContext.cs
- ComPlusTypeLoader.cs
- HttpProfileBase.cs
- ProfileSettings.cs
- BatchServiceHost.cs
- IFormattable.cs
- CryptoSession.cs
- Variable.cs
- XD.cs
- SingleTagSectionHandler.cs
- StorageRoot.cs
- AttributeSetAction.cs
- SQLInt16Storage.cs
- XmlnsCache.cs
- FixedSOMElement.cs
- TwoPhaseCommit.cs
- Debug.cs
- BamlLocalizationDictionary.cs
- EventLogTraceListener.cs
- SafeNativeMemoryHandle.cs
- VSWCFServiceContractGenerator.cs
- RedistVersionInfo.cs
- TableItemProviderWrapper.cs
- FormViewPagerRow.cs
- ObjectListFieldsPage.cs
- RSAOAEPKeyExchangeFormatter.cs
- SerialErrors.cs
- SerializationObjectManager.cs
- DataMemberFieldConverter.cs
- XmlTextReaderImpl.cs
- ListViewDeletedEventArgs.cs