File: VarRefManager.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (222 lines) | stat: -rw-r--r-- 8,886 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
//---------------------------------------------------------------------
// <copyright file="VarRefManager.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// @owner  Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics;
using System.Data.Query.InternalTrees;

namespace System.Data.Query.PlanCompiler
{
    /// <summary>
    /// This is a halper module for <see cref="JoinElimination"/>
    /// The VarRefManager keeps track of the child-parent relationships in order to be able
    /// to decide whether a given var is referenced by children on right-side relatives of a given node.
    /// It is used in JoinElimination when deciding whether it is possible to eliminate the child table participating
    /// in a left-outer join when there is a 1 - 0..1 FK relationship.
    /// </summary>
    internal class VarRefManager
    {
        #region Internal State
        private Dictionary<Node, Node> m_nodeToParentMap;   //child-parent mapping
        private Dictionary<Node, int> m_nodeToSiblingNumber;   //the index of the given node among its siblings, i.e. 0 for a first child
        Command m_command;
        #endregion

        #region Constructor
        /// <summary>
        /// Constructs a new VarRefManager given a command.
        /// </summary>
        /// <param name="command"></param>
        internal VarRefManager(Command command)
        {
            m_nodeToParentMap = new Dictionary<Node, Node>();
            m_nodeToSiblingNumber = new Dictionary<Node, int>();
            m_command = command;
        }
        #endregion

        #region Public Methods

        /// <summary>
        /// Tracks the information that the given node is a parent of its children (one level only)
        /// </summary>
        /// <param name="parent"></param>
        internal void AddChildren(Node parent)
        {
            for(int i=0; i< parent.Children.Count; i++)
            {                
                //We do not use add on purpose, we may be updating a child's parent after join elimination in a subtree
                m_nodeToParentMap[parent.Children[i]] = parent;
                m_nodeToSiblingNumber[parent.Children[i]] = i;
            }
        }

        /// <summary>
        /// Determines whether any var from a given list of keys is referenced by any of defining node's right relatives, 
        /// with the exception of the relatives brunching at the given targetJoinNode.
        /// </summary>
        /// <param name="keys">A list of vars to check for</param>
        /// <param name="definingNode">The node considered to be the defining node</param>
        /// <param name="targetJoinNode">The relatives branching at this node are skipped</param>
        /// <returns>False, only it can determine that not a single var from a given list of keys is referenced by any 
        /// of defining node's right relatives, with the exception of the relatives brunching at the given targetJoinNode. </returns>
        internal bool HasKeyReferences(VarVec keys, Node definingNode, Node targetJoinNode)
        {
            Node currentChild = definingNode;
            Node parent;
            bool continueUp = true;

            while (continueUp & m_nodeToParentMap.TryGetValue(currentChild, out parent))
            {
                if (parent != targetJoinNode)
                {
                    // Check the parent
                    if (HasVarReferencesShallow(parent, keys, m_nodeToSiblingNumber[currentChild], out continueUp))
                    {
                        return true;
                    }

                    //Check all the siblings to the right
                    for (int i = m_nodeToSiblingNumber[currentChild] + 1; i < parent.Children.Count; i++)
                    {
                        if (parent.Children[i].GetNodeInfo(m_command).ExternalReferences.Overlaps(keys))
                        {
                            return true;
                        }
                    }
                }
                currentChild = parent;
            }
            return false;
        }

        #endregion

        #region Private Methods
        /// <summary>
        /// Checks whether the given node has references to any of the vars in the given VarVec.
        /// It only checks the given node, not its children.
        /// </summary>
        /// <param name="node">The node to check</param>
        /// <param name="vars">The list of vars to check for</param>
        /// <param name="childIndex">The index of the node's subree from which this var is coming.
        /// This is used for SetOp-s, to be able to locate the appropriate var map that will give the
        /// vars corresponding to the given once</param>
        /// <param name="continueUp">If the OpType of the node's Op is such that it 'hides' the input, i.e.
        /// the decision of whether the given vars are referenced can be made on this level, it returns true,
        /// false otherwise</param>
        /// <returns>True if the given node has references to any of the vars in the given VarVec, false otherwise</returns>
        private static bool HasVarReferencesShallow(Node node, VarVec vars, int childIndex, out bool continueUp)
        {
            switch (node.Op.OpType)
            {
                case OpType.ConstrainedSort:
                case OpType.Sort:
                    continueUp = true;
                    return HasVarReferences(((SortBaseOp)node.Op).Keys, vars);

                case OpType.Distinct:
                    continueUp = false;
                    return HasVarReferences(((DistinctOp)node.Op).Keys, vars);

                case OpType.Except:
                case OpType.Intersect:
                case OpType.UnionAll:
                    continueUp = false;
                    return HasVarReferences((SetOp)node.Op, vars, childIndex);

                case OpType.GroupBy:
                    continueUp = false;
                    return HasVarReferences(((GroupByOp)node.Op).Keys, vars);

                case OpType.PhysicalProject:
                    continueUp = false;
                    return HasVarReferences(((PhysicalProjectOp)node.Op).Outputs, vars);

                case OpType.Project:
                    continueUp = false;
                    return HasVarReferences(((ProjectOp)node.Op).Outputs, vars);

                default:
                    continueUp = true;
                    return false;
            }
        }

        /// <summary>
        /// Does the gvien VarList overlap with the given VarVec
        /// </summary>
        /// <param name="listToCheck"></param>
        /// <param name="vars"></param>
        /// <returns></returns>
        private static bool HasVarReferences(VarList listToCheck, VarVec vars)
        {
            foreach (Var var in vars)
            {
                if (listToCheck.Contains(var))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Do the two given varVecs overlap
        /// </summary>
        /// <param name="listToCheck"></param>
        /// <param name="vars"></param>
        /// <returns></returns>
        private static bool HasVarReferences(VarVec listToCheck, VarVec vars)
        {
            return listToCheck.Overlaps(vars);
        }

        /// <summary>
        /// Does the given list of sort keys contain a key with a var that is the given VarVec
        /// </summary>
        /// <param name="listToCheck"></param>
        /// <param name="vars"></param>
        /// <returns></returns>
        private static bool HasVarReferences(List<InternalTrees.SortKey> listToCheck, VarVec vars)
        {
            foreach (InternalTrees.SortKey key in listToCheck)
            {
                if (vars.IsSet(key.Var))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Does the list of outputs of the given SetOp contain a var 
        /// from the given VarVec defined by the SetOp's child with the given index
        /// </summary>
        /// <param name="op"></param>
        /// <param name="vars"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private static bool HasVarReferences(SetOp op, VarVec vars, int index)
        {
            foreach (Var var in op.VarMap[index].Values)
            {
                if (vars.IsSet(var))
                {
                    return true;
                }
            }
            return false;
        }
        #endregion
    }
}