PropertyPushdownHelper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Query / PlanCompiler / PropertyPushdownHelper.cs / 1305376 / PropertyPushdownHelper.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections.Generic;
//using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...
using System.Globalization;
 
using System.Data.Common;
using md = System.Data.Metadata.Edm; 
using System.Data.Query.InternalTrees; 

namespace System.Data.Query.PlanCompiler 
{

    /// 
    /// The PropertyPushdownHelper module is a submodule of the StructuredTypeEliminator 
    /// module. It serves as a useful optimization sidekick for NominalTypeEliminator which
    /// is the real guts of eliminating structured types. 
    /// 
    /// The goal of this module is to identify a list of desired properties for each node
    /// (and Var) in the tree that is of a structured type. This list of desired properties 
    /// is identified in a top-down push fashion.
    ///
    /// While it is desirable to get as accurate information as possible, it is unnecessary
    /// for this module to be super-efficient (i.e.) it is ok for it to get a superset 
    /// of the appropriate information for each node, but it is absolutely not ok for it
    /// to get a subset. Later phases (projection pruning) can help eliminate unnecessary 
    /// information, but the query cannot be made incorrect. 
    ///
    /// This module is implemented as a visitor - it leverages information about 
    /// types in the query - made possible by the TypeFlattener module - and walks
    /// down the tree pushing properties to each child of a node. It builds two maps:
    ///
    ///     (*) a node-property map 
    ///     (*) a var-property map
    /// 
    /// Each of these keeps trackof the properties needed from each node/var. 
    ///
    /// These maps are returned to the caller and will be used by the NominalTypeEliminator 
    /// module to eliminate all structured types.
    /// 
    internal class PropertyPushdownHelper : BasicOpVisitor
    { 

        #region private state 
 
        private readonly Dictionary m_nodePropertyRefMap;
        private readonly Dictionary m_varPropertyRefMap; 
        private readonly StructuredTypeInfo m_structuredTypeInfo;

        #endregion
 
        #region constructor
 
        private PropertyPushdownHelper(StructuredTypeInfo structuredTypeInfo) 
        {
            m_structuredTypeInfo = structuredTypeInfo; 
            m_varPropertyRefMap = new Dictionary();
            m_nodePropertyRefMap = new Dictionary();
        }
 
        #endregion
 
        #region Process Driver 

        ///  
        /// The driver.
        /// Walks the tree, and "pushes" down information about required properties
        /// to every node and Var in the tree.
        ///  
        /// The query tree
        /// Type info for structured types appearing in query. 
        /// List of desired properties from each Var 
        /// List of desired properties from each node
        internal static void Process(Command itree, StructuredTypeInfo structuredTypeInfo, out Dictionary varPropertyRefs, out Dictionary nodePropertyRefs) 
        {
            PropertyPushdownHelper pph = new PropertyPushdownHelper(structuredTypeInfo);
            pph.Process(itree.Root);
 
            varPropertyRefs = pph.m_varPropertyRefMap;
            nodePropertyRefs = pph.m_nodePropertyRefMap; 
        } 

        ///  
        /// the driver routine. Invokes the visitor, and then returns the collected
        /// info
        /// 
        /// node in the tree to begin processing at 
        private void Process(Node rootNode)
        { 
            // simply invoke the visitor 
            rootNode.Op.Accept(this, rootNode);
        } 

        #endregion

        #region private methods 

        #region state maintenance 
 
        /// 
        /// Get the list of propertyrefs for a node. If none exists, create an 
        /// empty structure and store it in the map
        /// 
        /// Specific node
        /// List of properties expected from this node 
        private PropertyRefList GetPropertyRefList(Node node)
        { 
            PropertyRefList propRefs; 
            if (!m_nodePropertyRefMap.TryGetValue(node, out propRefs))
            { 
                propRefs = new PropertyRefList();
                m_nodePropertyRefMap[node] = propRefs;
            }
            return propRefs; 
        }
 
        ///  
        /// Add a list of property references for this node
        ///  
        /// the node
        /// list of property references
        private void AddPropertyRefs(Node node, PropertyRefList propertyRefs)
        { 
            PropertyRefList refs = GetPropertyRefList(node);
            refs.Append(propertyRefs); 
        } 

        ///  
        /// Get the list of desired properties for a Var
        /// 
        /// the var
        /// List of desired properties 
        private PropertyRefList GetPropertyRefList(Var v)
        { 
            PropertyRefList propRefs; 
            if (!m_varPropertyRefMap.TryGetValue(v, out propRefs))
            { 
                propRefs = new PropertyRefList();
                m_varPropertyRefMap[v] = propRefs;
            }
            return propRefs; 
        }
 
        ///  
        /// Add a new set of properties to a Var
        ///  
        /// the var
        /// desired properties
        private void AddPropertyRefs(Var v, PropertyRefList propertyRefs)
        { 
            PropertyRefList currentRefs = GetPropertyRefList(v);
            currentRefs.Append(propertyRefs); 
        } 

        #endregion 

        #region Visitor Helpers

        ///  
        /// Gets the list of "identity" properties for an entity. Gets the
        /// "entitysetid" property in addition to the "key" properties 
        ///  
        /// 
        ///  
        private static PropertyRefList GetIdentityProperties(md.EntityType type)
        {
            PropertyRefList desiredProperties = GetKeyProperties(type);
            desiredProperties.Add(EntitySetIdPropertyRef.Instance); 
            return desiredProperties;
        } 
 
        /// 
        /// Gets the list of key properties for an entity 
        /// 
        /// 
        /// 
        private static PropertyRefList GetKeyProperties(md.EntityType entityType) 
        {
            PropertyRefList desiredProperties = new PropertyRefList(); 
            foreach (md.EdmMember p in entityType.KeyMembers) 
            {
                md.EdmProperty edmP = p as md.EdmProperty; 
                PlanCompiler.Assert(edmP != null, "EntityType had non-EdmProperty key member?");
                SimplePropertyRef pRef = new SimplePropertyRef(edmP);
                desiredProperties.Add(pRef);
            } 
            return desiredProperties;
        } 
 
        #endregion
 
        /// 
        /// Default visitor for an Op.
        ///
        /// Simply walks through all children looking for Ops of structured 
        /// types, and asks for all their properties.
        ///  
        ///  
        /// Several of the ScalarOps take the default handling, to simply ask
        /// for all the children's properties: 
        ///
        ///     AggegateOp
        ///     ArithmeticOp
        ///     CastOp 
        ///     ConditionalOp
        ///     ConstantOp 
        ///     ElementOp 
        ///     ExistsOp
        ///     FunctionOp 
        ///     GetRefKeyOp
        ///     LikeOp
        ///     NestAggregateOp
        ///     NewInstanceOp 
        ///     NewMultisetOp
        ///     NewRecordOp 
        ///     RefOp 
        ///
        /// They do not exist here to eliminate noise. 
        ///
        /// Note that the NewRecordOp and the NewInstanceOp could be optimized to only
        /// push down the appropriate references, but it isn't clear to Murali that the
        /// complexity is worth it. 
        /// 
        ///  
        protected override void VisitDefault(Node n) 
        {
            // for each child that is a complex type, simply ask for all properties 
            foreach (Node chi in n.Children)
            {
                ScalarOp chiOp = chi.Op as ScalarOp;
                if (chiOp != null && TypeUtils.IsStructuredType(chiOp.Type)) 
                {
                    AddPropertyRefs(chi, PropertyRefList.All); 
                } 
            }
            VisitChildren(n); 
        }

        #region ScalarOps
 
        /// 
        /// SoftCastOp: 
        /// If the input is 
        ///    Ref - ask for all properties
        ///    Entity, ComplexType - ask for the same properties I've been asked for 
        ///    Record - ask for all properties (Note: This should be more optimized in the future
        ///        since we can actually "remap" the properties)
        /// 
        ///  
        /// 
        public override void Visit(SoftCastOp op, Node n) 
        { 
            PropertyRefList childProps = null;
 
            if (md.TypeSemantics.IsReferenceType(op.Type))
            {
                childProps = PropertyRefList.All;
            } 
            else if (md.TypeSemantics.IsNominalType(op.Type))
            { 
                PropertyRefList myProps = m_nodePropertyRefMap[n]; 
                childProps = myProps.Clone();
            } 
            else if (md.TypeSemantics.IsRowType(op.Type))
            {
                //
                // Note: We should do a better job here (by translating 
                // our PropertyRefs to the equivalent property refs on the child
                // 
                childProps = PropertyRefList.All; 
            }
 
            if (childProps != null)
            {
                AddPropertyRefs(n.Child0, childProps);
            } 
            VisitChildren(n);
        } 
 
        /// 
        /// CaseOp handling 
        ///
        /// Pushes its desired properties to each of the WHEN/ELSE clauses
        /// 
        ///  
        /// 
        public override void Visit(CaseOp op, Node n) 
        { 
            // First find the properties that my parent expects from me
            PropertyRefList pdProps = GetPropertyRefList(n); 

            // push down the same properties to my then/else clauses.
            // the "when" clauses are irrelevant
            for (int i = 1; i < n.Children.Count - 1; i += 2) 
            {
                PropertyRefList cdProps = pdProps.Clone(); 
                AddPropertyRefs(n.Children[i], cdProps); 
            }
            AddPropertyRefs(n.Children[n.Children.Count - 1], pdProps.Clone()); 

            // Now visit the children
            VisitChildren(n);
        } 

        ///  
        /// CollectOp handling. 
        /// 
        ///  
        /// 
        public override void Visit(CollectOp op, Node n)
        {
            // Simply visit the children without pushing down any references to them. 
            VisitChildren(n);
        } 
 
        /// 
        /// ComparisonOp handling 
        /// 
        /// 
        /// 
        public override void Visit(ComparisonOp op, Node n) 
        {
            // Check to see if the children are structured types. Furthermore, 
            // if the children are of entity types, then all we really need are 
            // the key properties (and the entityset property)
            // For record and ref types, simply keep going 
            md.TypeUsage childOpType = (n.Child0.Op as ScalarOp).Type;

            if (!TypeUtils.IsStructuredType(childOpType))
            { 
                VisitChildren(n);
            } 
            else if (md.TypeSemantics.IsRowType(childOpType) || md.TypeSemantics.IsReferenceType(childOpType)) 
                VisitDefault(n);
            else 
            {
                PlanCompiler.Assert(md.TypeSemantics.IsEntityType(childOpType), "unexpected childOpType?");
                PropertyRefList desiredProperties = GetIdentityProperties(TypeHelpers.GetEdmType(childOpType));
 
                // Now push these set of properties to each child
                foreach (Node chi in n.Children) 
                    AddPropertyRefs(chi, desiredProperties); 

                // Visit the children 
                VisitChildren(n);
            }
        }
 
        /// 
        /// ElementOp handling 
        ///  
        /// 
        ///  
        public override void Visit(ElementOp op, Node n)
        {
            // Cannot occur at this stage of processing
            throw EntityUtil.NotSupported(); 
        }
 
        ///  
        /// GetEntityRefOp handling
        /// 
        /// Ask for the "identity" properties from the input entity, and push that
        /// down to my child
        /// 
        ///  
        /// 
        public override void Visit(GetEntityRefOp op, Node n) 
        { 
            ScalarOp childOp = n.Child0.Op as ScalarOp;
            PlanCompiler.Assert(childOp != null, "input to GetEntityRefOp is not a ScalarOp?"); 

            // bug 428542 - the child is of the entity type; not this op
            md.EntityType entityType = TypeHelpers.GetEdmType(childOp.Type);
 
            PropertyRefList desiredProperties = GetIdentityProperties(entityType);
            AddPropertyRefs(n.Child0, desiredProperties); 
 
            VisitNode(n.Child0);
        } 

        /// 
        /// IsOfOp handling
        /// 
        /// Simply requests the "typeid" property from
        /// the input. No other property is required 
        ///  
        /// IsOf op
        /// Node to visit 
        public override void Visit(IsOfOp op, Node n)
        {

            // The only property I need from my child is the typeid property; 
            PropertyRefList childProps = new PropertyRefList();
            childProps.Add(TypeIdPropertyRef.Instance); 
            AddPropertyRefs(n.Child0, childProps); 

            VisitChildren(n); 
        }

        /// 
        /// Common handler for RelPropertyOp and PropertyOp. 
        /// Simply pushes down the desired set of properties to the child
        ///  
        /// the *propertyOp 
        /// node tree corresponding to the Op
        /// the property reference 
        private void VisitPropertyOp(Op op, Node n, PropertyRef propertyRef)
        {
            PropertyRefList cdProps = new PropertyRefList();
            if (!TypeUtils.IsStructuredType(op.Type)) 
            {
                cdProps.Add(propertyRef); 
            } 
            else
            { 
                // Get the list of properties my parent expects from me.
                PropertyRefList pdProps = GetPropertyRefList(n);

                // Ask my child (which is really my container type) for each of these 
                // properties
 
                // If I've been asked for all my properties, then get the 
                // corresponding flat list of properties from my children.
                // For now, however, simply ask for all properties in this case 
                // What we really need to do is to get the "flattened" list of
                // properties from the input, and prepend each of these with
                // our property name. We don't have that info available, so
                // I'm taking the easier route. 
                if (pdProps.AllProperties)
                { 
                    cdProps = pdProps; 
                }
                else 
                {
                    foreach (PropertyRef p in pdProps.Properties)
                    {
                        cdProps.Add(p.CreateNestedPropertyRef(propertyRef)); 
                    }
                } 
            } 

            // push down my expectations 
            AddPropertyRefs(n.Child0, cdProps);
            VisitChildren(n);
        }
 
        /// 
        /// RelPropertyOp handling. 
        /// Delegates to VisitPropertyOp. Marks the rel-property as required from the 
        /// child
        ///  
        /// the RelPropertyOp
        /// node tree corresponding to the op
        public override void Visit(RelPropertyOp op, Node n)
        { 
            VisitPropertyOp(op, n, new RelPropertyRef(op.PropertyInfo));
        } 
 
        /// 
        /// PropertyOp handling 
        ///
        /// Pushes down the requested properties along with the current
        /// property to the child
        ///  
        /// 
        ///  
        public override void Visit(PropertyOp op, Node n) 
        {
            VisitPropertyOp(op, n, new SimplePropertyRef(op.PropertyInfo)); 
        }

        /// 
        /// TreatOp handling 
        ///
        /// Simply passes down "my" desired properties, and additionally 
        /// asks for the TypeID property 
        /// 
        ///  
        /// 
        public override void Visit(TreatOp op, Node n)
        {
            // First find the properties that my parent expects from me 
            PropertyRefList pdProps = GetPropertyRefList(n);
 
            // Push down each of these, and in addition, push down the typeid property 
            // to my child
            PropertyRefList childProps = pdProps.Clone(); 
            childProps.Add(TypeIdPropertyRef.Instance);
            AddPropertyRefs(n.Child0, childProps);
            VisitChildren(n);
        } 

        ///  
        /// VarRefOp handling 
        ///
        /// Simply passes along the current "desired" properties 
        /// to the corresponding Var
        /// 
        /// 
        ///  
        public override void Visit(VarRefOp op, Node n)
        { 
            if (TypeUtils.IsStructuredType(op.Var.Type)) 
            {
                // Get the properties that my parent expects from me. 
                PropertyRefList myProps = GetPropertyRefList(n);
                // Add this onto the list of properties expected from the var itself
                AddPropertyRefs(op.Var, myProps);
            } 
        }
 
        #endregion 

        #region AncillaryOps 

        /// 
        /// VarDefOp handling
        /// 
        /// Pushes the "desired" properties to the
        /// defining expression 
        ///  
        /// 
        ///  
        public override void Visit(VarDefOp op, Node n)
        {
            if (TypeUtils.IsStructuredType(op.Var.Type))
            { 
                PropertyRefList myProps = GetPropertyRefList(op.Var);
                // Push this down to the expression defining the var 
                AddPropertyRefs(n.Child0, myProps); 
            }
            VisitChildren(n); 
        }

        /// 
        /// VarDefListOp handling 
        /// 
        ///  
        ///  
        public override void Visit(VarDefListOp op, Node n)
        { 
            // Simply visit the children without pushing down any references to them.
            VisitChildren(n);
        }
 
        #endregion
 
        #region RelOps 

        ///  
        /// ApplyOp handling
        /// CrossApplyOp handling
        /// OuterApplyOp handling
        /// 
        /// Handling for all ApplyOps: Process the right child, and then
        /// the left child - since the right child may have references to the 
        /// left 
        /// 
        /// apply op 
        /// 
        protected override void VisitApplyOp(ApplyBaseOp op, Node n)
        {
            VisitNode(n.Child1); // the right input 
            VisitNode(n.Child0); // the left input
        } 
 

        ///  
        /// DistinctOp handling
        ///
        /// Require all properties out of all structured vars
        ///  
        /// 
        ///  
        public override void Visit(DistinctOp op, Node n) 
        {
            foreach (Var v in op.Keys) 
                if (TypeUtils.IsStructuredType(v.Type))
                {
                    AddPropertyRefs(v, PropertyRefList.All);
                } 
            VisitChildren(n);
        } 
 
        /// 
        /// FilterOp handling 
        ///
        /// Process the predicate child, and then the input child - since the
        /// predicate child will probably have references to the input.
        ///  
        /// 
        ///  
        public override void Visit(FilterOp op, Node n) 
        {
            VisitNode(n.Child1); // visit predicate first 
            VisitNode(n.Child0); // then visit the relop input
        }

        ///  
        /// GroupByOp handling
        ///  
        ///  
        /// 
        protected override void VisitGroupByOp(GroupByBaseOp op, Node n) 
        {
            // First "request" all properties for every key (that is a structured type)
            foreach (Var v in op.Keys)
            { 
                if (TypeUtils.IsStructuredType(v.Type))
                { 
                    AddPropertyRefs(v, PropertyRefList.All); 
                }
            } 

            // Now visit the aggregate definitions, the key definitions, and
            // the relop input in that order
            VisitChildrenReverse(n); 
        }
 
 
        /// 
        /// JoinOp handling 
        /// CrossJoinOp handling
        /// InnerJoinOp handling
        /// LeftOuterJoinOp handling
        /// FullOuterJoinOp handling 
        ///
        /// Handler for all JoinOps. For all joins except cross joins, process 
        /// the predicate first, and then the inputs - the inputs can be processed 
        /// in any order.
        /// 
        /// For cross joins, simply process all the (relop) inputs
        /// 
        /// join op
        ///  
        protected override void VisitJoinOp(JoinBaseOp op, Node n)
        { 
            if (n.Op.OpType == OpType.CrossJoin) 
                VisitChildren(n);
            else 
            {
                VisitNode(n.Child2); // the predicate first
                VisitNode(n.Child0); // then, the left input
                VisitNode(n.Child1); // the right input 
            }
        } 
 
        /// 
        /// ProjectOp handling 
        /// 
        /// 
        /// 
        public override void Visit(ProjectOp op, Node n) 
        {
            VisitNode(n.Child1); // visit projections first 
            VisitNode(n.Child0); // then visit the relop input 
        }
 

        /// 
        /// ScanTableOp handler
        ///  
        /// 
        ///  
        public override void Visit(ScanTableOp op, Node n) 
        {
            PlanCompiler.Assert(!n.HasChild0, "scanTableOp with an input?"); 
        }

        /// 
        /// ScanViewOp 
        ///
        /// ask for all properties from the view definition 
        /// that have currently been requested from the view itself 
        /// 
        /// current ScanViewOp 
        /// current node
        public override void Visit(ScanViewOp op, Node n)
        {
            PlanCompiler.Assert(op.Table.Columns.Count == 1, "ScanViewOp with multiple columns?"); 
            Var columnVar = op.Table.Columns[0];
            PropertyRefList columnProps = GetPropertyRefList(columnVar); 
 
            Var inputVar = NominalTypeEliminator.GetSingletonVar(n.Child0);
            PlanCompiler.Assert(inputVar != null, "cannot determine single Var from ScanViewOp's input"); 

            AddPropertyRefs(inputVar, columnProps.Clone());

            VisitChildren(n); 
        }
 
        ///  
        /// SetOp handling
        /// UnionAllOp handling 
        /// IntersectOp handling
        /// ExceptOp handling
        ///
        /// Visitor for a SetOp. Pushes desired properties to the corresponding 
        /// Vars of the input
        ///  
        /// the setop 
        /// 
        protected override void VisitSetOp(SetOp op, Node n) 
        {
            foreach (VarMap varMap in op.VarMap)
                foreach (KeyValuePair kv in varMap)
                { 
                    if (TypeUtils.IsStructuredType(kv.Key.Type))
                    { 
                        // Get the set of expected properties for the unionVar, and 
                        // push it down to the inputvars
                        // For Intersect and ExceptOps, we need all properties 
                        // from the input
                        // We call GetPropertyRefList() always to initialize
                        // the map, even though we may not use it
                        // 
                        PropertyRefList myProps = GetPropertyRefList(kv.Key);
                        if (op.OpType == OpType.Intersect || op.OpType == OpType.Except) 
                        { 
                            myProps = PropertyRefList.All;
                            // We "want" all properties even on the output of the setop 
                            AddPropertyRefs(kv.Key, myProps);
                        }
                        else
                        { 
                            myProps = myProps.Clone();
                        } 
                        AddPropertyRefs(kv.Value, myProps); 
                    }
                } 
            VisitChildren(n);
        }

        ///  
        /// SortOp handling
        /// 
        /// First, "request" that for any sort key that is a structured type, we 
        /// need all its properties. Then process any local definitions, and
        /// finally the relop input 
        /// 
        /// 
        /// 
        protected override void VisitSortOp(SortBaseOp op, Node n) 
        {
            // foreach sort key, every single bit of the Var is needed 
            foreach (InternalTrees.SortKey sk in op.Keys) 
                if (TypeUtils.IsStructuredType(sk.Var.Type))
                    AddPropertyRefs(sk.Var, PropertyRefList.All); 

            // if the sort has any local definitions, process those first
            if (n.HasChild1)
                VisitNode(n.Child1); 
            // then process the relop input
            VisitNode(n.Child0); 
        } 

        ///  
        /// UnnestOp handling
        /// 
        /// 
        ///  
        public override void Visit(UnnestOp op, Node n)
        { 
            VisitChildren(n); 
        }
 
        #endregion

        #region PhysicalOps
 
        /// 
        /// PhysicalProjectOp handling 
        ///  
        /// 
        ///  
        public override void Visit(PhysicalProjectOp op, Node n)
        {
            // Insist that we need all properties from all the outputs
            foreach (Var v in op.Outputs) 
            {
                if (TypeUtils.IsStructuredType(v.Type)) 
                { 
                    AddPropertyRefs(v, PropertyRefList.All);
                } 
            }

            // simply visit the children
            VisitChildren(n); 
        }
 
        ///  
        /// MultiStreamNestOp handling
        ///  
        /// 
        /// 
        public override void Visit(MultiStreamNestOp op, Node n)
        { 
            // Cannot occur at this stage of processing
            throw EntityUtil.NotSupported(); 
        } 

        ///  
        /// SingleStreamNestOp handling
        /// 
        /// 
        ///  
        public override void Visit(SingleStreamNestOp op, Node n)
        { 
            // Cannot occur at this stage of processing 
            throw EntityUtil.NotSupported();
        } 

        #endregion

        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections.Generic;
//using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...
using System.Globalization;
 
using System.Data.Common;
using md = System.Data.Metadata.Edm; 
using System.Data.Query.InternalTrees; 

namespace System.Data.Query.PlanCompiler 
{

    /// 
    /// The PropertyPushdownHelper module is a submodule of the StructuredTypeEliminator 
    /// module. It serves as a useful optimization sidekick for NominalTypeEliminator which
    /// is the real guts of eliminating structured types. 
    /// 
    /// The goal of this module is to identify a list of desired properties for each node
    /// (and Var) in the tree that is of a structured type. This list of desired properties 
    /// is identified in a top-down push fashion.
    ///
    /// While it is desirable to get as accurate information as possible, it is unnecessary
    /// for this module to be super-efficient (i.e.) it is ok for it to get a superset 
    /// of the appropriate information for each node, but it is absolutely not ok for it
    /// to get a subset. Later phases (projection pruning) can help eliminate unnecessary 
    /// information, but the query cannot be made incorrect. 
    ///
    /// This module is implemented as a visitor - it leverages information about 
    /// types in the query - made possible by the TypeFlattener module - and walks
    /// down the tree pushing properties to each child of a node. It builds two maps:
    ///
    ///     (*) a node-property map 
    ///     (*) a var-property map
    /// 
    /// Each of these keeps trackof the properties needed from each node/var. 
    ///
    /// These maps are returned to the caller and will be used by the NominalTypeEliminator 
    /// module to eliminate all structured types.
    /// 
    internal class PropertyPushdownHelper : BasicOpVisitor
    { 

        #region private state 
 
        private readonly Dictionary m_nodePropertyRefMap;
        private readonly Dictionary m_varPropertyRefMap; 
        private readonly StructuredTypeInfo m_structuredTypeInfo;

        #endregion
 
        #region constructor
 
        private PropertyPushdownHelper(StructuredTypeInfo structuredTypeInfo) 
        {
            m_structuredTypeInfo = structuredTypeInfo; 
            m_varPropertyRefMap = new Dictionary();
            m_nodePropertyRefMap = new Dictionary();
        }
 
        #endregion
 
        #region Process Driver 

        ///  
        /// The driver.
        /// Walks the tree, and "pushes" down information about required properties
        /// to every node and Var in the tree.
        ///  
        /// The query tree
        /// Type info for structured types appearing in query. 
        /// List of desired properties from each Var 
        /// List of desired properties from each node
        internal static void Process(Command itree, StructuredTypeInfo structuredTypeInfo, out Dictionary varPropertyRefs, out Dictionary nodePropertyRefs) 
        {
            PropertyPushdownHelper pph = new PropertyPushdownHelper(structuredTypeInfo);
            pph.Process(itree.Root);
 
            varPropertyRefs = pph.m_varPropertyRefMap;
            nodePropertyRefs = pph.m_nodePropertyRefMap; 
        } 

        ///  
        /// the driver routine. Invokes the visitor, and then returns the collected
        /// info
        /// 
        /// node in the tree to begin processing at 
        private void Process(Node rootNode)
        { 
            // simply invoke the visitor 
            rootNode.Op.Accept(this, rootNode);
        } 

        #endregion

        #region private methods 

        #region state maintenance 
 
        /// 
        /// Get the list of propertyrefs for a node. If none exists, create an 
        /// empty structure and store it in the map
        /// 
        /// Specific node
        /// List of properties expected from this node 
        private PropertyRefList GetPropertyRefList(Node node)
        { 
            PropertyRefList propRefs; 
            if (!m_nodePropertyRefMap.TryGetValue(node, out propRefs))
            { 
                propRefs = new PropertyRefList();
                m_nodePropertyRefMap[node] = propRefs;
            }
            return propRefs; 
        }
 
        ///  
        /// Add a list of property references for this node
        ///  
        /// the node
        /// list of property references
        private void AddPropertyRefs(Node node, PropertyRefList propertyRefs)
        { 
            PropertyRefList refs = GetPropertyRefList(node);
            refs.Append(propertyRefs); 
        } 

        ///  
        /// Get the list of desired properties for a Var
        /// 
        /// the var
        /// List of desired properties 
        private PropertyRefList GetPropertyRefList(Var v)
        { 
            PropertyRefList propRefs; 
            if (!m_varPropertyRefMap.TryGetValue(v, out propRefs))
            { 
                propRefs = new PropertyRefList();
                m_varPropertyRefMap[v] = propRefs;
            }
            return propRefs; 
        }
 
        ///  
        /// Add a new set of properties to a Var
        ///  
        /// the var
        /// desired properties
        private void AddPropertyRefs(Var v, PropertyRefList propertyRefs)
        { 
            PropertyRefList currentRefs = GetPropertyRefList(v);
            currentRefs.Append(propertyRefs); 
        } 

        #endregion 

        #region Visitor Helpers

        ///  
        /// Gets the list of "identity" properties for an entity. Gets the
        /// "entitysetid" property in addition to the "key" properties 
        ///  
        /// 
        ///  
        private static PropertyRefList GetIdentityProperties(md.EntityType type)
        {
            PropertyRefList desiredProperties = GetKeyProperties(type);
            desiredProperties.Add(EntitySetIdPropertyRef.Instance); 
            return desiredProperties;
        } 
 
        /// 
        /// Gets the list of key properties for an entity 
        /// 
        /// 
        /// 
        private static PropertyRefList GetKeyProperties(md.EntityType entityType) 
        {
            PropertyRefList desiredProperties = new PropertyRefList(); 
            foreach (md.EdmMember p in entityType.KeyMembers) 
            {
                md.EdmProperty edmP = p as md.EdmProperty; 
                PlanCompiler.Assert(edmP != null, "EntityType had non-EdmProperty key member?");
                SimplePropertyRef pRef = new SimplePropertyRef(edmP);
                desiredProperties.Add(pRef);
            } 
            return desiredProperties;
        } 
 
        #endregion
 
        /// 
        /// Default visitor for an Op.
        ///
        /// Simply walks through all children looking for Ops of structured 
        /// types, and asks for all their properties.
        ///  
        ///  
        /// Several of the ScalarOps take the default handling, to simply ask
        /// for all the children's properties: 
        ///
        ///     AggegateOp
        ///     ArithmeticOp
        ///     CastOp 
        ///     ConditionalOp
        ///     ConstantOp 
        ///     ElementOp 
        ///     ExistsOp
        ///     FunctionOp 
        ///     GetRefKeyOp
        ///     LikeOp
        ///     NestAggregateOp
        ///     NewInstanceOp 
        ///     NewMultisetOp
        ///     NewRecordOp 
        ///     RefOp 
        ///
        /// They do not exist here to eliminate noise. 
        ///
        /// Note that the NewRecordOp and the NewInstanceOp could be optimized to only
        /// push down the appropriate references, but it isn't clear to Murali that the
        /// complexity is worth it. 
        /// 
        ///  
        protected override void VisitDefault(Node n) 
        {
            // for each child that is a complex type, simply ask for all properties 
            foreach (Node chi in n.Children)
            {
                ScalarOp chiOp = chi.Op as ScalarOp;
                if (chiOp != null && TypeUtils.IsStructuredType(chiOp.Type)) 
                {
                    AddPropertyRefs(chi, PropertyRefList.All); 
                } 
            }
            VisitChildren(n); 
        }

        #region ScalarOps
 
        /// 
        /// SoftCastOp: 
        /// If the input is 
        ///    Ref - ask for all properties
        ///    Entity, ComplexType - ask for the same properties I've been asked for 
        ///    Record - ask for all properties (Note: This should be more optimized in the future
        ///        since we can actually "remap" the properties)
        /// 
        ///  
        /// 
        public override void Visit(SoftCastOp op, Node n) 
        { 
            PropertyRefList childProps = null;
 
            if (md.TypeSemantics.IsReferenceType(op.Type))
            {
                childProps = PropertyRefList.All;
            } 
            else if (md.TypeSemantics.IsNominalType(op.Type))
            { 
                PropertyRefList myProps = m_nodePropertyRefMap[n]; 
                childProps = myProps.Clone();
            } 
            else if (md.TypeSemantics.IsRowType(op.Type))
            {
                //
                // Note: We should do a better job here (by translating 
                // our PropertyRefs to the equivalent property refs on the child
                // 
                childProps = PropertyRefList.All; 
            }
 
            if (childProps != null)
            {
                AddPropertyRefs(n.Child0, childProps);
            } 
            VisitChildren(n);
        } 
 
        /// 
        /// CaseOp handling 
        ///
        /// Pushes its desired properties to each of the WHEN/ELSE clauses
        /// 
        ///  
        /// 
        public override void Visit(CaseOp op, Node n) 
        { 
            // First find the properties that my parent expects from me
            PropertyRefList pdProps = GetPropertyRefList(n); 

            // push down the same properties to my then/else clauses.
            // the "when" clauses are irrelevant
            for (int i = 1; i < n.Children.Count - 1; i += 2) 
            {
                PropertyRefList cdProps = pdProps.Clone(); 
                AddPropertyRefs(n.Children[i], cdProps); 
            }
            AddPropertyRefs(n.Children[n.Children.Count - 1], pdProps.Clone()); 

            // Now visit the children
            VisitChildren(n);
        } 

        ///  
        /// CollectOp handling. 
        /// 
        ///  
        /// 
        public override void Visit(CollectOp op, Node n)
        {
            // Simply visit the children without pushing down any references to them. 
            VisitChildren(n);
        } 
 
        /// 
        /// ComparisonOp handling 
        /// 
        /// 
        /// 
        public override void Visit(ComparisonOp op, Node n) 
        {
            // Check to see if the children are structured types. Furthermore, 
            // if the children are of entity types, then all we really need are 
            // the key properties (and the entityset property)
            // For record and ref types, simply keep going 
            md.TypeUsage childOpType = (n.Child0.Op as ScalarOp).Type;

            if (!TypeUtils.IsStructuredType(childOpType))
            { 
                VisitChildren(n);
            } 
            else if (md.TypeSemantics.IsRowType(childOpType) || md.TypeSemantics.IsReferenceType(childOpType)) 
                VisitDefault(n);
            else 
            {
                PlanCompiler.Assert(md.TypeSemantics.IsEntityType(childOpType), "unexpected childOpType?");
                PropertyRefList desiredProperties = GetIdentityProperties(TypeHelpers.GetEdmType(childOpType));
 
                // Now push these set of properties to each child
                foreach (Node chi in n.Children) 
                    AddPropertyRefs(chi, desiredProperties); 

                // Visit the children 
                VisitChildren(n);
            }
        }
 
        /// 
        /// ElementOp handling 
        ///  
        /// 
        ///  
        public override void Visit(ElementOp op, Node n)
        {
            // Cannot occur at this stage of processing
            throw EntityUtil.NotSupported(); 
        }
 
        ///  
        /// GetEntityRefOp handling
        /// 
        /// Ask for the "identity" properties from the input entity, and push that
        /// down to my child
        /// 
        ///  
        /// 
        public override void Visit(GetEntityRefOp op, Node n) 
        { 
            ScalarOp childOp = n.Child0.Op as ScalarOp;
            PlanCompiler.Assert(childOp != null, "input to GetEntityRefOp is not a ScalarOp?"); 

            // bug 428542 - the child is of the entity type; not this op
            md.EntityType entityType = TypeHelpers.GetEdmType(childOp.Type);
 
            PropertyRefList desiredProperties = GetIdentityProperties(entityType);
            AddPropertyRefs(n.Child0, desiredProperties); 
 
            VisitNode(n.Child0);
        } 

        /// 
        /// IsOfOp handling
        /// 
        /// Simply requests the "typeid" property from
        /// the input. No other property is required 
        ///  
        /// IsOf op
        /// Node to visit 
        public override void Visit(IsOfOp op, Node n)
        {

            // The only property I need from my child is the typeid property; 
            PropertyRefList childProps = new PropertyRefList();
            childProps.Add(TypeIdPropertyRef.Instance); 
            AddPropertyRefs(n.Child0, childProps); 

            VisitChildren(n); 
        }

        /// 
        /// Common handler for RelPropertyOp and PropertyOp. 
        /// Simply pushes down the desired set of properties to the child
        ///  
        /// the *propertyOp 
        /// node tree corresponding to the Op
        /// the property reference 
        private void VisitPropertyOp(Op op, Node n, PropertyRef propertyRef)
        {
            PropertyRefList cdProps = new PropertyRefList();
            if (!TypeUtils.IsStructuredType(op.Type)) 
            {
                cdProps.Add(propertyRef); 
            } 
            else
            { 
                // Get the list of properties my parent expects from me.
                PropertyRefList pdProps = GetPropertyRefList(n);

                // Ask my child (which is really my container type) for each of these 
                // properties
 
                // If I've been asked for all my properties, then get the 
                // corresponding flat list of properties from my children.
                // For now, however, simply ask for all properties in this case 
                // What we really need to do is to get the "flattened" list of
                // properties from the input, and prepend each of these with
                // our property name. We don't have that info available, so
                // I'm taking the easier route. 
                if (pdProps.AllProperties)
                { 
                    cdProps = pdProps; 
                }
                else 
                {
                    foreach (PropertyRef p in pdProps.Properties)
                    {
                        cdProps.Add(p.CreateNestedPropertyRef(propertyRef)); 
                    }
                } 
            } 

            // push down my expectations 
            AddPropertyRefs(n.Child0, cdProps);
            VisitChildren(n);
        }
 
        /// 
        /// RelPropertyOp handling. 
        /// Delegates to VisitPropertyOp. Marks the rel-property as required from the 
        /// child
        ///  
        /// the RelPropertyOp
        /// node tree corresponding to the op
        public override void Visit(RelPropertyOp op, Node n)
        { 
            VisitPropertyOp(op, n, new RelPropertyRef(op.PropertyInfo));
        } 
 
        /// 
        /// PropertyOp handling 
        ///
        /// Pushes down the requested properties along with the current
        /// property to the child
        ///  
        /// 
        ///  
        public override void Visit(PropertyOp op, Node n) 
        {
            VisitPropertyOp(op, n, new SimplePropertyRef(op.PropertyInfo)); 
        }

        /// 
        /// TreatOp handling 
        ///
        /// Simply passes down "my" desired properties, and additionally 
        /// asks for the TypeID property 
        /// 
        ///  
        /// 
        public override void Visit(TreatOp op, Node n)
        {
            // First find the properties that my parent expects from me 
            PropertyRefList pdProps = GetPropertyRefList(n);
 
            // Push down each of these, and in addition, push down the typeid property 
            // to my child
            PropertyRefList childProps = pdProps.Clone(); 
            childProps.Add(TypeIdPropertyRef.Instance);
            AddPropertyRefs(n.Child0, childProps);
            VisitChildren(n);
        } 

        ///  
        /// VarRefOp handling 
        ///
        /// Simply passes along the current "desired" properties 
        /// to the corresponding Var
        /// 
        /// 
        ///  
        public override void Visit(VarRefOp op, Node n)
        { 
            if (TypeUtils.IsStructuredType(op.Var.Type)) 
            {
                // Get the properties that my parent expects from me. 
                PropertyRefList myProps = GetPropertyRefList(n);
                // Add this onto the list of properties expected from the var itself
                AddPropertyRefs(op.Var, myProps);
            } 
        }
 
        #endregion 

        #region AncillaryOps 

        /// 
        /// VarDefOp handling
        /// 
        /// Pushes the "desired" properties to the
        /// defining expression 
        ///  
        /// 
        ///  
        public override void Visit(VarDefOp op, Node n)
        {
            if (TypeUtils.IsStructuredType(op.Var.Type))
            { 
                PropertyRefList myProps = GetPropertyRefList(op.Var);
                // Push this down to the expression defining the var 
                AddPropertyRefs(n.Child0, myProps); 
            }
            VisitChildren(n); 
        }

        /// 
        /// VarDefListOp handling 
        /// 
        ///  
        ///  
        public override void Visit(VarDefListOp op, Node n)
        { 
            // Simply visit the children without pushing down any references to them.
            VisitChildren(n);
        }
 
        #endregion
 
        #region RelOps 

        ///  
        /// ApplyOp handling
        /// CrossApplyOp handling
        /// OuterApplyOp handling
        /// 
        /// Handling for all ApplyOps: Process the right child, and then
        /// the left child - since the right child may have references to the 
        /// left 
        /// 
        /// apply op 
        /// 
        protected override void VisitApplyOp(ApplyBaseOp op, Node n)
        {
            VisitNode(n.Child1); // the right input 
            VisitNode(n.Child0); // the left input
        } 
 

        ///  
        /// DistinctOp handling
        ///
        /// Require all properties out of all structured vars
        ///  
        /// 
        ///  
        public override void Visit(DistinctOp op, Node n) 
        {
            foreach (Var v in op.Keys) 
                if (TypeUtils.IsStructuredType(v.Type))
                {
                    AddPropertyRefs(v, PropertyRefList.All);
                } 
            VisitChildren(n);
        } 
 
        /// 
        /// FilterOp handling 
        ///
        /// Process the predicate child, and then the input child - since the
        /// predicate child will probably have references to the input.
        ///  
        /// 
        ///  
        public override void Visit(FilterOp op, Node n) 
        {
            VisitNode(n.Child1); // visit predicate first 
            VisitNode(n.Child0); // then visit the relop input
        }

        ///  
        /// GroupByOp handling
        ///  
        ///  
        /// 
        protected override void VisitGroupByOp(GroupByBaseOp op, Node n) 
        {
            // First "request" all properties for every key (that is a structured type)
            foreach (Var v in op.Keys)
            { 
                if (TypeUtils.IsStructuredType(v.Type))
                { 
                    AddPropertyRefs(v, PropertyRefList.All); 
                }
            } 

            // Now visit the aggregate definitions, the key definitions, and
            // the relop input in that order
            VisitChildrenReverse(n); 
        }
 
 
        /// 
        /// JoinOp handling 
        /// CrossJoinOp handling
        /// InnerJoinOp handling
        /// LeftOuterJoinOp handling
        /// FullOuterJoinOp handling 
        ///
        /// Handler for all JoinOps. For all joins except cross joins, process 
        /// the predicate first, and then the inputs - the inputs can be processed 
        /// in any order.
        /// 
        /// For cross joins, simply process all the (relop) inputs
        /// 
        /// join op
        ///  
        protected override void VisitJoinOp(JoinBaseOp op, Node n)
        { 
            if (n.Op.OpType == OpType.CrossJoin) 
                VisitChildren(n);
            else 
            {
                VisitNode(n.Child2); // the predicate first
                VisitNode(n.Child0); // then, the left input
                VisitNode(n.Child1); // the right input 
            }
        } 
 
        /// 
        /// ProjectOp handling 
        /// 
        /// 
        /// 
        public override void Visit(ProjectOp op, Node n) 
        {
            VisitNode(n.Child1); // visit projections first 
            VisitNode(n.Child0); // then visit the relop input 
        }
 

        /// 
        /// ScanTableOp handler
        ///  
        /// 
        ///  
        public override void Visit(ScanTableOp op, Node n) 
        {
            PlanCompiler.Assert(!n.HasChild0, "scanTableOp with an input?"); 
        }

        /// 
        /// ScanViewOp 
        ///
        /// ask for all properties from the view definition 
        /// that have currently been requested from the view itself 
        /// 
        /// current ScanViewOp 
        /// current node
        public override void Visit(ScanViewOp op, Node n)
        {
            PlanCompiler.Assert(op.Table.Columns.Count == 1, "ScanViewOp with multiple columns?"); 
            Var columnVar = op.Table.Columns[0];
            PropertyRefList columnProps = GetPropertyRefList(columnVar); 
 
            Var inputVar = NominalTypeEliminator.GetSingletonVar(n.Child0);
            PlanCompiler.Assert(inputVar != null, "cannot determine single Var from ScanViewOp's input"); 

            AddPropertyRefs(inputVar, columnProps.Clone());

            VisitChildren(n); 
        }
 
        ///  
        /// SetOp handling
        /// UnionAllOp handling 
        /// IntersectOp handling
        /// ExceptOp handling
        ///
        /// Visitor for a SetOp. Pushes desired properties to the corresponding 
        /// Vars of the input
        ///  
        /// the setop 
        /// 
        protected override void VisitSetOp(SetOp op, Node n) 
        {
            foreach (VarMap varMap in op.VarMap)
                foreach (KeyValuePair kv in varMap)
                { 
                    if (TypeUtils.IsStructuredType(kv.Key.Type))
                    { 
                        // Get the set of expected properties for the unionVar, and 
                        // push it down to the inputvars
                        // For Intersect and ExceptOps, we need all properties 
                        // from the input
                        // We call GetPropertyRefList() always to initialize
                        // the map, even though we may not use it
                        // 
                        PropertyRefList myProps = GetPropertyRefList(kv.Key);
                        if (op.OpType == OpType.Intersect || op.OpType == OpType.Except) 
                        { 
                            myProps = PropertyRefList.All;
                            // We "want" all properties even on the output of the setop 
                            AddPropertyRefs(kv.Key, myProps);
                        }
                        else
                        { 
                            myProps = myProps.Clone();
                        } 
                        AddPropertyRefs(kv.Value, myProps); 
                    }
                } 
            VisitChildren(n);
        }

        ///  
        /// SortOp handling
        /// 
        /// First, "request" that for any sort key that is a structured type, we 
        /// need all its properties. Then process any local definitions, and
        /// finally the relop input 
        /// 
        /// 
        /// 
        protected override void VisitSortOp(SortBaseOp op, Node n) 
        {
            // foreach sort key, every single bit of the Var is needed 
            foreach (InternalTrees.SortKey sk in op.Keys) 
                if (TypeUtils.IsStructuredType(sk.Var.Type))
                    AddPropertyRefs(sk.Var, PropertyRefList.All); 

            // if the sort has any local definitions, process those first
            if (n.HasChild1)
                VisitNode(n.Child1); 
            // then process the relop input
            VisitNode(n.Child0); 
        } 

        ///  
        /// UnnestOp handling
        /// 
        /// 
        ///  
        public override void Visit(UnnestOp op, Node n)
        { 
            VisitChildren(n); 
        }
 
        #endregion

        #region PhysicalOps
 
        /// 
        /// PhysicalProjectOp handling 
        ///  
        /// 
        ///  
        public override void Visit(PhysicalProjectOp op, Node n)
        {
            // Insist that we need all properties from all the outputs
            foreach (Var v in op.Outputs) 
            {
                if (TypeUtils.IsStructuredType(v.Type)) 
                { 
                    AddPropertyRefs(v, PropertyRefList.All);
                } 
            }

            // simply visit the children
            VisitChildren(n); 
        }
 
        ///  
        /// MultiStreamNestOp handling
        ///  
        /// 
        /// 
        public override void Visit(MultiStreamNestOp op, Node n)
        { 
            // Cannot occur at this stage of processing
            throw EntityUtil.NotSupported(); 
        } 

        ///  
        /// SingleStreamNestOp handling
        /// 
        /// 
        ///  
        public override void Visit(SingleStreamNestOp op, Node n)
        { 
            // Cannot occur at this stage of processing 
            throw EntityUtil.NotSupported();
        } 

        #endregion

        #endregion 
    }
} 

// 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