PlanCompiler.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / Query / PlanCompiler / PlanCompiler.cs / 1 / PlanCompiler.cs

                             //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....], [....]
//--------------------------------------------------------------------- 
 
using System;
using System.Collections.Generic; 
using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...

using cqt = System.Data.Common.CommandTrees;
using md = System.Data.Metadata.Edm; 
using System.Data.Query.InternalTrees;
using System.Data.Query.PlanCompiler; 
 
namespace System.Data.Query.PlanCompiler
{ 
    /// 
    /// The PlanCompiler class is used by the BridgeCommand to produce an
    /// execution plan - this execution plan is the plan object. The plan compilation
    /// process takes as input a command tree (in C space), and then runs through a 
    /// set of changes before the final plan is produced. The final plan contains
    /// one or more command trees (commands?) (in S space), with a set of assembly 
    /// instructions. 
    /// The compiler phases include
    /// * Convert the command tree (CTree) into an internal tree (an ITree) 
    /// * Run initializations on the ITree.
    /// * Eliminate structured types from the tree
    ///    * Eliminating named type references, refs and records from the tree
    ///    At the end of this phase, we still may have collections (and record 
    ///    arguments to collections) in the tree.
    /// * Projection pruning (ie) eliminating unused references 
    /// * Tree transformations. Various transformations are run on the ITree to 
    ///      (ostensibly) optimize the tree. These transformations are represented as
    ///      rules, and a rule processor is invoked. 
    /// * Nest elimination. At this point, we try to get pull up nest operations
    ///      as high up the tree as possible
    /// * Code Generation. This phase produces a plan object with various subpieces
    ///      of the ITree represented as commands (in S space). 
    ///    * The subtrees of the ITree are then converted into the corresponding CTrees
    ///      and converted into S space as part of the CTree creation. 
    ///    * A plan object is created and returned. 
    /// 
    internal class PlanCompiler { 

        #region private state

        ///  
        /// Bid Counter object
        ///  
        private static int _objectTypeCount; 

        ///  
        /// The object Id of this instance, for BID tracing.
        /// 
        internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
 
        /// 
        /// A boolean switch indicating whether we should apply transformation rules regardless of the size of the Iqt. 
        /// By default, the Enabled property of a boolean switch is set using the value specified in the configuration file. 
        /// Configuring the switch with a value of 0 sets the Enabled property to false; configuring the switch with a nonzero
        /// value to set the Enabled property to true. If the BooleanSwitch constructor cannot find initial switch settings 
        /// in the configuration file, the Enabled property of the new switch is set to false by default.
        /// 
        private static BooleanSwitch _applyTransformationsRegardlessOfSize = new BooleanSwitch("System.Data.EntityClient.IgnoreOptimizationLimit", "The Entity Framework should try to optimize the query regardless of its size");
 
        /// 
        /// Determines the maximum size of the query in terms of Iqt nodes for which we attempt to do transformation rules. 
        /// This number is ignored if applyTransformationsRegardlessOfSize is enabled. 
        /// 
        private const int MaxNodeCountForTransformations = 100000; 

        /// 
        /// The CTree we're compiling a plan for.
        ///  
        private cqt.DbCommandTree m_ctree;
 
        ///  
        /// The ITree we're working on.
        ///  
        private Command m_command;

        /// 
        /// The phase of the process we're currently in. 
        /// 
        private PlanCompilerPhase m_phase; 
 
        /// 
        /// Set of phases we need to go through 
        /// 
        private int m_neededPhases;

        #endregion 

        #region constructors 
 
        /// 
        /// private constructor 
        /// 
        /// the input cqt
        private PlanCompiler(cqt.DbCommandTree ctree) {
            m_ctree = ctree; // the input command tree 
        }
 
        #endregion 

        #region public interfaces 

        internal const Bid.ApiGroup PlanCompilerTracePoints = (Bid.ApiGroup)0x8000;  // That's Bit_15 for those counting at home :)

        ///  
        /// Retail Assertion code.
         /// 
        /// Provides the ability to have retail asserts. 
        /// 
        ///  
        /// 
        internal static void Assert(bool condition, string message) {
            if (!condition) {
                System.Diagnostics.Debug.Fail(message); 

                // NOTE: I considered, at great length, whether to have the assertion message text 
                //       included in the exception we throw; in the end, there really isn't a reliable 
                //       equivalent to the C++ __LINE__ and __FILE__ macros in C# (at least not without
                //       using the C++ PreProcessor...ick)  The StackTrace object comes close but 
                //       doesn't handle inlined callers properly for our needs (MethodA() calls MethodB()
                //       calls us, but MethodB() is inlined, so we'll get MethodA() info instead), and
                //       since these are retail "Asserts" (as in: we're not supposed to get them in our
                //       shipping code, and we're doing this to avoid a null-ref which is even worse) I 
                //       elected to simplify this by just including them as the additional info.
                throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.AssertionFailed, 0, message); 
            } 
        }
 
        /// 
        /// Compile a query, and produce a plan
        /// 
        /// the input CQT 
        /// list of provider commands
        /// column map for result assembly 
        /// the entity sets referenced in this query 
        /// a compiled plan object
        internal static void Compile(cqt.DbCommandTree ctree, out List providerCommands, out ColumnMap resultColumnMap, out int columnCount, out Common.Utils.Set entitySets) { 
            PlanCompiler.Assert(ctree != null, "Expected a valid, non-null Command Tree input");
            PlanCompiler pc = new PlanCompiler(ctree);
            pc.Compile(out providerCommands, out resultColumnMap, out columnCount, out entitySets);
        } 

 
        ///  
        /// Get the current command
        ///  
        internal Command Command { get { return m_command; } }

#if DEBUG
        ///  
        /// Get the current plan compiler phase
        ///  
        internal PlanCompilerPhase Phase { get { return m_phase; } } 
#endif
        ///  
        /// The MetadataWorkspace
        /// 
        internal md.MetadataWorkspace MetadataWorkspace { get { return m_ctree.MetadataWorkspace; } }
 
        /// 
        /// Is the specified phase needed for this query? 
        ///  
        /// the phase in question
        ///  
        internal bool IsPhaseNeeded(PlanCompilerPhase phase) {
            return ((m_neededPhases & (1 << (int)phase)) != 0);
        }
 
        /// 
        /// Mark the specified phase as needed 
        ///  
        /// plan compiler phase
        internal void MarkPhaseAsNeeded(PlanCompilerPhase phase) { 
            m_neededPhases = m_neededPhases | (1 << (int)phase);
        }

        ///  
        /// Mark the specified phase as not needed
        ///  
        /// plan compiler phase 
        internal void MarkPhaseAsNotNeeded(PlanCompilerPhase phase) {
            m_neededPhases = m_neededPhases & (~0 ^ (1 << (int)phase)); 
        }

        #endregion
 
        #region private methods
 
        ///  
        /// The real driver.
        ///  
        /// list of provider commands
        /// column map for the result
        /// the entity sets exposed in this query
        private void Compile(out List providerCommands, out ColumnMap resultColumnMap, out int columnCount, out Common.Utils.Set entitySets) { 
            EntityBid.Trace(" %d# Compiling Plan for DbCommandTree=%d#\n", ObjectID, m_ctree.ObjectId);
 
            Initialize(); // initialize the ITree 

            string beforePreProcessor = String.Empty; 
            string beforeNTE = String.Empty;
            string beforeProjectionPruning1 = String.Empty;
            string beforeNestPullup = String.Empty;
            string beforeProjectionPruning2 = String.Empty; 
            string beforeTransformationRules = String.Empty;
            string beforeProjectionPruning3 = String.Empty; 
            string beforeJoinElimination = String.Empty; 
            string beforeCodeGen = String.Empty;
 
            //
            // We always need the pre-processor and the codegen phases.
            // It is generally a good thing to run through the transformation rules, and
            // the projection pruning phases. 
            // The "optional" phases are NTE, NestPullup and JoinElimination
            // 
            m_neededPhases = (1 << (int)PlanCompilerPhase.PreProcessor) | 
                // (1 << (int)PlanCompilerPhase.NTE) |
                (1 << (int)PlanCompilerPhase.ProjectionPruning) | 
                // (1 << (int)PlanCompilerPhase.NestPullup) |
                (1 << (int)PlanCompilerPhase.Transformations) |
                // (1 << (int)PlanCompilerPhase.JoinElimination) |
                (1 << (int)PlanCompilerPhase.CodeGen); 

            // Perform any necessary preprocessing 
            StructuredTypeInfo typeInfo = null; 
            beforePreProcessor = SwitchToPhase(PlanCompilerPhase.PreProcessor);
            PreProcessor.Process(this, out typeInfo); 
            entitySets = typeInfo.GetEntitySets();

            // Eliminate "structured" types.
            if (IsPhaseNeeded(PlanCompilerPhase.NTE)) { 
                beforeNTE = SwitchToPhase(PlanCompilerPhase.NTE);
                NominalTypeEliminator.Process(this, typeInfo); 
            } 

            // Projection pruning - eliminate unreferenced expressions 
            if (IsPhaseNeeded(PlanCompilerPhase.ProjectionPruning)) {
                beforeProjectionPruning1 = SwitchToPhase(PlanCompilerPhase.ProjectionPruning);
                ProjectionPruner.Process(this);
            } 

            // Nest Pull-up on the ITree 
            if (IsPhaseNeeded(PlanCompilerPhase.NestPullup)) { 
                beforeNestPullup = SwitchToPhase(PlanCompilerPhase.NestPullup);
                NestPullup.Process(this); 

                //If we do Nest Pull-up, we should again do projection pruning
                beforeProjectionPruning2 = SwitchToPhase(PlanCompilerPhase.ProjectionPruning);
                ProjectionPruner.Process(this); 
            }
 
            // Run transformations on the tree 
            if (IsPhaseNeeded(PlanCompilerPhase.Transformations) && MayApplyTransformationRules()) {
                //Clear the projection pruning phase, transformation rules will set it again if needed. 
                MarkPhaseAsNotNeeded(PlanCompilerPhase.ProjectionPruning);

                beforeTransformationRules = SwitchToPhase(PlanCompilerPhase.Transformations);
                TransformationRules.ApplyAllRules(this); 

                if (IsPhaseNeeded(PlanCompilerPhase.ProjectionPruning)) { 
                    beforeProjectionPruning3 = SwitchToPhase(PlanCompilerPhase.ProjectionPruning); 
                    ProjectionPruner.Process(this);
                    TransformationRules.ApplyProjectRules(this); 
                }
            }

            // Join elimination 
            if (IsPhaseNeeded(PlanCompilerPhase.JoinElimination)) {
                //Clear the transformation rules phase, join elimination will set it again if needed. 
                MarkPhaseAsNotNeeded(PlanCompilerPhase.Transformations); 

                beforeJoinElimination = SwitchToPhase(PlanCompilerPhase.JoinElimination); 
                JoinElimination.Process(this);

                if (IsPhaseNeeded(PlanCompilerPhase.Transformations) && MayApplyTransformationRules()) {
                    TransformationRules.ApplyKeyInfoDependentRules(this); 
                }
            } 
 
            // Code generation
            beforeCodeGen = SwitchToPhase(PlanCompilerPhase.CodeGen); 
            CodeGen.Process(this, out providerCommands, out resultColumnMap, out columnCount);

#if DEBUG
            // GC.KeepAlive makes FxCop Grumpy. 
            int size = beforePreProcessor.Length;
            size = beforeNTE.Length; 
            size = beforeProjectionPruning1.Length; 
            size = beforeNestPullup.Length;
            size = beforeProjectionPruning2.Length; 
            size = beforeTransformationRules.Length;
            size = beforeProjectionPruning3.Length;
            size = beforeJoinElimination.Length;
            size = beforeCodeGen.Length; 
#endif
            if (EntityBid.TraceOn) { 
                int i = 0; 
                foreach (ProviderCommandInfo pi in providerCommands) {
                    EntityBid.Trace(" %d# resulting command %d with DbCommandTree=%d#\n", ObjectID, i++, pi.CommandTree.ObjectId); 
                }
            }

            // All done 
            return;
        } 
 
        /// 
        /// Logic to perform between each compile phase 
        /// 
        /// 
        /// 
        private string SwitchToPhase(PlanCompilerPhase newPhase) { 
            string iqtDumpResult = string.Empty;
 
            m_phase = newPhase; 

            if (EntityBid.PlanCompilerOn) { 
                iqtDumpResult = Dump.ToXml(m_command);
                EntityBid.PlanCompilerTrace(" %d# phase=%d\n", ObjectID, (int)newPhase);
                EntityBid.PlanCompilerPutStr(iqtDumpResult);
            } 
#if DEBUG
            else { 
                iqtDumpResult = Dump.ToXml(m_command); 
            }
 
            Validator.Validate(this);
#endif
            return iqtDumpResult;
        } 

        ///  
        /// Transformation rules may be applied if the number of nodes is less then MaxNodeCountForTransformations 
        /// or it is specified that they may be applied regardless of the size of the query.
        /// We approximate the number of nodes by looking at the nextNodeId. 
        /// 
        /// 
        private bool MayApplyTransformationRules() {
            return (_applyTransformationsRegardlessOfSize.Enabled 
                || (this.m_command.NextNodeId < MaxNodeCountForTransformations));
        } 
 
        /// 
        /// Converts the CTree into an ITree, and initializes the plan 
        /// 
        private void Initialize() {
            // Only support queries for now
            cqt.DbQueryCommandTree cqtree = m_ctree as cqt.DbQueryCommandTree; 
            PlanCompiler.Assert(cqtree != null, "Unexpected command tree kind. Only query command tree is supported.");
 
            // Generate the ITree 
            m_command = ITreeGenerator.Generate(cqtree);
            PlanCompiler.Assert(m_command != null, "Unable to generate internal tree from Command Tree"); 
        }

        #endregion
    } 

 
    ///  
    /// Enum describing which phase of plan compilation we're currently in
    ///  
    internal enum PlanCompilerPhase {
        /// 
        /// Just entering the PreProcessor phase
        ///  
        PreProcessor = 0,
 
        ///  
        /// Just entering the NTE (Nominal Type Eliminator) phase
        ///  
        NTE = 1,

        /// 
        /// Entering the Projection pruning phase 
        /// 
        ProjectionPruning = 2, 
 
        /// 
        /// Entering the Nest Pullup phase 
        /// 
        NestPullup = 3,

        ///  
        /// Entering the Transformations phase
        ///  
        Transformations = 4, 

        ///  
        /// Entering the JoinElimination phase
        /// 
        JoinElimination = 5,
 
        /// 
        /// Entering the codegen phase 
        ///  
        CodeGen = 6,
 
        /// 
        /// We're almost done
        /// 
        PostCodeGen = 7, 

        ///  
        /// Marker 
        /// 
        MaxMarker = 8 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
 //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....], [....]
//--------------------------------------------------------------------- 
 
using System;
using System.Collections.Generic; 
using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...

using cqt = System.Data.Common.CommandTrees;
using md = System.Data.Metadata.Edm; 
using System.Data.Query.InternalTrees;
using System.Data.Query.PlanCompiler; 
 
namespace System.Data.Query.PlanCompiler
{ 
    /// 
    /// The PlanCompiler class is used by the BridgeCommand to produce an
    /// execution plan - this execution plan is the plan object. The plan compilation
    /// process takes as input a command tree (in C space), and then runs through a 
    /// set of changes before the final plan is produced. The final plan contains
    /// one or more command trees (commands?) (in S space), with a set of assembly 
    /// instructions. 
    /// The compiler phases include
    /// * Convert the command tree (CTree) into an internal tree (an ITree) 
    /// * Run initializations on the ITree.
    /// * Eliminate structured types from the tree
    ///    * Eliminating named type references, refs and records from the tree
    ///    At the end of this phase, we still may have collections (and record 
    ///    arguments to collections) in the tree.
    /// * Projection pruning (ie) eliminating unused references 
    /// * Tree transformations. Various transformations are run on the ITree to 
    ///      (ostensibly) optimize the tree. These transformations are represented as
    ///      rules, and a rule processor is invoked. 
    /// * Nest elimination. At this point, we try to get pull up nest operations
    ///      as high up the tree as possible
    /// * Code Generation. This phase produces a plan object with various subpieces
    ///      of the ITree represented as commands (in S space). 
    ///    * The subtrees of the ITree are then converted into the corresponding CTrees
    ///      and converted into S space as part of the CTree creation. 
    ///    * A plan object is created and returned. 
    /// 
    internal class PlanCompiler { 

        #region private state

        ///  
        /// Bid Counter object
        ///  
        private static int _objectTypeCount; 

        ///  
        /// The object Id of this instance, for BID tracing.
        /// 
        internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
 
        /// 
        /// A boolean switch indicating whether we should apply transformation rules regardless of the size of the Iqt. 
        /// By default, the Enabled property of a boolean switch is set using the value specified in the configuration file. 
        /// Configuring the switch with a value of 0 sets the Enabled property to false; configuring the switch with a nonzero
        /// value to set the Enabled property to true. If the BooleanSwitch constructor cannot find initial switch settings 
        /// in the configuration file, the Enabled property of the new switch is set to false by default.
        /// 
        private static BooleanSwitch _applyTransformationsRegardlessOfSize = new BooleanSwitch("System.Data.EntityClient.IgnoreOptimizationLimit", "The Entity Framework should try to optimize the query regardless of its size");
 
        /// 
        /// Determines the maximum size of the query in terms of Iqt nodes for which we attempt to do transformation rules. 
        /// This number is ignored if applyTransformationsRegardlessOfSize is enabled. 
        /// 
        private const int MaxNodeCountForTransformations = 100000; 

        /// 
        /// The CTree we're compiling a plan for.
        ///  
        private cqt.DbCommandTree m_ctree;
 
        ///  
        /// The ITree we're working on.
        ///  
        private Command m_command;

        /// 
        /// The phase of the process we're currently in. 
        /// 
        private PlanCompilerPhase m_phase; 
 
        /// 
        /// Set of phases we need to go through 
        /// 
        private int m_neededPhases;

        #endregion 

        #region constructors 
 
        /// 
        /// private constructor 
        /// 
        /// the input cqt
        private PlanCompiler(cqt.DbCommandTree ctree) {
            m_ctree = ctree; // the input command tree 
        }
 
        #endregion 

        #region public interfaces 

        internal const Bid.ApiGroup PlanCompilerTracePoints = (Bid.ApiGroup)0x8000;  // That's Bit_15 for those counting at home :)

        ///  
        /// Retail Assertion code.
         /// 
        /// Provides the ability to have retail asserts. 
        /// 
        ///  
        /// 
        internal static void Assert(bool condition, string message) {
            if (!condition) {
                System.Diagnostics.Debug.Fail(message); 

                // NOTE: I considered, at great length, whether to have the assertion message text 
                //       included in the exception we throw; in the end, there really isn't a reliable 
                //       equivalent to the C++ __LINE__ and __FILE__ macros in C# (at least not without
                //       using the C++ PreProcessor...ick)  The StackTrace object comes close but 
                //       doesn't handle inlined callers properly for our needs (MethodA() calls MethodB()
                //       calls us, but MethodB() is inlined, so we'll get MethodA() info instead), and
                //       since these are retail "Asserts" (as in: we're not supposed to get them in our
                //       shipping code, and we're doing this to avoid a null-ref which is even worse) I 
                //       elected to simplify this by just including them as the additional info.
                throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.AssertionFailed, 0, message); 
            } 
        }
 
        /// 
        /// Compile a query, and produce a plan
        /// 
        /// the input CQT 
        /// list of provider commands
        /// column map for result assembly 
        /// the entity sets referenced in this query 
        /// a compiled plan object
        internal static void Compile(cqt.DbCommandTree ctree, out List providerCommands, out ColumnMap resultColumnMap, out int columnCount, out Common.Utils.Set entitySets) { 
            PlanCompiler.Assert(ctree != null, "Expected a valid, non-null Command Tree input");
            PlanCompiler pc = new PlanCompiler(ctree);
            pc.Compile(out providerCommands, out resultColumnMap, out columnCount, out entitySets);
        } 

 
        ///  
        /// Get the current command
        ///  
        internal Command Command { get { return m_command; } }

#if DEBUG
        ///  
        /// Get the current plan compiler phase
        ///  
        internal PlanCompilerPhase Phase { get { return m_phase; } } 
#endif
        ///  
        /// The MetadataWorkspace
        /// 
        internal md.MetadataWorkspace MetadataWorkspace { get { return m_ctree.MetadataWorkspace; } }
 
        /// 
        /// Is the specified phase needed for this query? 
        ///  
        /// the phase in question
        ///  
        internal bool IsPhaseNeeded(PlanCompilerPhase phase) {
            return ((m_neededPhases & (1 << (int)phase)) != 0);
        }
 
        /// 
        /// Mark the specified phase as needed 
        ///  
        /// plan compiler phase
        internal void MarkPhaseAsNeeded(PlanCompilerPhase phase) { 
            m_neededPhases = m_neededPhases | (1 << (int)phase);
        }

        ///  
        /// Mark the specified phase as not needed
        ///  
        /// plan compiler phase 
        internal void MarkPhaseAsNotNeeded(PlanCompilerPhase phase) {
            m_neededPhases = m_neededPhases & (~0 ^ (1 << (int)phase)); 
        }

        #endregion
 
        #region private methods
 
        ///  
        /// The real driver.
        ///  
        /// list of provider commands
        /// column map for the result
        /// the entity sets exposed in this query
        private void Compile(out List providerCommands, out ColumnMap resultColumnMap, out int columnCount, out Common.Utils.Set entitySets) { 
            EntityBid.Trace(" %d# Compiling Plan for DbCommandTree=%d#\n", ObjectID, m_ctree.ObjectId);
 
            Initialize(); // initialize the ITree 

            string beforePreProcessor = String.Empty; 
            string beforeNTE = String.Empty;
            string beforeProjectionPruning1 = String.Empty;
            string beforeNestPullup = String.Empty;
            string beforeProjectionPruning2 = String.Empty; 
            string beforeTransformationRules = String.Empty;
            string beforeProjectionPruning3 = String.Empty; 
            string beforeJoinElimination = String.Empty; 
            string beforeCodeGen = String.Empty;
 
            //
            // We always need the pre-processor and the codegen phases.
            // It is generally a good thing to run through the transformation rules, and
            // the projection pruning phases. 
            // The "optional" phases are NTE, NestPullup and JoinElimination
            // 
            m_neededPhases = (1 << (int)PlanCompilerPhase.PreProcessor) | 
                // (1 << (int)PlanCompilerPhase.NTE) |
                (1 << (int)PlanCompilerPhase.ProjectionPruning) | 
                // (1 << (int)PlanCompilerPhase.NestPullup) |
                (1 << (int)PlanCompilerPhase.Transformations) |
                // (1 << (int)PlanCompilerPhase.JoinElimination) |
                (1 << (int)PlanCompilerPhase.CodeGen); 

            // Perform any necessary preprocessing 
            StructuredTypeInfo typeInfo = null; 
            beforePreProcessor = SwitchToPhase(PlanCompilerPhase.PreProcessor);
            PreProcessor.Process(this, out typeInfo); 
            entitySets = typeInfo.GetEntitySets();

            // Eliminate "structured" types.
            if (IsPhaseNeeded(PlanCompilerPhase.NTE)) { 
                beforeNTE = SwitchToPhase(PlanCompilerPhase.NTE);
                NominalTypeEliminator.Process(this, typeInfo); 
            } 

            // Projection pruning - eliminate unreferenced expressions 
            if (IsPhaseNeeded(PlanCompilerPhase.ProjectionPruning)) {
                beforeProjectionPruning1 = SwitchToPhase(PlanCompilerPhase.ProjectionPruning);
                ProjectionPruner.Process(this);
            } 

            // Nest Pull-up on the ITree 
            if (IsPhaseNeeded(PlanCompilerPhase.NestPullup)) { 
                beforeNestPullup = SwitchToPhase(PlanCompilerPhase.NestPullup);
                NestPullup.Process(this); 

                //If we do Nest Pull-up, we should again do projection pruning
                beforeProjectionPruning2 = SwitchToPhase(PlanCompilerPhase.ProjectionPruning);
                ProjectionPruner.Process(this); 
            }
 
            // Run transformations on the tree 
            if (IsPhaseNeeded(PlanCompilerPhase.Transformations) && MayApplyTransformationRules()) {
                //Clear the projection pruning phase, transformation rules will set it again if needed. 
                MarkPhaseAsNotNeeded(PlanCompilerPhase.ProjectionPruning);

                beforeTransformationRules = SwitchToPhase(PlanCompilerPhase.Transformations);
                TransformationRules.ApplyAllRules(this); 

                if (IsPhaseNeeded(PlanCompilerPhase.ProjectionPruning)) { 
                    beforeProjectionPruning3 = SwitchToPhase(PlanCompilerPhase.ProjectionPruning); 
                    ProjectionPruner.Process(this);
                    TransformationRules.ApplyProjectRules(this); 
                }
            }

            // Join elimination 
            if (IsPhaseNeeded(PlanCompilerPhase.JoinElimination)) {
                //Clear the transformation rules phase, join elimination will set it again if needed. 
                MarkPhaseAsNotNeeded(PlanCompilerPhase.Transformations); 

                beforeJoinElimination = SwitchToPhase(PlanCompilerPhase.JoinElimination); 
                JoinElimination.Process(this);

                if (IsPhaseNeeded(PlanCompilerPhase.Transformations) && MayApplyTransformationRules()) {
                    TransformationRules.ApplyKeyInfoDependentRules(this); 
                }
            } 
 
            // Code generation
            beforeCodeGen = SwitchToPhase(PlanCompilerPhase.CodeGen); 
            CodeGen.Process(this, out providerCommands, out resultColumnMap, out columnCount);

#if DEBUG
            // GC.KeepAlive makes FxCop Grumpy. 
            int size = beforePreProcessor.Length;
            size = beforeNTE.Length; 
            size = beforeProjectionPruning1.Length; 
            size = beforeNestPullup.Length;
            size = beforeProjectionPruning2.Length; 
            size = beforeTransformationRules.Length;
            size = beforeProjectionPruning3.Length;
            size = beforeJoinElimination.Length;
            size = beforeCodeGen.Length; 
#endif
            if (EntityBid.TraceOn) { 
                int i = 0; 
                foreach (ProviderCommandInfo pi in providerCommands) {
                    EntityBid.Trace(" %d# resulting command %d with DbCommandTree=%d#\n", ObjectID, i++, pi.CommandTree.ObjectId); 
                }
            }

            // All done 
            return;
        } 
 
        /// 
        /// Logic to perform between each compile phase 
        /// 
        /// 
        /// 
        private string SwitchToPhase(PlanCompilerPhase newPhase) { 
            string iqtDumpResult = string.Empty;
 
            m_phase = newPhase; 

            if (EntityBid.PlanCompilerOn) { 
                iqtDumpResult = Dump.ToXml(m_command);
                EntityBid.PlanCompilerTrace(" %d# phase=%d\n", ObjectID, (int)newPhase);
                EntityBid.PlanCompilerPutStr(iqtDumpResult);
            } 
#if DEBUG
            else { 
                iqtDumpResult = Dump.ToXml(m_command); 
            }
 
            Validator.Validate(this);
#endif
            return iqtDumpResult;
        } 

        ///  
        /// Transformation rules may be applied if the number of nodes is less then MaxNodeCountForTransformations 
        /// or it is specified that they may be applied regardless of the size of the query.
        /// We approximate the number of nodes by looking at the nextNodeId. 
        /// 
        /// 
        private bool MayApplyTransformationRules() {
            return (_applyTransformationsRegardlessOfSize.Enabled 
                || (this.m_command.NextNodeId < MaxNodeCountForTransformations));
        } 
 
        /// 
        /// Converts the CTree into an ITree, and initializes the plan 
        /// 
        private void Initialize() {
            // Only support queries for now
            cqt.DbQueryCommandTree cqtree = m_ctree as cqt.DbQueryCommandTree; 
            PlanCompiler.Assert(cqtree != null, "Unexpected command tree kind. Only query command tree is supported.");
 
            // Generate the ITree 
            m_command = ITreeGenerator.Generate(cqtree);
            PlanCompiler.Assert(m_command != null, "Unable to generate internal tree from Command Tree"); 
        }

        #endregion
    } 

 
    ///  
    /// Enum describing which phase of plan compilation we're currently in
    ///  
    internal enum PlanCompilerPhase {
        /// 
        /// Just entering the PreProcessor phase
        ///  
        PreProcessor = 0,
 
        ///  
        /// Just entering the NTE (Nominal Type Eliminator) phase
        ///  
        NTE = 1,

        /// 
        /// Entering the Projection pruning phase 
        /// 
        ProjectionPruning = 2, 
 
        /// 
        /// Entering the Nest Pullup phase 
        /// 
        NestPullup = 3,

        ///  
        /// Entering the Transformations phase
        ///  
        Transformations = 4, 

        ///  
        /// Entering the JoinElimination phase
        /// 
        JoinElimination = 5,
 
        /// 
        /// Entering the codegen phase 
        ///  
        CodeGen = 6,
 
        /// 
        /// We're almost done
        /// 
        PostCodeGen = 7, 

        ///  
        /// Marker 
        /// 
        MaxMarker = 8 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK