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
- HttpInputStream.cs
- GridItemProviderWrapper.cs
- AmbiguousMatchException.cs
- Predicate.cs
- ProxyGenerationError.cs
- SqlDataSourceEnumerator.cs
- CharacterShapingProperties.cs
- Int64KeyFrameCollection.cs
- UncommonField.cs
- ProxyDataContractResolver.cs
- NavigatingCancelEventArgs.cs
- DataGridViewRowCollection.cs
- EntityCommandCompilationException.cs
- BreadCrumbTextConverter.cs
- NumericUpDownAccelerationCollection.cs
- SQlBooleanStorage.cs
- GeneralTransform3DTo2DTo3D.cs
- ClassValidator.cs
- MatrixCamera.cs
- CaseExpr.cs
- TypeDependencyAttribute.cs
- ListViewTableCell.cs
- ProcessInputEventArgs.cs
- SupportingTokenChannel.cs
- GroupBox.cs
- MaskedTextBoxDesigner.cs
- BitmapScalingModeValidation.cs
- ClientRuntimeConfig.cs
- RijndaelManaged.cs
- Path.cs
- ReadOnlyDictionary.cs
- HTTPNotFoundHandler.cs
- SHA384.cs
- OptimizerPatterns.cs
- GridView.cs
- CrossSiteScriptingValidation.cs
- DataBinding.cs
- FixedFindEngine.cs
- Range.cs
- XmlHierarchyData.cs
- ProvidersHelper.cs
- ThreadStaticAttribute.cs
- CompositeFontFamily.cs
- ScriptControlDescriptor.cs
- TypeCacheManager.cs
- ItemCollection.cs
- ObsoleteAttribute.cs
- SHA384Managed.cs
- DataGridPagerStyle.cs
- KnownBoxes.cs
- PathStreamGeometryContext.cs
- SocketElement.cs
- MethodCallConverter.cs
- Convert.cs
- EntityCollection.cs
- remotingproxy.cs
- SecurityRuntime.cs
- TextServicesContext.cs
- DesignerTransaction.cs
- XmlName.cs
- ImmutableAssemblyCacheEntry.cs
- OpenFileDialog.cs
- TypeUtil.cs
- XmlSerializationReader.cs
- DataSourceProvider.cs
- SafeArrayTypeMismatchException.cs
- HMACSHA256.cs
- FaultFormatter.cs
- TextServicesContext.cs
- SchemaCollectionPreprocessor.cs
- CqlParser.cs
- XmlCharCheckingReader.cs
- CompiledIdentityConstraint.cs
- TimerExtension.cs
- DrawingImage.cs
- Publisher.cs
- ChildTable.cs
- NullRuntimeConfig.cs
- ComPlusTraceRecord.cs
- TagNameToTypeMapper.cs
- TypedAsyncResult.cs
- SessionPageStateSection.cs
- DrawingImage.cs
- SpeechUI.cs
- TransactedReceiveData.cs
- DispatcherSynchronizationContext.cs
- NavigationPropertyEmitter.cs
- HopperCache.cs
- VarRefManager.cs
- SoapReflectionImporter.cs
- ClonableStack.cs
- VariableModifiersHelper.cs
- RelationshipDetailsRow.cs
- PrimitiveCodeDomSerializer.cs
- MinMaxParagraphWidth.cs
- RegistrationServices.cs
- TraceHandler.cs
- URL.cs
- XmlValueConverter.cs
- DataGridItem.cs