98e9d1d3b6708e238c8898d4a1f988daec4e4825
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Query / PlanCompiler / CTreeGenerator.cs
1 //---------------------------------------------------------------------
2 // <copyright file="CTreeGenerator.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner  Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10 //using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...
11
12 // It is fine to use Debug.Assert in cases where you assert an obvious thing that is supposed
13 // to prevent from simple mistakes during development (e.g. method argument validation 
14 // in cases where it was you who created the variables or the variables had already been validated or 
15 // in "else" clauses where due to code changes (e.g. adding a new value to an enum type) the default 
16 // "else" block is chosen why the new condition should be treated separately). This kind of asserts are 
17 // (can be) helpful when developing new code to avoid simple mistakes but have no or little value in 
18 // the shipped product. 
19 // PlanCompiler.Assert *MUST* be used to verify conditions in the trees. These would be assumptions 
20 // about how the tree was built etc. - in these cases we probably want to throw an exception (this is
21 // what PlanCompiler.Assert does when the condition is not met) if either the assumption is not correct 
22 // or the tree was built/rewritten not the way we thought it was.
23 // Use your judgment - if you rather remove an assert than ship it use Debug.Assert otherwise use
24 // PlanCompiler.Assert.
25
26
27 namespace System.Data.Query.PlanCompiler
28 {
29     using System;
30     using System.Collections.Generic;
31     using System.Data;
32     using System.Data.Common;
33     using System.Data.Common.CommandTrees;
34     using System.Data.Common.CommandTrees.ExpressionBuilder;
35     using System.Data.Common.Utils;
36     using System.Data.Metadata.Edm;
37     using System.Data.Query.InternalTrees;
38     using System.Globalization;
39
40     internal class CTreeGenerator : BasicOpVisitorOfT<DbExpression>
41     {
42         #region Nested Types
43
44         /// <summary>
45         /// The VarInfo class tracks how a single IQT Var should be referenced in terms of CQT Expressions.
46         /// The tracked Var must have been introduced by an IQT RelOp that was converted to a DbExpression that
47         /// is subsequently used in a DbExpressionBinding, otherwise the Var is either a ParameterVar or a locally
48         /// defined Var, which are tracked by the parameters collection of the Command and the VarDefScope
49         /// class, respectively.
50         /// An IQT Var that is tracked by a VarInfo instance is reachable in the following way:
51         /// 1. By a DbVariableReferenceExpression that references the Variable of the DbExpressionBinding that contains the DbExpression that logically publishes the IQT Var.
52         ///     This is tracked by the PublisherName property of the RelOpInfo class, which is used to track Vars brought into scope by a DbExpressionBinding.
53         ///     Without an enclosing RelOpInfo, the VarInfo is unbound and cannot be used to instantiate a CQT expression tree that is the equivalent of a VarRef of the IQT Var)
54         /// 2. By zero or more PropertyRefExpressions starting with a property of the DbVariableReferenceExpression created in step 1.
55         ///     These PropertyRefExpressions are introduced on top of the DbVariableReferenceExpression because of Join or ApplyExpressions that
56         ///     occur in the CQT between the expression that publishes the Var and the expression higher in the tree that contains a VarRefOp
57         ///     to the IQT Var that must be resolved to a CQT DbExpression. In such cases the DbExpression that logically publishes
58         ///     the IQT Var will have a record return Type.
59         ///     The required property names are tracked, in order, in the PropertyPath property of this class.
60         /// The PrependProperty method is used to update the DbPropertyExpression path required to reach
61         /// the DbVariableReferenceExpression when the referenced Variable becomes part of such a record-typed output.
62         /// </summary>
63         private class VarInfo
64         {
65             #region Private Member Variables
66             private Var _var;
67             private List<string> _propertyChain = new List<string>();
68             #endregion
69
70             /// <summary>
71             /// Gets the Var tracked by this VarInfo instance
72             /// </summary>
73             internal Var Var { get { return _var; } }
74
75             /// <summary>
76             /// Gets the names, in order of use, that should be used to build DbPropertyExpression around an initial DbVariableReferenceExpression in order to build a DbExpression subtree that correctly references the tracked IQT Var
77             /// </summary>
78             internal List<string> PropertyPath { get { return _propertyChain; } }
79
80             /// <summary>
81             /// Constructs a new VarInfo instance that tracks the specified Var.
82             /// </summary>
83             /// <param name="target">The IQT Var that this VarInfo instance should track.</param>
84             internal VarInfo(Var target)
85             {
86                 _var = target;
87             }
88
89             /// <summary>
90             /// Adds a property name to the beginning of the property path for this VarInfo instance.
91             /// Each time a new record structure is constructed on top of the expression that logically
92             /// publishes this var, another DbPropertyExpression is required around the DbVariableReferenceExpression used
93             /// to reach the Var in the CQT. Each new DbPropertyExpression must be added immediately around the
94             /// DbVariableReferenceExpression, with previous PropertyExpressions now referring to the new DbPropertyExpression.
95             /// Therefore the new property name added by this method is inserted at the start of the property path.
96             /// See the Visit methods for the Join/ApplyOps for examples of using this method to adjust the property path.
97             /// </summary>
98             /// <param name="propName">The new property name to insert at the start of the property path for the Var tracked by this VarInfo instance</param>
99             internal void PrependProperty(string propName)
100             {
101                 _propertyChain.Insert(0, propName);
102             }
103         }
104
105         /// <summary>
106         /// Groups a set of VarInfo instances together and allows certain operations (Bind/Unbind/PrependProperty)
107         /// to be performed on all instances in the VarInfoList with a single call.
108         /// </summary>
109         private class VarInfoList : List<VarInfo>
110         {
111             /// <summary>
112             /// Constructs a new, empty VarInfoList.
113             /// </summary>
114             internal VarInfoList() : base() { }
115
116             /// <summary>
117             /// Constructs a new VarInfoList that contains the specified VarInfo instances.
118             /// </summary>
119             /// <param name="elements"></param>
120             internal VarInfoList(IEnumerable<VarInfo> elements) : base(elements) { }
121
122             /// <summary>
123             /// Prepends the specified property name to the property path of all VarInfo instances in this list.
124             /// </summary>
125             /// <param name="propName"></param>
126             internal void PrependProperty(string propName)
127             {
128                 foreach (VarInfo vInf in this)
129                 {
130                     vInf.PropertyPath.Insert(0, propName);
131                 }
132             }
133
134             /// <summary>
135             /// Attempts to retrieve the VarInfo instance that tracks the specified IQT Var, if it is contained by this VarInfoList.
136             /// </summary>
137             /// <param name="targetVar">The required IQT Var</param>
138             /// <param name="varInfo">Contains the VarInfo instance that tracks the specified Var if this method returns true</param>
139             /// <returns>True if this list contains a VarInfo instance that tracks the specified Var; otherwise false</returns>
140             internal bool TryGetInfo(Var targetVar, out VarInfo varInfo)
141             {
142                 varInfo = null;
143                 foreach (VarInfo info in this)
144                 {
145                     if (info.Var == targetVar)
146                     {
147                         varInfo = info;
148                         return true;
149                     }
150                 }
151
152                 return false;
153             }
154         }
155
156         /// <summary>
157         /// IqtVarScope is used to represent one or more IQT Vars that are currently in scope and can be mapped to a corresponding CQT DbExpression subtree.
158         /// </summary>
159         private abstract class IqtVarScope
160         {
161             /// <summary>
162             /// Attempts to resolve the specified IQT Var by building or mapping to a CQT DbExpression subtree. Overridden in derived classes.
163             /// </summary>
164             /// <param name="targetVar">The IQT Var to resolve</param>
165             /// <param name="resultExpr">If the methods returns true, the DbExpression to which the Var was resolved; otherwise null</param>
166             /// <returns>True if the specified Var was successfully resolved; otherwise false</returns>
167             internal abstract bool TryResolveVar(Var targetVar, out DbExpression resultExpr);
168         }
169
170         private abstract class BindingScope : IqtVarScope
171         {
172             private readonly VarInfoList _definedVars;
173
174             internal BindingScope(IEnumerable<VarInfo> boundVars)
175             {
176                 _definedVars = new VarInfoList(boundVars);
177             }
178
179             /// <summary>
180             /// Information (current binding name, property path) about the Vars logically published by the Publisher expression
181             /// </summary>
182             internal VarInfoList PublishedVars { get { return _definedVars; } }
183             
184             /// <summary>
185             /// Implements the abstract IqtVarScope.TryResolveVar method. If the specified Var was published by this scope's DbExpression, it is mapped to a CQT DbExpression by calling CreateExpression on the VarInfo used to track it.
186             /// </summary>
187             /// <param name="targetVar">The Var to resolve</param>
188             /// <param name="resultExpr">If the method returns true, the DbExpression to which the Var was resolved; otherwise null</param>
189             /// <returns>True if the specified Var was successfully resolved; otherwise false</returns>
190             internal override bool TryResolveVar(Var targetVar, out DbExpression resultExpr)
191             {
192                 resultExpr = null;
193                 VarInfo foundInfo = null;
194                 if (_definedVars.TryGetInfo(targetVar, out foundInfo))
195                 {
196                     resultExpr = this.BindingReference;
197                     foreach (string propName in foundInfo.PropertyPath)
198                     {
199                         resultExpr = resultExpr.Property(propName);
200                     }
201
202                     return true;
203                 }
204
205                 return false;
206             }
207
208             protected abstract DbVariableReferenceExpression BindingReference { get; }
209         }
210
211         /// <summary>
212         /// Represents a collection of IQT Vars that were brought into scope by a DbExpression used in a DbExpressionBinding. This class is also used to associate those Vars with that DbExpression, which is considered the logical 'publisher' of the Vars.
213         /// </summary>
214         private class RelOpInfo : BindingScope
215         {
216             private readonly DbExpressionBinding _binding;
217             
218             internal RelOpInfo(string bindingName, DbExpression publisher, IEnumerable<VarInfo> publishedVars)
219                 : base(publishedVars)
220             {
221                 PlanCompiler.Assert(TypeSemantics.IsCollectionType(publisher.ResultType), "non-collection type used as RelOpInfo publisher");
222                 _binding = publisher.BindAs(bindingName);
223             }
224
225             /// <summary>
226             /// The unique name assigned to the CQT DbExpression that logically publishes the PublishedVars. Used primarily in ExpressionBindings that contain that DbExpression
227             /// </summary>
228             internal string PublisherName
229             {
230                 get { return _binding.VariableName; }
231             }
232
233             /// <summary>
234             /// The CQT DbExpression that logically publishes the PublishedVars
235             /// </summary>
236             internal DbExpression Publisher { get { return _binding.Expression; } }
237                         
238             /// <summary>
239             /// Creates a new DbExpressionBinding that binds the publisher DbExpression under the binding name
240             /// </summary>
241             /// <returns>The new DbExpressionBinding</returns>
242             internal DbExpressionBinding CreateBinding()
243             {
244                 return _binding;
245             }
246
247             protected override DbVariableReferenceExpression BindingReference
248             {
249                 get { return _binding.Variable; }
250             }
251         }
252
253         /// <summary>
254         /// Represents a collection of IQT Vars that were brought into scope by a DbExpression used in a DbGroupExpressionBinding. 
255         /// </summary>
256         private class GroupByScope : BindingScope
257         {
258             private readonly DbGroupExpressionBinding _binding;
259             private bool _referenceGroup;
260
261             internal GroupByScope(DbGroupExpressionBinding binding, IEnumerable<VarInfo> publishedVars)
262                 : base(publishedVars)
263             {
264                 _binding = binding;
265             }
266                 
267             /// <summary>
268             /// Returns the DbGroupExpressionBinding that backs this group-by scope
269             /// </summary>
270             /// <returns>The new DbExpressionBinding</returns>
271             internal DbGroupExpressionBinding Binding { get { return _binding; } }
272
273             internal void SwitchToGroupReference()
274             {
275                 PlanCompiler.Assert(!_referenceGroup, "SwitchToGroupReference called more than once on the same GroupByScope?");
276                 _referenceGroup = true;
277             }
278
279             protected override DbVariableReferenceExpression BindingReference
280             {
281                 get { return (_referenceGroup ? _binding.GroupVariable : _binding.Variable); }
282             }
283         }
284
285         /// <summary>
286         /// Represents a collection of IQT Vars that are in scope because they are defined locally (by VarDefOps) to an IQT Op that is being visited.
287         /// </summary>
288         private class VarDefScope : IqtVarScope
289         {
290             private Dictionary<Var, DbExpression> _definedVars;
291
292             internal VarDefScope(Dictionary<Var, DbExpression> definedVars)
293             {
294                 _definedVars = definedVars;
295             }
296
297             /// <summary>
298             /// Implements the abstract IqtVarScope.TryResolveVar method. If the specified Var exists in this scope, it is resolved by mapping it to the DbExpression that was produced by converting the IQT child Node of the VarDefOp that defines it to a CQT DbExpression subtree.
299             /// </summary>
300             /// <param name="targetVar">The Var to resolve</param>
301             /// <param name="resultExpr">If the method returns true, the DbExpression to which the Var was resolved; otherwise null</param>
302             /// <returns>True if the specified Var was successfully resolved; otherwise false</returns>
303             internal override bool TryResolveVar(Var targetVar, out DbExpression resultExpr)
304             {
305                 resultExpr = null;
306                 DbExpression foundExpr = null;
307                 if (_definedVars.TryGetValue(targetVar, out foundExpr))
308                 {
309                     resultExpr = foundExpr;
310                     return true;
311                 }
312
313                 return false;
314             }
315         }
316
317         #endregion
318
319         #region Private Instance Members
320
321         private Command _iqtCommand;
322         private DbQueryCommandTree _queryTree;
323         private Dictionary<ParameterVar, DbParameterReferenceExpression> _addedParams = new Dictionary<ParameterVar, DbParameterReferenceExpression>();
324         private Stack<IqtVarScope> _bindingScopes = new Stack<IqtVarScope>();
325         private Stack<VarDefScope> _varScopes = new Stack<VarDefScope>();
326         private Dictionary<DbExpression, RelOpInfo> _relOpState = new Dictionary<DbExpression, RelOpInfo>();
327
328         private AliasGenerator _applyAliases = new AliasGenerator("Apply");
329         private AliasGenerator _distinctAliases = new AliasGenerator("Distinct");
330         private AliasGenerator _exceptAliases = new AliasGenerator("Except");
331         private AliasGenerator _extentAliases = new AliasGenerator("Extent");
332         private AliasGenerator _filterAliases = new AliasGenerator("Filter");
333         private AliasGenerator _groupByAliases = new AliasGenerator("GroupBy");
334         private AliasGenerator _intersectAliases = new AliasGenerator("Intersect");
335         private AliasGenerator _joinAliases = new AliasGenerator("Join");
336         private AliasGenerator _projectAliases = new AliasGenerator("Project");
337         private AliasGenerator _sortAliases = new AliasGenerator("Sort");
338         private AliasGenerator _unionAllAliases = new AliasGenerator("UnionAll");
339         private AliasGenerator _elementAliases = new AliasGenerator("Element");
340         private AliasGenerator _singleRowTableAliases = new AliasGenerator("SingleRowTable");
341         private AliasGenerator _limitAliases = new AliasGenerator("Limit");
342         private AliasGenerator _skipAliases = new AliasGenerator("Skip");
343
344         #endregion
345
346         #region (pseudo) Public API
347         internal static DbCommandTree Generate(Command itree, Node toConvert)
348         {
349             CTreeGenerator treeGenerator = new CTreeGenerator(itree, toConvert);
350             return treeGenerator._queryTree;
351         }
352         #endregion
353
354         #region Constructors (private)
355         private CTreeGenerator(Command itree, Node toConvert)
356         {
357             _iqtCommand = itree;
358             DbExpression queryExpression = VisitNode(toConvert);
359             _queryTree = DbQueryCommandTree.FromValidExpression(itree.MetadataWorkspace, DataSpace.SSpace, queryExpression);
360         }
361         #endregion
362
363         #region RelOp Helpers and PublishedVar State Maintenance
364
365         /// <summary>
366         /// Asserts that the specified DbExpression is a 'RelOp' DbExpression, i.e. it is considered the publisher of one or more (IQT) RelVars.
367         /// </summary>
368         /// <param name="expr">The DbExpression on which to Assert</param>
369         private void AssertRelOp(DbExpression expr)
370         {
371             PlanCompiler.Assert(_relOpState.ContainsKey(expr),"not a relOp expression?");
372         }
373
374         /// <summary>
375         /// Update the DbExpression to RelOpInfo map to indicate that the specified DbExpression logically publishes the Vars
376         /// tracked in VarInfoList and that they should be bound under the specified name.
377         /// </summary>
378         /// <param name="name">The name under which the Vars tracked in VarInfoList are initially considered bound. This will be a unique name based on what kind of RelOp the specified DbExpression (the publisher) corresponds to</param>
379         /// <param name="expr">The DbExpression that is considered the logical publisher of the Vars tracked in publishedVars</param>
380         /// <param name="publishedVars">A VarInfoList that contains VarInfo instances that track the IQT Vars that are logically published by the specified DbExpression</param>
381         /// <returns>A new RelOpInfo instance that associates the given binding name and published Vars with the specified DbExpression. This RelOpInfo is also added to the DbExpression to RelOpInfo map</returns>
382         private RelOpInfo PublishRelOp(string name, DbExpression expr, VarInfoList publishedVars)
383         {
384             RelOpInfo retInfo = new RelOpInfo(name, expr, publishedVars);
385             _relOpState.Add(expr, retInfo);
386             return retInfo;
387         }
388
389         /// <summary>
390         /// Removes an entry in the DbExpression to RelOpInfo map, 'consuming' it so that it is not visible higher in the converted CQT.
391         /// </summary>
392         /// <param name="expr">The DbExpression for which the corresponding RelOpEntry should be removed</param>
393         /// <returns>The RelOpInfo that was removed from the DbExpression to RelOpInfo map</returns>
394         private RelOpInfo ConsumeRelOp(DbExpression expr)
395         {
396             AssertRelOp(expr);
397             RelOpInfo retInfo = _relOpState[expr];
398             _relOpState.Remove(expr);
399             return retInfo;
400         }
401
402         private RelOpInfo VisitAsRelOp(Node inputNode)
403         {
404             // Assert that the Op is actually a RelOp before attempting to use it
405             PlanCompiler.Assert(inputNode.Op is RelOp, "Non-RelOp used as DbExpressionBinding Input");
406
407             //
408             // Visit the Op. This Visit method of this class that actually processes the Op will
409             // publish the Vars produced by the resulting DbExpression in the DbExpression to RelOpInfo
410             // map, then return that DbExpression.
411             //
412             DbExpression inputExpr = VisitNode(inputNode);
413
414             //
415             // Retrieve the RelOpInfo for the DbExpression, that was published as part of the above call.
416             // ConsumeRelOp is called to both retrieve and remove the RelOpInfo instance since it is being
417             // used here in a DbExpressionBinding.
418             //
419             return ConsumeRelOp(inputExpr);
420         }
421
422         #endregion
423
424         #region Var Scope Maintenance
425         private void PushExpressionBindingScope(RelOpInfo inputState)
426         {
427             PlanCompiler.Assert(inputState != null && inputState.PublisherName != null && inputState.PublishedVars != null , "Invalid RelOpInfo produced by DbExpressionBinding Input");
428             _bindingScopes.Push(inputState);
429         }
430
431         /// <summary>
432         /// Visit a Node that will be used as the basis of a DbExpressionBinding, optionally pushing the
433         /// Vars that are logically published by the DbExpression produced from the Node's Op onto the expression binding scopes stack.
434         /// </summary>
435         /// <param name="inputNode">The Node to Visit</param>
436         /// <param name="pushScope">Indicates whether or not the Vars published by the converted form of the Node's Op should be brought into scope before this method returns</param>
437         /// <returns>The RelOpInfo that corresponds to the given Node, which details the DbExpression it was converted to, the Vars that are logically published by that DbExpression, and the unique name under which those Vars should be bound</returns>
438         private RelOpInfo EnterExpressionBindingScope(Node inputNode, bool pushScope)
439         {
440             RelOpInfo inputInfo = VisitAsRelOp(inputNode);
441
442             //
443             // If the pushScope flag is set, push the RelOpInfo onto the binding scopes stack to bring
444             // the Vars it tracks into scope.
445             //
446             if (pushScope)
447             {
448                 PushExpressionBindingScope(inputInfo);
449             }
450
451             //
452             // Return the RelOpInfo that was produced by the input Node to the caller, providing access to the
453             // DbExpression that the Node's Op was converted to, the Vars that are logically published by that DbExpression,
454             // and the unique binding name that the Vars are considered bound under - that name should be used in
455             // the DbExpressionBinding that uses the DbExpression.
456             //
457             return inputInfo;
458         }
459
460         private RelOpInfo EnterExpressionBindingScope(Node inputNode)
461         {
462             return EnterExpressionBindingScope(inputNode, true);
463         }
464
465         private void ExitExpressionBindingScope(RelOpInfo scope, bool wasPushed)
466         {
467             if (wasPushed)
468             {
469                 PlanCompiler.Assert(_bindingScopes.Count > 0, "ExitExpressionBindingScope called on empty ExpressionBindingScope stack");
470
471                 RelOpInfo bindingScope = (RelOpInfo)_bindingScopes.Pop();
472
473                 PlanCompiler.Assert(bindingScope == scope, "ExitExpressionBindingScope called on incorrect expression");
474             }
475         }
476
477         private void ExitExpressionBindingScope(RelOpInfo scope)
478         {
479             ExitExpressionBindingScope(scope, true);
480         }
481
482         private GroupByScope EnterGroupByScope(Node inputNode)
483         {
484             RelOpInfo inputInfo = VisitAsRelOp(inputNode);
485
486             // The current binding name is saved for use later as the VarName in the DbGroupExpressionBinding.
487             string varName = inputInfo.PublisherName;
488
489             // Generate the GroupVarName, and rebind the Input Vars under that name
490             string groupVarName = string.Format(CultureInfo.InvariantCulture, "{0}Group", varName);
491             
492             DbGroupExpressionBinding newBinding = inputInfo.CreateBinding().Expression.GroupBindAs(varName, groupVarName);
493             GroupByScope newScope = new GroupByScope(newBinding, inputInfo.PublishedVars);
494             _bindingScopes.Push(newScope);
495             return newScope;
496         }
497
498         private void ExitGroupByScope(GroupByScope scope)
499         {
500             PlanCompiler.Assert(_bindingScopes.Count > 0, "ExitGroupByScope called on empty ExpressionBindingScope stack");
501
502             GroupByScope groupScope = (GroupByScope)_bindingScopes.Pop();
503
504             PlanCompiler.Assert(groupScope == scope, "ExitGroupByScope called on incorrect expression");
505         }
506
507         /// <summary>
508         /// Converts a list of VarDefOp Nodes into Expressions, builds a map of Var to DbExpression for each
509         /// defined Var, and pushes a new VarDefScope containing the map onto the stack of 'in scope' Vars.
510         /// </summary>
511         /// <param name="varDefNodes">A list of Nodes. Each Node in the list must reference a VarDefOp</param>
512         private void EnterVarDefScope(List<Node> varDefNodes)
513         {
514             //
515             // Create a new dictionary to act as the Var to DbExpression map
516             //
517             Dictionary<Var, DbExpression> varDefs = new Dictionary<Var, DbExpression>();
518
519             //
520             // For each Node in the list:
521             // 1. Assert that the Node is actually referencing a VarDefOp
522             // 2. Assert that the Var defined by the VarDefOp is actually a ComputedVar
523             // 3. Visit the Child0 Node of the Node to produce the CQT DbExpression that defines the Var
524             // 4. Add the returned DbExpression to the Var to DbExpression map.
525             foreach (Node childNode in varDefNodes)
526             {
527                 VarDefOp defOp = childNode.Op as VarDefOp;
528                 PlanCompiler.Assert(defOp != null, "VarDefListOp contained non-VarDefOp child node");
529                 PlanCompiler.Assert(defOp.Var is ComputedVar, "VarDefOp defined non-Computed Var");
530
531                 varDefs.Add(defOp.Var, VisitNode(childNode.Child0));
532             }
533
534             //
535             // Finally, construct and push a new VarDefScope based on the Var to DbExpression map onto the stack
536             // of locally 'in scope' IQT ComputedVars. All of the Vars defined in the original list are brought into scope by
537             // this final step, and are not in scope until this is done. Therefore it is not valid for any Var
538             // in the original list to refer to a Var that occurs previously in the list (left-correlation).
539             //
540             _varScopes.Push(new VarDefScope(varDefs));
541         }
542
543         /// <summary>
544         /// A convenience method to create a new VarDefScope from the specified VarDefListOp Node
545         /// </summary>
546         /// <param name="varDefListNode">The Node that references the VarDefListOp. Its children will be used as the basis of the new VarDefScope</param>
547         private void EnterVarDefListScope(Node varDefListNode)
548         {
549             PlanCompiler.Assert(varDefListNode.Op is VarDefListOp, "EnterVarDefListScope called with non-VarDefListOp");
550             EnterVarDefScope(varDefListNode.Children);
551         }
552         
553         /// <summary>
554         /// Asserts that the top of the scope stack is actually a VarDefScope, and then pops it to remove the locally defined Vars from scope.
555         /// </summary>
556         private void ExitVarDefScope()
557         {
558             PlanCompiler.Assert(_varScopes.Count > 0, "ExitVarDefScope called on empty VarDefScope stack");
559             _varScopes.Pop();
560         }
561
562         /// <summary>
563         /// Resolves an IQT Var to a CQT DbExpression.
564         /// There are 3 possible ways for an IQT Var to resolve to a valid reference expressed as a CQT DbExpression:
565         /// 1. The specified Var is a valid ParameterVar in the IQT Command being converted:
566         ///     This resolves simply to ParameterRefExpression. A Parameter that corresponds to the ParameterVar
567         ///     is declared on the CQT DbCommandTree is this has not already been done.
568         /// 2. The specified Var is a ComputedVar that is defined locally to the Op being visited. In this case
569         ///     The DbExpression produced by converting the VarDefOp that defines the Var is returned.
570         /// 3. Otherwise, the Var must have been brought into scope because the DbExpression that logically produces it is
571         ///     being used in a DbExpressionBinding which is currently in scope. Each RelOpInfo on the ExpressionBindingScopes stack
572         ///     is asked to resolve the Var, if one of the RelOpInfo scopes is tracking the Var it will construct an appropriate combination
573         ///     of DbVariableReferenceExpression and PropertyRefExpressions that are sufficient to logically reference the Var.
574         /// If none of the 3 above conditions are satisfied then the Var is unresolvable in the CQT being constructed and
575         /// the original IQT Command must be considered invalid for the purposes of this conversion.
576         /// </summary>
577         /// <param name="referencedVar">The IQT Var to resolve</param>
578         /// <returns>The CQT DbExpression to which the specified Var resolves</returns>
579         private DbExpression ResolveVar(Var referencedVar)
580         {
581             DbExpression retExpr = null;
582             ParameterVar paramVar = referencedVar as ParameterVar;
583             if (paramVar != null)
584             {
585                 //
586                 // If there is already a parameter expression that corresponds to this parameter Var, reuse it.
587                 //
588                 DbParameterReferenceExpression paramRef;
589                 if (!_addedParams.TryGetValue(paramVar, out paramRef))
590                 {
591                     paramRef = DbExpressionBuilder.Parameter(paramVar.Type, paramVar.ParameterName);
592                     _addedParams[paramVar] = paramRef;
593                 }
594                 retExpr = paramRef;
595             }
596             else
597             {
598                 ComputedVar compVar = referencedVar as ComputedVar;
599                 if (compVar != null)
600                 {
601                     //
602                     // If this is a ComputedVar, first check if it is defined locally to the Node of the Op being visited.
603                     // Such local ComputedVars are only directly accessible from the Op being converted, so only the topmost
604                     // ComputedVar scope on the stack should be considered.
605                     //
606                     if (_varScopes.Count > 0)
607                     {
608                         if (!_varScopes.Peek().TryResolveVar(compVar, out retExpr))
609                         {
610                             retExpr = null;
611                         }
612                     }
613                 }
614
615                 if (null == retExpr)
616                 {
617                     //
618                     // If the Var was not resolved as a locally defined ComputedVar, then it must now be a Var that was brought
619                     // into scope by a DbExpressionBinding in order to be considered valid. Each DbExpressionBinding scope (represented as a RelOpInfo)
620                     // on the binding scopes stack from top to bottom is asked in turn to resolve the Var, breaking if the Var is successfully resolved.
621                     //
622                     DbExpression foundExpr = null;
623                     foreach (IqtVarScope scope in _bindingScopes)
624                     {
625                         if (scope.TryResolveVar(referencedVar, out foundExpr))
626                         {
627                             retExpr = foundExpr;
628                             break;
629                         }
630                     }
631                 }
632             }
633
634             PlanCompiler.Assert(retExpr != null, string.Format(CultureInfo.InvariantCulture, "Unresolvable Var used in Command: VarType={0}, Id={1}", Enum.GetName(typeof(VarType), referencedVar.VarType), referencedVar.Id));
635             return retExpr;
636         }
637         #endregion
638
639         #region Visitor Helpers
640
641         /// <summary>
642         /// Asserts that the specified Node has exactly 2 child Nodes
643         /// </summary>
644         /// <param name="n">The Node on which to Assert</param>
645         private static void AssertBinary(Node n)
646         {
647             PlanCompiler.Assert(2 == n.Children.Count, string.Format(CultureInfo.InvariantCulture, "Non-Binary {0} encountered", n.Op.GetType().Name));
648         }
649
650         private DbExpression VisitChild(Node n, int index)
651         {
652             PlanCompiler.Assert(n.Children.Count > index, "VisitChild called with invalid index");
653             return VisitNode(n.Children[index]);
654         }
655
656         private new List<DbExpression> VisitChildren(Node n)
657         {
658             List<DbExpression> retList = new List<DbExpression>();
659             foreach (Node argNode in n.Children)
660             {
661                 retList.Add(VisitNode(argNode));
662             }
663
664             return retList;
665         }
666
667         #endregion
668
669         #region IOpVisitor<DbExpression> Members
670
671         #region ScalarOp Conversions
672         protected override DbExpression VisitConstantOp(ConstantBaseOp op, Node n)
673         {
674             //
675             // Simple conversion using the same constant value as the ConstantBaseOp in a CQT DbConstantExpression
676             //
677             return DbExpressionBuilder.Constant(op.Type, op.Value);
678         }
679
680         public override DbExpression Visit(ConstantOp op, Node n)
681         {
682             return VisitConstantOp(op, n);
683         }
684
685         public override DbExpression Visit(InternalConstantOp op, Node n)
686         {
687             return VisitConstantOp(op, n);
688         }
689
690         public override DbExpression Visit(NullOp op, Node n)
691         {
692             return DbExpressionBuilder.Null(op.Type);
693         }
694
695         public override DbExpression Visit(NullSentinelOp op, Node n)
696         {
697             return VisitConstantOp(op, n);
698         }
699
700         public override DbExpression Visit(ConstantPredicateOp op, Node n)
701         {
702             //
703             // Create a "true=true" for "true" predicates,
704             // Create a "true=false" expression for false predicates
705             //
706             return DbExpressionBuilder.True.Equal(op.IsTrue ? DbExpressionBuilder.True : DbExpressionBuilder.False);
707         }
708
709         public override DbExpression Visit(FunctionOp op, Node n)
710         {
711             //
712             // FunctionOp becomes DbFunctionExpression that references the same EdmFunction metadata and
713             // with argument Expressions produced by converting the child nodes of the FunctionOp's Node
714             //
715             return op.Function.Invoke(VisitChildren(n));
716         }
717
718         public override DbExpression Visit(PropertyOp op, Node n)
719         {
720             // We should never see this Op - should have been eliminated in NTE
721             throw EntityUtil.NotSupported();
722         }
723
724         public override DbExpression Visit(RelPropertyOp op, Node n)
725         {
726             // should have been eliminated in NTE
727             throw EntityUtil.NotSupported();
728         }
729
730         public override DbExpression Visit(ArithmeticOp op, Node n)
731         {
732             //
733             // ArithmeticOp converts to a DbArithmeticExpression with an appropriate DbExpressionKind.
734             //
735             DbExpression resultExpr = null;
736             if (OpType.UnaryMinus == op.OpType)
737             {
738                 // If the OpType is Unary minus, only 1 child Node is required.
739                 resultExpr = VisitChild(n, 0).UnaryMinus();
740             }
741             else
742             {
743                 // Otherwise this is a binary operator, so visit the left and right child Nodes
744                 // and convert to CQT DbExpression based on the OpType.
745                 DbExpression left = VisitChild(n, 0);
746                 DbExpression right = VisitChild(n, 1);
747
748                 switch (op.OpType)
749                 {
750                     case OpType.Divide:
751                         {
752                             resultExpr = left.Divide(right);
753                         }
754                         break;
755
756                     case OpType.Minus:
757                         {
758                             resultExpr = left.Minus(right);
759                         }
760                         break;
761
762                     case OpType.Modulo:
763                         {
764                             resultExpr = left.Modulo(right);
765                         }
766                         break;
767
768                     case OpType.Multiply:
769                         {
770                             resultExpr = left.Multiply(right);
771                         }
772                         break;
773
774                     case OpType.Plus:
775                         {
776                             resultExpr = left.Plus(right);
777                         }
778                         break;
779
780                     default:
781                         {
782                             resultExpr = null;
783                         }
784                         break;
785                 }
786             }
787
788             // The result DbExpression will only be null if a new OpType is added and this code is not updated
789             PlanCompiler.Assert(resultExpr != null, string.Format(CultureInfo.InvariantCulture, "ArithmeticOp OpType not recognized: {0}", Enum.GetName(typeof(OpType), op.OpType)));
790             return resultExpr;
791         }
792
793         public override DbExpression Visit(CaseOp op, Node n)
794         {
795             //
796             // CaseOp converts directly to DbCaseExpression.
797             // If no 'Else' Node is present a new DbNullExpression typed to the result Type of the CaseOp is used as the DbCaseExpression's Else expression.
798             // Otherwise the converted form of the 'Else' Node is used.
799             // This method assumes that the child Nodes of the CaseOp's Node are as follows:
800             // When1, Then1[..., WhenN, ThenN][, Else]
801             // that is, at least one When/Then pair MUST be present, subsequent When/Then pairs and the final Else are optional.
802
803             // This is the count of Nodes that contribute to the When/Then pairs, NOT the count of those pairs.
804             int caseCount = n.Children.Count;
805
806             // Verify the assumption made that at least one case is present.
807             PlanCompiler.Assert(caseCount > 1, "Invalid CaseOp: At least 2 child Nodes (1 When/Then pair) must be present");
808
809             List<DbExpression> whens = new List<DbExpression>();
810             List<DbExpression> thens = new List<DbExpression>();
811             DbExpression elseExpr = null;
812
813             if(0 == n.Children.Count % 2)
814             {
815                 // If the number of child Nodes is divisible by 2, it is assumed that they are When/Then pairs without the optional Else Node.
816                 // The Else DbExpression defaults to a properly typed DbNullExpression.
817                 elseExpr = DbExpressionBuilder.Null(op.Type);
818             }
819             else
820             {
821                 // Otherwise, an Else Node is present as the last child Node. It's CQT DbExpression form is used as the Else DbExpression.
822                 // The count of child Nodes that contribute to the When/Then pairs must now be reduced by 1.
823                 caseCount = caseCount - 1;
824                 elseExpr = VisitChild(n, n.Children.Count - 1);
825             }
826
827             // Convert the When/Then Nodes in pairs until the number of converted Nodes is equal to the number of Nodes that contribute to the When/Then pairs.
828             for(int idx = 0; idx < caseCount; idx += 2)
829             {
830                 whens.Add(VisitChild(n, idx));
831                 thens.Add(VisitChild(n, idx + 1));
832             }
833
834             // Create and return a new DbCaseExpression using the When and Then DbExpression lists and the (converted or DbNullExpression) Else DbExpression.
835             return DbExpressionBuilder.Case(whens, thens, elseExpr);
836         }
837
838         public override DbExpression Visit(ComparisonOp op, Node n)
839         {
840             //
841             // ComparisonOp converts to a DbComparisonExpression with an appropriate DbExpressionKind.
842             // The ComparisonOp is only convertible to a DbComparisonExpression if it has 2 child Nodes
843             //
844             AssertBinary(n);
845
846             DbExpression left = VisitChild(n, 0);
847             DbExpression right = VisitChild(n, 1);
848
849             DbExpression compExpr = null;
850
851             switch (op.OpType)
852             {
853                 case OpType.EQ:
854                     {
855                         compExpr = left.Equal(right);
856                     }
857                     break;
858
859                 case OpType.NE:
860                     {
861                         compExpr = left.NotEqual(right);
862                     }
863                     break;
864
865                 case OpType.LT:
866                     {
867                         compExpr = left.LessThan(right);
868                     }
869                     break;
870
871                 case OpType.GT:
872                     {
873                         compExpr = left.GreaterThan(right);
874                     }
875                     break;
876
877                 case OpType.LE:
878                     {
879                         compExpr = left.LessThanOrEqual(right);
880                     }
881                     break;
882
883                 case OpType.GE:
884                     {
885                         compExpr = left.GreaterThanOrEqual(right);
886                     }
887                     break;
888
889                 default:
890                     {
891                         compExpr = null;
892                     }
893                     break;
894             }
895
896             // The result DbExpression will only be null if a new OpType is added and this code is not updated
897             PlanCompiler.Assert(compExpr != null, string.Format(CultureInfo.InvariantCulture, "ComparisonOp OpType not recognized: {0}", Enum.GetName(typeof(OpType), op.OpType)));
898             return compExpr;
899         }
900
901         public override DbExpression Visit(ConditionalOp op, Node n)
902         {
903             //
904             // Boolean ConditionalOps convert to the corresponding And/Or/DbNotExpression. The IsNull ConditionalOp converts to DbIsNullExpression.
905             // In all cases the OpType is used to determine what kind of DbExpression to create.
906             //
907
908             // There will always be at least one argument (IsNull, Not) and should be at most 2 (And, Or).
909             DbExpression left = VisitChild(n, 0);
910             DbExpression condExpr = null;
911             switch (op.OpType)
912             {
913                 case OpType.IsNull:
914                     {
915                         condExpr = left.IsNull();
916                     }
917                     break;
918
919                 case OpType.And:
920                     {
921                         condExpr = left.And(VisitChild(n, 1));
922                     }
923                     break;
924
925                 case OpType.Or:
926                     {
927                         condExpr = left.Or(VisitChild(n, 1));
928                     }
929                     break;
930
931                 case OpType.Not:
932                     {
933                         // Convert Not(Not(<expression>)) to just <expression>. This is taken into account here
934                         // because LeftSemi/AntiJoin conversions generate intermediate Not(Exists(<Op>)) IQT Nodes,
935                         // which would then be converted to Not(Not(IsEmpty(<expression>)) if the following code were not present.
936                         DbNotExpression notExpr = left as DbNotExpression;
937                         if (notExpr != null)
938                         {
939                             condExpr = notExpr.Argument;
940                         }
941                         else
942                         {
943                             condExpr = left.Not();
944                         }
945                     }
946                     break;
947
948                 default:
949                     {
950                         condExpr = null;
951                     }
952                     break;
953             }
954
955             // The result DbExpression will only be null if a new OpType is added and this code is not updated
956             PlanCompiler.Assert(condExpr != null, string.Format(CultureInfo.InvariantCulture, "ConditionalOp OpType not recognized: {0}", Enum.GetName(typeof(OpType), op.OpType)));
957             return condExpr;
958         }
959
960         public override DbExpression Visit(LikeOp op, Node n)
961         {
962             //
963             // LikeOp converts to DbLikeExpression, with the conversions of the
964             // Node's first, second and third child nodes providing the
965             // Input, Pattern and Escape expressions.
966             //
967             return DbExpressionBuilder.Like(
968                     VisitChild(n, 0),
969                     VisitChild(n, 1),
970                     VisitChild(n, 2)
971                 );
972         }
973
974         public override DbExpression Visit(AggregateOp op, Node n)
975         {
976             // AggregateOp may only occur as the immediate child of a VarDefOp that is itself the
977             // child of a VarDefListOp used as the 'Aggregates' collection of a GroupByOp.
978             // As such, aggregates are handled directly during processing of GroupByOp.
979             // If this method is called an AggregateOp was encountered at some other (invalid) point in the IQT.
980             PlanCompiler.Assert(false, "AggregateOp encountered outside of GroupByOp");
981             throw EntityUtil.NotSupported(System.Data.Entity.Strings.Iqt_CTGen_UnexpectedAggregate);
982         }
983         public override DbExpression Visit(NavigateOp op, Node n)
984         {
985             // we should never see this Op
986             throw EntityUtil.NotSupported();
987         }
988
989         public override DbExpression Visit(NewEntityOp op, Node n)
990         {
991             // We should never see this Op - should have been eliminated in NTE
992             throw EntityUtil.NotSupported();
993         }
994         public override DbExpression Visit(NewInstanceOp op, Node n)
995         {
996             // We should never see this Op - should have been eliminated in NTE
997             throw EntityUtil.NotSupported();
998         }
999
1000         public override DbExpression Visit(DiscriminatedNewEntityOp op, Node n)
1001         {
1002             // We should never see this Op -  should have been eliminated in NTE
1003             throw EntityUtil.NotSupported();
1004         }
1005
1006         public override DbExpression Visit(NewMultisetOp op, Node n)
1007         {
1008             // We should never see this Op
1009             throw EntityUtil.NotSupported();
1010         }
1011
1012         public override DbExpression Visit(NewRecordOp op, Node n)
1013         {
1014             // We should never see this Op
1015             throw EntityUtil.NotSupported();
1016         }
1017
1018         public override DbExpression Visit(RefOp op, Node n)
1019         {
1020             // We should never see this Op
1021             throw EntityUtil.NotSupported();
1022         }
1023
1024         public override DbExpression Visit(VarRefOp op, Node n)
1025         {
1026             return ResolveVar(op.Var);
1027         }
1028
1029         public override DbExpression Visit(TreatOp op, Node n)
1030         {
1031             // We should never see this Op
1032             throw EntityUtil.NotSupported();
1033         }
1034
1035         public override DbExpression Visit(CastOp op, Node n)
1036         {
1037             // Direct conversion to DbCastExpression with the same Type and converted argument DbExpression
1038             return VisitChild(n, 0).CastTo(op.Type);
1039         }
1040
1041         /// <summary>
1042         /// A SoftCastOp is intended to be used only for promotion (and/or equivalence)
1043         /// and should be ignored in the CTree
1044         /// </summary>
1045         /// <param name="op">the softcast Op</param>
1046         /// <param name="n">the node</param>
1047         /// <returns></returns>
1048         public override DbExpression Visit(SoftCastOp op, Node n)
1049         {
1050             // Microsoft 9/21/06 - temporarily removing check here 
1051             //  because the assert wrongly fails in some cases where the types are promotable,
1052             //  but the facets are not.  Put this back when that issue is solved.
1053             //
1054             // PlanCompiler.Assert(TypeSemantics.IsEquivalentOrPromotableTo(n.Child0.Op.Type, op.Type),
1055             //    "Invalid use of SoftCastOp: Type " + n.Child0.Op.Type.Identity + " is not promotable to " + op.Type);
1056             return VisitChild(n, 0);
1057         }
1058
1059         public override DbExpression Visit(IsOfOp op, Node n)
1060         {
1061             // Direct conversion to DbIsOfExpression (with DbExpressionKind.IsOf) with the same Type and converted argument DbExpression
1062             if (op.IsOfOnly)
1063                 return VisitChild(n, 0).IsOfOnly(op.IsOfType);
1064             else
1065                 return VisitChild(n, 0).IsOf(op.IsOfType);
1066         }
1067
1068         public override DbExpression Visit(ExistsOp op, Node n)
1069         {
1070             //
1071             // Exists requires a RelOp input set
1072             //
1073             DbExpression inputExpr = VisitNode(n.Child0);
1074
1075             //
1076             // Information about the Vars published by the RelOp argument does not need to be maintained
1077             // since they may not now be used higher in the CQT.
1078             //
1079             ConsumeRelOp(inputExpr);
1080
1081             //
1082             // Exists --> Not(IsEmpty(Input set)) via DbExpressionBuilder.Exists
1083             //
1084             return inputExpr.IsEmpty().Not();
1085         }
1086
1087         public override DbExpression Visit(ElementOp op, Node n)
1088         {
1089             // We create this op when turning ApplyOp into a scalar subquery
1090             DbExpression inputExpr = VisitNode(n.Child0);
1091             AssertRelOp(inputExpr);
1092             ConsumeRelOp(inputExpr);
1093
1094             DbElementExpression elementExpr = DbExpressionBuilder.CreateElementExpressionUnwrapSingleProperty(inputExpr);
1095             return elementExpr;
1096         }
1097
1098         public override DbExpression Visit(GetRefKeyOp op, Node n)
1099         {
1100             // We should never see this Op
1101             throw EntityUtil.NotSupported();
1102         }
1103
1104         public override DbExpression Visit(GetEntityRefOp op, Node n)
1105         {
1106             // We should never see this Op
1107             throw EntityUtil.NotSupported();
1108         }
1109
1110         public override DbExpression Visit(CollectOp op, Node n)
1111         {
1112             // We should never get here
1113             throw EntityUtil.NotSupported();
1114         }
1115         #endregion
1116
1117         #region RelOp Conversions
1118
1119         /// <summary>
1120         /// Generates a name for the specified Var.
1121         /// If the Var has a name (TryGetName), then we use the name to look up
1122         /// the right alias generator, and get a column name from the alias generator
1123         /// Otherwise, we simply get a name from the default alias generator
1124         /// </summary>
1125         /// <param name="projectedVar">the var in question</param>
1126         /// <param name="aliasMap">map to identify the appropriate alias generator</param>
1127         /// <param name="defaultAliasGenerator">the default alias generator</param>
1128         /// <param name="alreadyUsedNames">list of already used names</param>
1129         /// <returns></returns>
1130         private static string GenerateNameForVar(Var projectedVar, Dictionary<string, AliasGenerator> aliasMap,
1131             AliasGenerator defaultAliasGenerator, Dictionary<string, string> alreadyUsedNames)
1132         {
1133             string columnName;
1134             AliasGenerator aliasGenerator;
1135
1136             if (projectedVar.TryGetName(out columnName))
1137             {
1138                 if (!aliasMap.TryGetValue(columnName, out aliasGenerator))
1139                 {
1140                     //
1141                     // No existing column in the current row with the same name. Create
1142                     // an alias-generator for future use
1143                     //
1144                     aliasGenerator = new AliasGenerator(columnName);
1145                     aliasMap[columnName] = aliasGenerator;
1146                 }
1147                 else
1148                 {
1149                     //
1150                     // Column name collides with another name in the same row. 
1151                     // Use the alias-generator to generate a new name
1152                     //
1153                     columnName = aliasGenerator.Next();
1154                 }
1155             }
1156             else
1157             {
1158                 //
1159                 // Must be a computed column or some such. Use the default alias generator
1160                 //
1161                 aliasGenerator = defaultAliasGenerator;
1162                 columnName = aliasGenerator.Next();
1163             }
1164
1165             // Check to see if I've used this name already
1166             while (alreadyUsedNames.ContainsKey(columnName))
1167             {
1168                 columnName = aliasGenerator.Next();
1169             }
1170
1171             alreadyUsedNames[columnName] = columnName;
1172             return columnName;
1173         }
1174
1175         /// <summary>
1176         /// Called by both Visit(ProjectOp) and VisitSetOpArgument to create a DbProjectExpression
1177         /// based on the RelOpInfo of the projection input and the set of projected Vars.
1178         /// Note:
1179         /// The projected Vars must have already been brought into scope (by one of the
1180         /// methods such as EnterExpressionBinding, EnterVarDefScope, etc) before this method
1181         /// is called, or the projected Vars will not be successfully resolved.
1182         /// Both Visit(ProjectOp) and VisitSetOpArgument do this"
1183         /// 1. Visit(ProjectOp) takes both DbExpressionBinding and VarDef based Vars into account
1184         /// 2. The Vars produced by a SetOpArgument projection are only allowed to be DbExpressionBinding
1185         ///    based and are brought into scope when the original SetOp argument Node is visited.
1186         /// </summary>
1187         /// <param name="sourceInfo"></param>
1188         /// <param name="outputVars"></param>
1189         /// <returns></returns>
1190         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1309:UseOrdinalStringComparison", MessageId = "System.Collections.Generic.Dictionary`2<System.String,System.String>.#ctor(System.Collections.Generic.IEqualityComparer`1<System.String>)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1309:UseOrdinalStringComparison", MessageId = "System.Collections.Generic.Dictionary`2<System.String,System.Data.Common.Utils.AliasGenerator>.#ctor(System.Collections.Generic.IEqualityComparer`1<System.String>)")]
1191         private DbExpression CreateProject(RelOpInfo sourceInfo, IEnumerable<Var> outputVars)
1192         {
1193             //
1194             // For each Var produced by the ProjectOp, call ResolveVar to retrieve the correct CQT DbExpression.
1195             // This will either be a DbExpression that references the CQT Var under which the IQT is currently
1196             // bound (if it is in scope) or it will be a copy of the DbExpression subtree that defines the Var,
1197             // if the Var is a ComputedVar defined by a local VarDefOp.
1198             // A new column name is generated to project the DbExpression, and the VarInfoList produced
1199             // by this conversion is updated to include a new VarInfo indicating that the projected Var can be
1200             // reached in the DbProjectExpression returned from this method via a property reference to the generated column name.
1201             // This is the only path element required since the Vars are an immediate product of the ProjectOp, which also hides any Vars below it.
1202             // Hence a new VarInfoList is constructed and published by the new DbProjectExpression.
1203             // The list of column name/DbExpression pairs is built to use later when constructing the projection expression.
1204             //
1205             VarInfoList projectedInfo = new VarInfoList();
1206             List<KeyValuePair<string, DbExpression>> projectedCols = new List<KeyValuePair<string, DbExpression>>();
1207             AliasGenerator colGen = new AliasGenerator("C");
1208             Dictionary<string, AliasGenerator> aliasMap = new Dictionary<string, AliasGenerator>(StringComparer.InvariantCultureIgnoreCase);
1209             Dictionary<string, string> alreadyUsedAliases = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
1210             foreach (Var projectedVar in outputVars)
1211             {
1212                 string columnName = GenerateNameForVar(projectedVar, aliasMap, colGen, alreadyUsedAliases);
1213
1214                 DbExpression columnValue = ResolveVar(projectedVar);
1215                 projectedCols.Add(new KeyValuePair<string, DbExpression>(columnName, columnValue));
1216
1217                 VarInfo colInfo = new VarInfo(projectedVar);
1218                 colInfo.PrependProperty(columnName);
1219                 projectedInfo.Add(colInfo);
1220             }
1221
1222             //
1223             // Create a new DbProjectExpression with the converted Input and a new row (DbNewInstanceExpression) projection using the
1224             // previously constructed column names and Expressions to define the shape of the resulting row. The Input is bound
1225             // under the Var publisher name specified by its RelOpInfo, which will be a unique name based on the type of RelOp it was converted from.
1226             //
1227             DbExpression retExpr = sourceInfo.CreateBinding().Project(DbExpressionBuilder.NewRow(projectedCols));
1228                 
1229             //
1230             // Publish the Vars produced by the new DbProjectExpression:
1231             // PublisherName: The next Project alias.
1232             // PublishedVars: The PublishedVars of the Project are those specified in the VarSet of the ProjectOp, reachable using the generated column names.
1233             //
1234             PublishRelOp(_projectAliases.Next(), retExpr, projectedInfo);
1235
1236             return retExpr;
1237         }
1238
1239         /// <summary>
1240         /// Called by both ScanTableOp and UnnestOp Visitor pattern methods to determine
1241         /// the shape of the output of the converted form of those Ops, in terms of the
1242         /// IQT Vars that are published by the resulting DbExpression and how those Vars should
1243         /// be reached.
1244         /// </summary>
1245         /// <param name="targetTable">The table that is logically produced by the Op. For non-record sourceTypes, this should consist of a single column that logically constitutes the entire 'table'</param>
1246         /// <returns>A VarInfoList containing VarInfo instances that correctly track the Var or Vars produced by the targetTable, in accordance with the shape of the sourceType</returns>
1247         private static VarInfoList GetTableVars(Table targetTable)
1248         {
1249             VarInfoList outputVars = new VarInfoList();
1250
1251             if (targetTable.TableMetadata.Flattened)
1252             {
1253                 // For a flat table, one Var per table column must be produced.
1254                 // There should be a ColumnVar in the targetTable's Columns collection for each
1255                 // column in the record type (for the table), and the VarInfo instances created here will track the
1256                 // fact that each ColumnVar should be reached via DbPropertyExpression of the record column's name
1257                 for (int idx = 0; idx < targetTable.Columns.Count; idx++)
1258                 {
1259                     VarInfo colInfo = new VarInfo(targetTable.Columns[idx]);
1260                     colInfo.PrependProperty(targetTable.TableMetadata.Columns[idx].Name);
1261                     outputVars.Add(colInfo);
1262                 }
1263             }
1264             else
1265             {
1266                 // Otherwise, a single Var must be produced, which is immediately reachable
1267                 outputVars.Add(new VarInfo(targetTable.Columns[0]));
1268             }
1269
1270             return outputVars;
1271         }
1272
1273         public override DbExpression Visit(ScanTableOp op, Node n)
1274         {
1275             //
1276             // Currently 2 different types of 'Table' (i.e. Extent) are supported:
1277             // Record Extents (for example an S-Space table or view)
1278             // Entity Extents (for example a C-Space EntitySet)
1279             // These extents produce results of different shapes - the EntitySet case produces simply
1280             // A collection of Entities, not a collection of records with a single Entity-typed column
1281             // This distinction is handled in the common GetTableVars method shared by ScanTableOp and
1282             // UnnestOp Visitor pattern methods.
1283             //
1284             PlanCompiler.Assert(op.Table.TableMetadata.Extent != null, "Invalid TableMetadata used in ScanTableOp - no Extent specified");
1285
1286             //
1287             // We don't expect to see any view expressions here
1288             //
1289             PlanCompiler.Assert(!n.HasChild0, "views are not expected here");
1290
1291             VarInfoList outputVars = GetTableVars(op.Table);
1292
1293             // ScanTable converts to ExtentExpression
1294             DbExpression retExpr = op.Table.TableMetadata.Extent.Scan();
1295             
1296             //
1297             // Publish the Vars that are logically produced by the ExtentExpression:
1298             // PublisherName: The next Extent alias
1299             // PublishedVars: The single Var (for an Entity extent) or multiple column-bound Vars (for a structured type extent)
1300             //  that are logically published by the ExtentExpression.
1301             //
1302             PublishRelOp(_extentAliases.Next(), retExpr, outputVars);
1303
1304             // Return the ExtentExpression
1305             return retExpr;
1306         }
1307
1308         public override DbExpression Visit(ScanViewOp op, Node n)
1309         {
1310             // We should never see this Op
1311             throw EntityUtil.NotSupported();
1312         }
1313
1314         /// <summary>
1315         /// Translate UnnestOp which is assumed (at this stage) to wrap a native ScalarOp
1316         /// that returns a collection (e.g. a table-valued function node).
1317         /// </summary>
1318         public override DbExpression Visit(UnnestOp op, Node n)
1319         {
1320             // support Unnest(VarDef(input)) -> input
1321             // where input is presumed to have a collection type (e.g. TVF)
1322             PlanCompiler.Assert(n.Child0.Op.OpType == OpType.VarDef, 
1323                 "an unnest's child must be a VarDef");
1324
1325             // get input (first child of VarDef)
1326             Node input = n.Child0.Child0;
1327
1328             // translate input
1329             DbExpression expr = input.Op.Accept(this, input);
1330
1331             // verify that the result is actually a collection
1332             PlanCompiler.Assert(expr.ResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType,
1333                 "the input to unnest must yield a collection after plan compilation");
1334
1335             // collect table vars for the unnest
1336             VarInfoList outputVars = GetTableVars(op.Table);
1337             PublishRelOp(_extentAliases.Next(), expr, outputVars);
1338
1339             return expr;
1340         }
1341
1342         /// <summary>
1343         /// Builds up an "empty" projection over the input node. Well, in reality, we build
1344         /// up a dummy projection node - which simply selects out some constant (which
1345         /// is never used). This is useful in scenarios where the outputs are
1346         /// uninteresting, but the input row count is
1347         /// </summary>
1348         /// <param name="relOpNode">the relOp node</param>
1349         /// <returns></returns>
1350         private RelOpInfo BuildEmptyProjection(Node relOpNode)
1351         {
1352             //
1353             // Ignore the projectOp at the root - if any
1354             //
1355             if (relOpNode.Op.OpType == OpType.Project)
1356             {
1357                 relOpNode = relOpNode.Child0;
1358             }
1359
1360             //
1361             // Visit the Input RelOp, bring its Var(s) into scope, and retrieve and consume the RelOpInfo that describes its published Vars
1362             //
1363             RelOpInfo sourceInfo = EnterExpressionBindingScope(relOpNode);
1364
1365             //
1366             // Create a new DbProjectExpression with the converted Input and a new row (DbNewInstanceExpression) projection using the
1367             // previously constructed column names and Expressions to define the shape of the resulting row. The Input is bound
1368             // under the Var publisher name specified by its RelOpInfo, which will be a unique name based on the type of RelOp it was converted from.
1369             //
1370             DbExpression constExpr = DbExpressionBuilder.Constant(1);
1371             List<KeyValuePair<string, DbExpression>> projectedCols = new List<KeyValuePair<string, DbExpression>>();
1372             projectedCols.Add(new KeyValuePair<string, DbExpression>("C0", constExpr));
1373
1374             DbExpression retExpr = sourceInfo.CreateBinding().Project(DbExpressionBuilder.NewRow(projectedCols));
1375                 
1376             // Publish the Vars produced by the new DbProjectExpression:
1377             // PublisherName: The next Project alias.
1378             // PublishedVars: The PublishedVars of the Project are those specified in the VarSet of the ProjectOp, reachable using the generated column names.
1379             //
1380             PublishRelOp(_projectAliases.Next(), retExpr, new VarInfoList());
1381
1382             // remove the Input's Vars from scope, unbinding the Input's VarInfos. 
1383             ExitExpressionBindingScope(sourceInfo);
1384
1385             RelOpInfo relOpInfo = ConsumeRelOp(retExpr);
1386             return relOpInfo;
1387         }
1388
1389         /// <summary>
1390         /// Build up a Project Op with exactly the Vars that we want. If the input is 
1391         /// a Project already, piggyback on it, and get the Vars we want. Otherwise, 
1392         /// create a new ProjectOp, and define the specified Vars
1393         /// 
1394         /// Note that the ProjectOp's output (element) type will be a record with the fields
1395         /// in exactly the order specified by the projectionVars argument
1396         /// 
1397         /// </summary>
1398         /// <param name="relOpNode">the input relOpNode to cap with a Project</param>
1399         /// <param name="projectionVars">List of vars we are interested in</param>
1400         /// <returns>A ProjectOp that produces the right set of Vars</returns>
1401         private RelOpInfo BuildProjection(Node relOpNode, IEnumerable<Var> projectionVars)
1402         {
1403             DbExpression retExpr = null;
1404
1405             //
1406             // If the input is a ProjectOp, then simply invoke the ProjectOp handler, but 
1407             // use the requested Vars instead
1408             //
1409             ProjectOp projectOp = relOpNode.Op as ProjectOp;
1410             if (projectOp != null)
1411             {
1412                 retExpr = VisitProject(projectOp, relOpNode, projectionVars);
1413             }
1414             else
1415             {
1416                 //
1417                 // Otherwise, treat it in a very similar fashion to a normal projectOp. The
1418                 // only difference being that we have no VarDefList argument
1419                 //
1420
1421                 //
1422                 // Visit the Input RelOp, bring its Var(s) into scope, and retrieve and consume the RelOpInfo that describes its published Vars
1423                 //
1424                 RelOpInfo sourceInfo = EnterExpressionBindingScope(relOpNode);
1425
1426                 //
1427                 // Call CreateProject to convert resolve the projected Vars,
1428                 // create the DbProjectExpression, and associate the projected Vars
1429                 // with the new DbProjectExpression in the DbExpression -> RelOpInfo map.
1430                 //
1431                 retExpr = CreateProject(sourceInfo, projectionVars);
1432
1433                 // remove the Input's Vars from scope, unbinding the Input's VarInfos. 
1434                 ExitExpressionBindingScope(sourceInfo);
1435             }
1436
1437             RelOpInfo relOpInfo = ConsumeRelOp(retExpr);
1438             return relOpInfo;
1439         }
1440
1441         DbExpression VisitProject(ProjectOp op, Node n, IEnumerable<Var> varList)
1442         {
1443             //
1444             // Visit the Input RelOp, bring its Var(s) into scope, and retrieve and consume the RelOpInfo that describes its published Vars
1445             //
1446             RelOpInfo sourceInfo = EnterExpressionBindingScope(n.Child0);
1447
1448             //
1449             // With the Input in scope, visit the VarDefs from the ProjectOp's VarDefList and bring their ComputedVars into scope
1450             //
1451             if (n.Children.Count > 1)
1452             {
1453                 EnterVarDefListScope(n.Child1);
1454             }
1455
1456             //
1457             // Call CreateProject to convert resolve the projected Vars,
1458             // create the DbProjectExpression, and associate the projected Vars
1459             // with the new DbProjectExpression in the DbExpression -> RelOpInfo map.
1460             //
1461             DbExpression retExpr = CreateProject(sourceInfo, varList);
1462
1463             // Take the local ComputedVars from the ProjectOp's VarDefList out of scope.
1464             if (n.Children.Count > 1)
1465             {
1466                 ExitVarDefScope();
1467             }
1468
1469             // remove the Input's Vars from scope, unbinding the Input's VarInfos.
1470             ExitExpressionBindingScope(sourceInfo);
1471
1472             return retExpr;
1473         }
1474
1475         public override DbExpression Visit(ProjectOp op, Node n)
1476         {
1477             return VisitProject(op, n, op.Outputs);
1478         }
1479
1480         public override DbExpression Visit(FilterOp op, Node n)
1481         {
1482             //
1483             // Visit the Input RelOp, bring its Var(s) into scope, and retrieve and consume the RelOpInfo that describes its published Vars
1484             //
1485             RelOpInfo inputInfo = EnterExpressionBindingScope(n.Child0);
1486
1487             //
1488             // Visit the Predicate with the Input Var(s) in scope and assert that the predicate is valid
1489             //
1490             DbExpression predicateExpr = VisitNode(n.Child1);
1491             PlanCompiler.Assert(TypeSemantics.IsPrimitiveType(predicateExpr.ResultType, PrimitiveTypeKind.Boolean), "Invalid FilterOp Predicate (non-ScalarOp or non-Boolean result)");
1492
1493             //
1494             // Create a new DbFilterExpression with the converted Input and Predicate.
1495             // The RelOpState produced from the Input (above) indicates the name that should be used
1496             // in the DbExpressionBinding for the Input expression (this is the name that the
1497             // Input's Vars were brought into scope with in EnterExpressionBindingScope).
1498             //
1499             DbExpression retExpr = inputInfo.CreateBinding().Filter(predicateExpr);
1500
1501             //
1502             // Remove the Input's Var(s) from scope and unbind the Input's VarInfo(s)
1503             //
1504             ExitExpressionBindingScope(inputInfo);
1505
1506             //
1507             // Update the tracked RelOpInfo for the new DbFilterExpression. This consists of:
1508             // PublisherName: The next Filter alias.
1509             // PublishedVars: The PublishedVars of the Filter are the same (now unbound) PublishedVars of its Input.
1510             //
1511             PublishRelOp(_filterAliases.Next(), retExpr, inputInfo.PublishedVars);
1512
1513             return retExpr;
1514         }
1515
1516         private List<DbSortClause> VisitSortKeys(IList<InternalTrees.SortKey> sortKeys)
1517         {
1518             VarVec sortVars = _iqtCommand.CreateVarVec();
1519             List<DbSortClause> sortClauses = new List<DbSortClause>();
1520             foreach (InternalTrees.SortKey sortKey in sortKeys)
1521             {
1522                 //
1523                 // If we've already seen the same Var, then ignore it
1524                 //
1525                 if (sortVars.IsSet(sortKey.Var))
1526                 {
1527                     continue;
1528                 }
1529                 else
1530                 {
1531                     sortVars.Set(sortKey.Var);
1532                 }
1533
1534                 DbSortClause sortClause = null;
1535                 DbExpression keyExpression = ResolveVar(sortKey.Var);
1536                 if (!string.IsNullOrEmpty(sortKey.Collation))
1537                 {
1538
1539                     sortClause = (sortKey.AscendingSort ? keyExpression.ToSortClause(sortKey.Collation) : keyExpression.ToSortClauseDescending(sortKey.Collation));
1540                 }
1541                 else
1542                 {
1543                     sortClause = (sortKey.AscendingSort ? keyExpression.ToSortClause() : keyExpression.ToSortClauseDescending());
1544                 }
1545
1546                 sortClauses.Add(sortClause);
1547             }
1548
1549             return sortClauses;
1550         }
1551
1552         public override DbExpression Visit(SortOp op, Node n)
1553         {
1554             //
1555             // Visit the Input RelOp, bring its Var(s) into scope, and retrieve and consume the RelOpInfo that describes its published Vars
1556             //
1557             RelOpInfo inputInfo = EnterExpressionBindingScope(n.Child0);
1558             PlanCompiler.Assert(!n.HasChild1, "SortOp can have only one child");
1559             
1560             //
1561             // Visit the SortKeys with the Input's Vars in scope and create the DbSortExpression
1562             //
1563             DbExpression retExpr = inputInfo.CreateBinding().Sort(VisitSortKeys(op.Keys));
1564             
1565             //
1566             // Remove the Input's Vars from scope
1567             //
1568             ExitExpressionBindingScope(inputInfo);
1569
1570             //
1571             // Update the tracked RelOpInfo for the new DbSortExpression. This consists of:
1572             // PublisherName: The next Sort alias.
1573             // PublishedVars: The PublishedVars of the Sort are the same as its Input.
1574             //
1575             PublishRelOp(_sortAliases.Next(), retExpr, inputInfo.PublishedVars);
1576             return retExpr;
1577         }
1578
1579         private DbExpression CreateLimitExpression(DbExpression argument, DbExpression limit, bool withTies)
1580         {
1581             PlanCompiler.Assert(!withTies, "Limit with Ties is not currently supported");
1582             return argument.Limit(limit);
1583         }
1584
1585         public override DbExpression Visit(ConstrainedSortOp op, Node n)
1586         {
1587             DbExpression retExpr = null;
1588             RelOpInfo inputInfo = null;
1589             string alias = null;
1590             bool nullSkip = (OpType.Null == n.Child1.Op.OpType);
1591             bool nullLimit = (OpType.Null == n.Child2.Op.OpType);
1592             PlanCompiler.Assert(!nullSkip || !nullLimit, "ConstrainedSortOp with no Skip Count and no Limit?");
1593             if (op.Keys.Count == 0)
1594             {
1595                 // Without SortKeys, this ConstrainedSortOp must represent a Limit operation applied to the input.
1596                 PlanCompiler.Assert(nullSkip, "ConstrainedSortOp without SortKeys cannot have Skip Count");
1597                 
1598                 //
1599                 // Visit the input Node and retrieve its RelOpInfo
1600                 //
1601                 DbExpression inputExpr = this.VisitNode(n.Child0);
1602                 inputInfo = ConsumeRelOp(inputExpr);
1603
1604                 //
1605                 // Create the DbLimitExpression using the converted form of the input Node's Child2 Node (the Limit Node)
1606                 // together with the input DbExpression created above.
1607                 //
1608                 retExpr = this.CreateLimitExpression(inputExpr, this.VisitNode(n.Child2), op.WithTies);
1609                 alias = _limitAliases.Next();
1610             }
1611             else
1612             {
1613                 //
1614                 // Bring the Input into scope and visit the SortKeys to produce the equivalent SortClauses,
1615                 // then remove the Input's Vars from scope.
1616                 //
1617                 inputInfo = EnterExpressionBindingScope(n.Child0);
1618                 List<DbSortClause> sortOrder = VisitSortKeys(op.Keys);
1619                 ExitExpressionBindingScope(inputInfo);
1620
1621                 //
1622                 // SortKeys are present, so one of the following cases must be true:
1623                 // - Child1 (Skip Count) is non-NullOp, Child2 (Limit) is non-NullOp    => Limit(Skip(input))
1624                 // - Child1 (Skip Count) is non-NullOp, Child2 (Limit) is NullOp        => Skip(input)
1625                 // - Child1 (Skip Count) is NullOp,     Child2 (Limit) is non-NullOp    => Limit(Sort(input))
1626                 //
1627                 if (!nullSkip && !nullLimit)
1628                 {
1629                     // Limit(Skip(input))
1630                     retExpr =
1631                         this.CreateLimitExpression(
1632                             inputInfo.CreateBinding().Skip(sortOrder, VisitChild(n, 1)),
1633                             VisitChild(n, 2),
1634                             op.WithTies
1635                         );
1636                     alias = _limitAliases.Next();
1637                 }
1638                 else if (!nullSkip && nullLimit)
1639                 {
1640                     // Skip(input)
1641                     retExpr = inputInfo.CreateBinding().Skip(sortOrder, VisitChild(n, 1));
1642                     alias = _skipAliases.Next();
1643                 }
1644                 else if (nullSkip && !nullLimit)
1645                 {
1646                     // Limit(Sort(input))
1647                     retExpr =
1648                         this.CreateLimitExpression(
1649                             inputInfo.CreateBinding().Sort(sortOrder), 
1650                             VisitChild(n, 2),
1651                             op.WithTies
1652                         );
1653                     alias = _limitAliases.Next();
1654                 }
1655             }
1656
1657             //
1658             // Update the tracked RelOpInfo for the new expression. This consists of:
1659             // PublisherName: The next Skip or Limit alias depending on which expression is topmost.
1660             // PublishedVars: The PublishedVars of the Skip/Limit are the same as its Input.
1661             //
1662             PublishRelOp(alias, retExpr, inputInfo.PublishedVars);
1663             return retExpr;
1664         }
1665
1666         public override DbExpression Visit(GroupByOp op, Node n)
1667         {
1668             //
1669             // Track the Vars that are logically published by this GroupBy. These will be
1670             //
1671             VarInfoList publishedVars = new VarInfoList();
1672
1673             //
1674             // Visit the Input, publish its Vars and bring them into scope under a new binding name
1675             //
1676             GroupByScope inputInfo = EnterGroupByScope(n.Child0);
1677
1678             //
1679             // With the Input in scope, visit the VarDefs for the Keys and build the Var to DbExpression map for them
1680             //
1681             EnterVarDefListScope(n.Child1);
1682
1683             //
1684             // With the mappings for the Key Vars in scope, build the Name/DbExpression key column pairs by
1685             // generating a new column alias (prefixed with 'K') and resolving the Var, for each Var in the Keys Var list.
1686             // The list of output Vars that represent aggregates is also built here, by starting with a list
1687             // of all output Vars and removing each Key Var as it is processed.
1688             //
1689             AliasGenerator keyAliases = new AliasGenerator("K");
1690             List<KeyValuePair<string, DbExpression>> keyExprs = new List<KeyValuePair<string, DbExpression>>();
1691             List<Var> outputAggVars = new List<Var>(op.Outputs);
1692             foreach (Var keyVar in op.Keys)
1693             {
1694                 //
1695                 // Generate the alias and resolve the Key Var. This will find and retrieve the DbExpression to which
1696                 // the Key Var maps, which is most likely the VarDef scope that was just entered by visiting the Key VarDefListOp Node.
1697                 // Track the Name/DbExpression pairs for use later in CreateGroupByExpression.
1698                 //
1699                 string keyColName = keyAliases.Next();
1700                 keyExprs.Add(new KeyValuePair<string, DbExpression>(keyColName, ResolveVar(keyVar)));
1701
1702                 //
1703                 // Create a new VarInfo to track this key Var. To begin with it is reachable through
1704                 // a property reference of the column under which it is bound, i.e. using the column alias
1705                 // generated above, so the VarInfo property path is set up to contain just that name
1706                 // (the VarInfo has no binding name until later in this method when PublishRelOp is called).
1707                 //
1708                 VarInfo keyColInfo = new VarInfo(keyVar);
1709                 keyColInfo.PrependProperty(keyColName);
1710                 publishedVars.Add(keyColInfo);
1711
1712                 //
1713                 // Remove the Key Var from the list of Aggregate Outputs
1714                 //
1715                 outputAggVars.Remove(keyVar);
1716             }
1717
1718             //
1719             // After this point, no Vars in the output Vars list of the GroupBy may be defined by the
1720             // VarDefOps from the Keys VarDefListOp Node, so the Keys VarDefScope should be removed from the scope stack.
1721             //
1722             ExitVarDefScope();
1723
1724             //
1725             // The Vars published by the Input are currently in scope under the binding name that was generated for the Input (Extent0, Filter3, etc).
1726             // This is correct while the Keys are processed, however it is not correct for the aggregates. While the aggregates have access to exactly
1727             // the same Vars, they must be bound under a different name, which will become the GroupVarName used later in this method when a DbGroupExpressionBinding
1728             // is constructed. The GroupVarName is generated simply by appending 'Group' to the (already unique) binding name that was generated for the Input (to yield Extent0Group, Filter3Group, etc).
1729
1730             // In aggregate arguments, the GroupBy input's Vars must be accessed using the Group variable
1731             inputInfo.SwitchToGroupReference();
1732
1733             // Build the map of Var to Aggregate. The Aggregates VarDefListOp Node child of the GroupByOp's Node is
1734             // processed here to build the map. This is the only location in an IQT Command where an AggregateOp is valid.
1735             Dictionary<Var, DbAggregate> aggMap = new Dictionary<Var,DbAggregate>();
1736             Node aggRootNode = n.Child2;
1737             PlanCompiler.Assert(aggRootNode.Op is VarDefListOp, "Invalid Aggregates VarDefListOp Node encountered in GroupByOp");
1738             foreach (Node aggVarDefNode in aggRootNode.Children)
1739             {
1740                 VarDefOp aggVarDef = aggVarDefNode.Op as VarDefOp;
1741                 PlanCompiler.Assert(aggVarDef != null, "Non-VarDefOp Node encountered as child of Aggregates VarDefListOp Node");
1742
1743                 Var aggVar = aggVarDef.Var;
1744                 PlanCompiler.Assert(aggVar is ComputedVar, "Non-ComputedVar encountered in Aggregate VarDefOp");
1745
1746                 Node aggOpNode = aggVarDefNode.Child0;
1747                 DbExpression aggDef = VisitNode(aggOpNode.Child0);
1748                 AggregateOp funcAggOp = aggOpNode.Op as AggregateOp;
1749                 PlanCompiler.Assert(funcAggOp != null, "Non-Aggregate Node encountered as child of Aggregate VarDefOp Node");
1750                 DbFunctionAggregate newFuncAgg;
1751                 if (funcAggOp.IsDistinctAggregate)
1752                 {
1753                     newFuncAgg = funcAggOp.AggFunc.AggregateDistinct(aggDef);
1754                 }
1755                 else
1756                 {
1757                     newFuncAgg = funcAggOp.AggFunc.Aggregate(aggDef);
1758                 }
1759
1760                 PlanCompiler.Assert(outputAggVars.Contains(aggVar), "Defined aggregate Var not in Output Aggregate Vars list?");
1761
1762                 aggMap.Add(aggVar, newFuncAgg);
1763
1764             }
1765
1766             //
1767             // The Vars published by the Input should no longer be considered in scope, so call ExitExpressionBindingScope to pop them off the scope stack.
1768             //
1769             ExitGroupByScope(inputInfo);
1770
1771             //
1772             // Process the list of Aggregate Vars using the Var to Aggregate map created in the code above.
1773             // Note that since there is no dedicated Aggregates VarSet on the GroupByOp, it is necessary to
1774             // process the Vars in the OutputVars set, but beginning with the Var that immediately follows
1775             // the last Key Var.
1776             // Each Var is mapped to a previously created Aggregate using the Var to Aggregate map. The end
1777             // result is a list of name CQT Aggregates that can be used in the call to CreateGroupByExpression.
1778             //
1779             AliasGenerator aggAliases = new AliasGenerator("A");
1780             List<KeyValuePair<string, DbAggregate>> aggregates = new List<KeyValuePair<string, DbAggregate>>();
1781             foreach(Var aggVar in outputAggVars)
1782             {
1783                 // Generate a new column name for the Aggregate that will be prefixed with 'A'.
1784                 string aggColName = aggAliases.Next();
1785
1786                 // Map the Var to an Aggregate and add it to the list under the newly generated column name
1787                 aggregates.Add(new KeyValuePair<string, DbAggregate>(aggColName, aggMap[aggVar]));
1788
1789                 // Create a new VarInfo that will track the Aggregate Var up the CQT. Its property path is
1790                 // initialized to the newly generated column name to indicate that the Var must be reached
1791                 // with a DbPropertyExpression of the column name.
1792                 VarInfo aggColInfo = new VarInfo(aggVar);
1793                 aggColInfo.PrependProperty(aggColName);
1794
1795                 // Add the Aggregate VarInfo to the list of VarInfos that are tracking the Vars that are
1796                 // logically published by the DbGroupByExpression that will result from this method.
1797                 publishedVars.Add(aggColInfo);
1798             }
1799
1800             //
1801             // Create the DbGroupByExpression. The binding name of the input is used together with the
1802             // generated group name and the input DbExpression to create a DbGroupExpressionBinding.
1803             // The list of named Keys and Aggregates built above are specified in the call to CreateGroupExpressionBinding.
1804             //
1805             DbExpression retExpr = inputInfo.Binding.GroupBy(keyExprs, aggregates);
1806
1807             PublishRelOp(_groupByAliases.Next(), retExpr, publishedVars);
1808
1809             return retExpr;
1810         }
1811
1812         public override DbExpression Visit(GroupByIntoOp op, Node n)
1813         {
1814             // We should never see this Op
1815             throw EntityUtil.NotSupported();
1816         }
1817
1818         #region JoinOp Conversions - CrossJoinOp, InnerJoinOp, FullOuterJoinOp, LeftOuterJoinOp
1819         /// <summary>
1820         /// Massages the input to a join node.
1821         /// 
1822         /// If the input is a Filter(ScanTable), we throw in a dummy project over
1823         /// this input. This projectOp simply looks at the "referenced" columns of
1824         /// the table, and uses those as the projection Vars
1825         /// Otherwise, sqlgen does not really know which columns are referenced, and
1826         /// ends up adding a projection with all columns of the table.
1827         /// 
1828         /// NOTE: We may want to do this for Apply as well
1829         /// </summary>
1830         /// <param name="joinInputNode">one of the inputs to the join node</param>
1831         /// <returns>RelopInfo for the transformed input</returns>
1832         private RelOpInfo VisitJoinInput(Node joinInputNode)
1833         {
1834             RelOpInfo relOpInfo;
1835
1836             if (joinInputNode.Op.OpType == OpType.Filter && joinInputNode.Child0.Op.OpType == OpType.ScanTable)
1837             {
1838                 ScanTableOp scanTableOp = (ScanTableOp)joinInputNode.Child0.Op;
1839                 //
1840                 // #479385: Handle "empty" projection lists
1841                 //
1842                 if (scanTableOp.Table.ReferencedColumns.IsEmpty)
1843                 {
1844                     relOpInfo = BuildEmptyProjection(joinInputNode);
1845                 }
1846                 else
1847                 {
1848                     relOpInfo = BuildProjection(joinInputNode, scanTableOp.Table.ReferencedColumns);
1849                 }
1850             }
1851             else
1852             {
1853                 relOpInfo = EnterExpressionBindingScope(joinInputNode, false);
1854             }
1855
1856             return relOpInfo;
1857         }
1858
1859         /// <summary>
1860         /// Called by all Visitor pattern method that handle binary JoinOps (Inner, FullOuter, LeftOuter)
1861         /// </summary>
1862         /// <param name="joinNode">The IQT Node that references the JoinOp</param>
1863         /// <param name="joinKind">The CQT DbExpressionKind that represents the type of join to create</param>
1864         /// <returns></returns>
1865         private DbExpression VisitBinaryJoin(Node joinNode, DbExpressionKind joinKind)
1866         {
1867             //
1868             // Visit and retrieve RelOpInfo for the left Input, but do not bring its published Vars
1869             // into scope. Passing the value false as the 'pushScope' argument indicates that
1870             // EnterExpressionBindingScope should visit the specified Node, retrieve (and remove)
1871             // its RelOpInfo from the DbExpression to RelOpInfo map, but not push that RelOpInfo onto
1872             // the scope stack.
1873             // The Vars are not brought into scope in order to prevent Left-correlation - the Vars of
1874             // the left Input should not be visible to the right Input of the same join.
1875             //
1876             RelOpInfo leftInfo = VisitJoinInput(joinNode.Child0);
1877             
1878             // Do the same for the right Input to the join.
1879             RelOpInfo rightInfo = VisitJoinInput(joinNode.Child1);
1880
1881             bool scopesPushed = false;
1882             DbExpression joinCond = null;
1883             if (joinNode.Children.Count > 2)
1884             {
1885                 // If a Join condition Node is present, bring the Vars from the left and right arguments into scope
1886                 // and visit the Join condition Node's Op to convert the join condition. The scopesPushed flag is updated
1887                 // to true to indicate that the Var scopes should be removed from the scope stack when this method completes.
1888                 scopesPushed = true;
1889
1890                 PushExpressionBindingScope(leftInfo);
1891                 PushExpressionBindingScope(rightInfo);
1892
1893                 joinCond = VisitNode(joinNode.Child2);
1894             }
1895             else
1896             {
1897                 // There is no join condition, so the default condition - DbConstantExpression(True) - is used.
1898                 // The Vars from the left and right Inputs to the join need not be brought into scope, so the scopesPushed flag is not updated.
1899                 joinCond = DbExpressionBuilder.True;
1900             }
1901
1902             // Create a new DbJoinExpression using bindings created by the RelOpInfos of the left and right Inputs,
1903             // the specified Join type, and the converted or default Join condition DbExpression.
1904             DbExpression retExpr = DbExpressionBuilder.CreateJoinExpressionByKind(
1905                 joinKind,
1906                 joinCond,
1907                 leftInfo.CreateBinding(),
1908                 rightInfo.CreateBinding()
1909             );
1910
1911             // Create a new VarInfoList to hold the output Vars that are logically published by the new DbJoinExpression
1912             VarInfoList outputVars = new VarInfoList();
1913
1914             //
1915             // Remove the right argument from scope. If the scopesPushed flag is true then the RelOpInfo
1916             // will be popped from the scope stack.
1917             //
1918             ExitExpressionBindingScope(rightInfo, scopesPushed);
1919
1920             // In the record type that results from the join, the Vars published by the left argument
1921             // must now be accessed using an additional DbPropertyExpression that specifies the column name
1922             // used in the join (which was also the binding name used in the DbExpressionBinding created as part of the join)
1923             // PrependProperty is called on the published Vars of the right argument to reflect this, then they
1924             // are added to the overall set of Vars that are logically published by the new DbJoinExpression.
1925             // Note that calling ExitExpressionBindingScope has already unbound these Vars, making them
1926             // ready for use by the consumer of the new DbJoinExpression.
1927             rightInfo.PublishedVars.PrependProperty(rightInfo.PublisherName);
1928             outputVars.AddRange(rightInfo.PublishedVars);
1929
1930             // Repeat the above steps for the left argument to the join
1931             ExitExpressionBindingScope(leftInfo, scopesPushed);
1932             leftInfo.PublishedVars.PrependProperty(leftInfo.PublisherName);
1933             outputVars.AddRange(leftInfo.PublishedVars);
1934
1935             //
1936             // Update the tracked RelOpInfo for the new DbJoinExpression. This consists of:
1937             // PublisherName: The next Join alias.
1938             // PublishedVars: The PublishedVars of the Join are the (now unbound) PublishedVars of both Inputs, with appropriate column names prepended to their property paths.
1939             //
1940             PublishRelOp(_joinAliases.Next(), retExpr, outputVars);
1941
1942             return retExpr;
1943         }
1944
1945         public override DbExpression Visit(CrossJoinOp op, Node n)
1946         {
1947             // Create a new list of DbExpressionBinding to track the bindings that will be used in the new DbJoinExpression
1948             List<DbExpressionBinding> inputBindings = new List<DbExpressionBinding>();
1949
1950             // Create a new VarInfoList to track the Vars that will be logically published by the new DbJoinExpression
1951             VarInfoList outputVars = new VarInfoList();
1952
1953             //
1954             // For each Input Node:
1955             // 1. Visit and retrieve RelOpInfo for the Node, but do not bring it's Vars into scope
1956             //      (again to avoid Left-correlation between join Inputs).
1957             // 2. Use the RelOpInfo to create a correct Expressionbinding and add it to the list of ExpressionBindings
1958             // 3. Call ExitExpressionBinding, indicating that the RelOpInfo was not originally pushed onto the scope stack
1959             //      and so its published Vars should simply be unbound and the attempt should not be made to pop it from the scope stack.
1960             // 4. Update the property path for the Vars published by the Input to start with the same column name as was just used in the DbExpressionBinding for the Input
1961             // 5. Add the Vars published by the Input to the overall set of Vars that will be logically published by the new DbJoinExpression (created below).
1962             //
1963             foreach (Node inputNode in n.Children)
1964             {
1965                 RelOpInfo inputInfo = VisitJoinInput(inputNode);
1966                 inputBindings.Add(inputInfo.CreateBinding());
1967                 ExitExpressionBindingScope(inputInfo, false);
1968                 inputInfo.PublishedVars.PrependProperty(inputInfo.PublisherName);
1969                 outputVars.AddRange(inputInfo.PublishedVars);
1970             }
1971
1972             // Create a new DbJoinExpression from the list of DbExpressionBinding (implicitly creating a CrossJoin)
1973             DbExpression retExpr = DbExpressionBuilder.CrossJoin(inputBindings);
1974
1975             // Update the DbExpression to RelOpInfo map to indicate that the overall set of Vars collected above are logically published by the new DbJoinExpression
1976             // PublisherName will be the next Join alias.
1977             PublishRelOp(_joinAliases.Next(), retExpr, outputVars);
1978
1979             // Return the new DbJoinExpression
1980             return retExpr;
1981         }
1982
1983         public override DbExpression Visit(InnerJoinOp op, Node n)
1984         {
1985             // Use common handling for binary Join Ops
1986             return VisitBinaryJoin(n, DbExpressionKind.InnerJoin);
1987         }
1988
1989         public override DbExpression Visit(LeftOuterJoinOp op, Node n)
1990         {
1991             // Use common handling for binary Join Ops
1992             return VisitBinaryJoin(n, DbExpressionKind.LeftOuterJoin);
1993         }
1994
1995         public override DbExpression Visit(FullOuterJoinOp op, Node n)
1996         {
1997             // Use common handling for binary Join Ops
1998             return VisitBinaryJoin(n, DbExpressionKind.FullOuterJoin);
1999         }
2000
2001         #endregion
2002
2003         #region ApplyOp Conversions - CrossApplyOp, OuterApplyOp
2004
2005         /// <summary>
2006         /// Called by both CrossApply and OuterApply visitor pattern methods - command handling of both types of Apply operation
2007         /// </summary>
2008         /// <param name="applyNode">The Node that references the ApplyOp</param>
2009         /// <param name="applyKind">The CQT DbExpressionKind that corresponds to the ApplyOp (DbExpressionKind.CrossApply for CrossApplyOp, DbExpressionKind.OuterApply for OuterApplyOp)</param>
2010         /// <returns>A new CqtResult containing a DbApplyExpression with the correct ApplyType</returns>
2011         private DbExpression VisitApply(Node applyNode, DbExpressionKind applyKind)
2012         {            
2013             //
2014             // Visit the Input and bring its Vars into scope for the Apply
2015             //
2016             RelOpInfo inputInfo = EnterExpressionBindingScope(applyNode.Child0);
2017
2018             //
2019             // Visit the Apply - there is no need to bring its Vars into scope
2020             //
2021             RelOpInfo applyInfo = EnterExpressionBindingScope(applyNode.Child1, false);
2022
2023             DbExpression retExpr = DbExpressionBuilder.CreateApplyExpressionByKind(
2024                 applyKind,
2025                 inputInfo.CreateBinding(),
2026                 applyInfo.CreateBinding());
2027
2028             //
2029             // Unbind the Apply Vars by calling ExitExpressionBindingScope and indicating that the specified scope was not pushed onto the scope stack.
2030             //
2031             ExitExpressionBindingScope(applyInfo, false);
2032
2033             //
2034             // Remove the Input Vars from scope and unbind them
2035             //
2036             ExitExpressionBindingScope(inputInfo);
2037
2038             //
2039             // Update the property path to the Input and Apply vars appropriately based on the names used in their ExpressionBindings, which will then form the column names in the record output type of the AppyExpression
2040             //
2041             inputInfo.PublishedVars.PrependProperty(inputInfo.PublisherName);
2042             applyInfo.PublishedVars.PrependProperty(applyInfo.PublisherName);
2043
2044             //
2045             // Build and publish the set of IQT Vars logically published by the DbApplyExpression
2046             // PublisherName: The next Apply alias.
2047             // PublishedVars: The PublishedVars of the Apply consists of the Vars published by the input plus those published by the apply.
2048             //
2049             VarInfoList outputVars = new VarInfoList();
2050             outputVars.AddRange(inputInfo.PublishedVars);
2051             outputVars.AddRange(applyInfo.PublishedVars);
2052
2053             PublishRelOp(_applyAliases.Next(), retExpr, outputVars);
2054
2055             return retExpr;
2056         }
2057
2058         public override DbExpression Visit(CrossApplyOp op, Node n)
2059         {
2060             // Use common handling for Apply Ops
2061             return VisitApply(n, DbExpressionKind.CrossApply);
2062         }
2063
2064         public override DbExpression Visit(OuterApplyOp op, Node n)
2065         {
2066             // Use common handling for Apply Ops
2067             return VisitApply(n, DbExpressionKind.OuterApply);
2068         }
2069         #endregion
2070
2071         #region SetOp Conversions - ExceptOp, IntersectOp, UnionAllOp
2072
2073         /// <summary>
2074         /// Called by VisitSetOp to convert each argument.
2075         /// Determines whether a column-reordering projection should be applied to
2076         /// the argument, and applies that projection if necessary during conversion
2077         /// to a DbExpression. A different projection is applied if no Nodes higher in
2078         /// the IQT consume the vars produced by the SetOp argument.
2079         /// </summary>
2080         /// <param name="argNode">
2081         /// A Node that provides one of the arguments to the SetOp
2082         /// </param>
2083         /// <param name="outputVars">
2084         /// Defines the expected order of the Output Vars of the SetOp
2085         /// </param>
2086         /// <param name="argVars">
2087         /// The VarMap for the SetOp argument represented by the node.
2088         /// This specifies the Output (SetOp-produced) Var to Input (Argument-produced)
2089         /// Var mappings for the Vars in the outputVars enumerable.
2090         /// </param>
2091         /// <returns>
2092         /// A DbExpression that is the converted form of the argument
2093         /// (with an appropriate column-reording projection applied if necessary)
2094         /// </returns>
2095         private DbExpression VisitSetOpArgument(Node argNode, VarVec outputVars, VarMap argVars)
2096         {
2097             RelOpInfo sourceInfo;
2098
2099             List<Var> projectionVars = new List<Var>();
2100
2101             //
2102             // If the list of output vars is empty, no higher Nodes required the vars produced by
2103             // this SetOp argument. A projection must therefore be applied that performs the equivalent
2104             // of 'SELECT true FROM <SetOp Argument>'.
2105             //
2106             if (outputVars.IsEmpty)
2107             {
2108                 sourceInfo = BuildEmptyProjection(argNode);
2109             }
2110             else
2111             {
2112                 //
2113                 // Build up the list of Vars that we want as the output for this argument.
2114                 // The "outputVars" argument defines the order in which we need the outputs
2115                 // 
2116                 foreach (Var v in outputVars)
2117                 {
2118                     projectionVars.Add(argVars[v]);
2119                 }
2120
2121                 //
2122                 // Build up a ProjectOp over the input that produces the required Output vars
2123                 //
2124                 sourceInfo = BuildProjection(argNode, projectionVars);
2125             }
2126
2127             return sourceInfo.Publisher;
2128         }
2129
2130         /// <summary>
2131         /// Called by UnionAll, Intersect and Except (SetOp) visitor pattern methods
2132         /// </summary>
2133         /// <param name="op">The visited SetOp</param>
2134         /// <param name="n">The Node that references the SetOp</param>
2135         /// <param name="alias">Alias to use when publishing the SetOp's Vars</param>
2136         /// <param name="setOpBuilder">Callback to construct the SetOp DbExpression from the left and right arguments</param>
2137         /// <returns>The DbExpression equivalent of the SetOp</returns>
2138         private DbExpression VisitSetOp(SetOp op, Node n, AliasGenerator alias, Func<DbExpression, DbExpression, DbExpression> setOpExpressionBuilder)
2139         {
2140             //
2141             // To be convertible to a CQT Except/Intersect/DbUnionAllExpression, the SetOp must have exactly 2 arguments.
2142             //
2143             AssertBinary(n);
2144
2145             //
2146             // Convert the left and right arguments to expressions.
2147             //
2148             DbExpression left = VisitSetOpArgument(n.Child0, op.Outputs, op.VarMap[0]);
2149             DbExpression right = VisitSetOpArgument(n.Child1, op.Outputs, op.VarMap[1]);
2150
2151             //
2152             // If the output of the SetOp is a collection of records then the Vars produced
2153             // by the SetOp must be prepended with the names of the record type's columns as
2154             // they are tracked up the tree by VarInfo instances.
2155             //
2156             CollectionType outputType = TypeHelpers.GetEdmType<CollectionType>(TypeHelpers.GetCommonTypeUsage(left.ResultType, right.ResultType));
2157             IEnumerator<EdmProperty> properties = null;
2158             RowType outputElementType = null;
2159             if (TypeHelpers.TryGetEdmType<RowType>(outputType.TypeUsage, out outputElementType))
2160             {
2161                 properties = outputElementType.Properties.GetEnumerator();
2162             }
2163             
2164             //
2165             // The published Vars of the DbExpression produced from the SetOp must be its Output Vars.
2166             // These Output Vars are mapped to the Vars of each of the SetOp's arguments using an array
2167             // of VarMaps (one for each argument) on the SetOp.
2168             // A VarInfo instance is added to the published Vars list for each Output Var of the SetOp.
2169             // If the output type of the SetOp is a collection of a record type then each Var's PropertyPath
2170             // is updated to be the name of the corresponding record column.
2171             //
2172             VarInfoList publishedVars = new VarInfoList();
2173             foreach (Var outputVar in op.Outputs)
2174             {
2175                 VarInfo newVarInfo = new VarInfo(outputVar);
2176                 // Prepend a property name to this var, if the output is a record type
2177                 if (outputElementType != null)
2178                 {
2179                     if (!properties.MoveNext())
2180                     {
2181                         PlanCompiler.Assert(false, "Record columns don't match output vars");
2182                     }
2183                     newVarInfo.PrependProperty(properties.Current.Name);
2184                 }
2185                 publishedVars.Add(newVarInfo);
2186             }
2187
2188             DbExpression retExpr = setOpExpressionBuilder(left, right);
2189             PublishRelOp(alias.Next(), retExpr, publishedVars);
2190
2191             return retExpr;
2192         }
2193
2194         public override DbExpression Visit(UnionAllOp op, Node n)
2195         {
2196             return VisitSetOp(op, n, _unionAllAliases, DbExpressionBuilder.UnionAll);
2197         }
2198
2199         public override DbExpression Visit(IntersectOp op, Node n)
2200         {
2201             return VisitSetOp(op, n, _intersectAliases, DbExpressionBuilder.Intersect);
2202         }
2203
2204         public override DbExpression Visit(ExceptOp op, Node n)
2205         {
2206             return VisitSetOp(op, n, _exceptAliases, DbExpressionBuilder.Except);
2207         }
2208         #endregion
2209
2210         public override DbExpression Visit(DerefOp op, Node n)
2211         {
2212             throw EntityUtil.NotSupported();
2213         }
2214
2215         public override DbExpression Visit(DistinctOp op, Node n)
2216         {
2217             //
2218             // Build a projection above the input that gets the "keys" of the 
2219             // DistinctOp.
2220             //
2221             RelOpInfo sourceInfo = BuildProjection(n.Child0, op.Keys);
2222
2223             //
2224             // Build the Distinct expression now
2225             //
2226             DbExpression distinctExpr = sourceInfo.Publisher.Distinct();
2227
2228             //
2229             // Publish the DbDistinctExpression's Vars:
2230             // PublisherName: The next Distinct alias
2231             // PublishedVars: The PublishedVars of the Distinct are the same (rebound) Vars published by its input
2232             //
2233             PublishRelOp(_distinctAliases.Next(), distinctExpr, sourceInfo.PublishedVars);
2234             
2235             return distinctExpr;
2236         }
2237
2238         /// <summary>
2239         /// Convert SRO(e) => NewMultiset(Element(e'))
2240         ///   where e' is the CTree version of e
2241         /// Add a Project over e, if it does not already have a ProjectOp
2242         /// </summary>
2243         /// <param name="op"></param>
2244         /// <param name="n"></param>
2245         /// <returns></returns>
2246         public override DbExpression Visit(SingleRowOp op, Node n)
2247         {
2248             RelOpInfo inputInfo;
2249             DbExpression inputExpr;
2250
2251             //
2252             // Build a Projection over the child - sqlgen gets very confused otherwise
2253             //
2254             if (n.Child0.Op.OpType != OpType.Project)
2255             {
2256                 ExtendedNodeInfo childNodeInfo = _iqtCommand.GetExtendedNodeInfo(n.Child0);
2257                 //
2258                 // #484757: Handle "empty" projection lists due to projection pruning
2259                 //
2260                 if (childNodeInfo.Definitions.IsEmpty)
2261                 {
2262                     inputInfo = BuildEmptyProjection(n.Child0);
2263                 }
2264                 else
2265                 {
2266                     inputInfo = BuildProjection(n.Child0, childNodeInfo.Definitions);
2267                 }
2268                 inputExpr = inputInfo.Publisher;
2269             }
2270             else
2271             {
2272                 inputExpr = VisitNode(n.Child0);
2273                 AssertRelOp(inputExpr);
2274                 inputInfo = ConsumeRelOp(inputExpr);
2275             }
2276
2277             DbElementExpression elementExpr = inputExpr.Element();
2278             List<DbExpression> collectionElements = new List<DbExpression>();
2279             collectionElements.Add(elementExpr);
2280             DbNewInstanceExpression collectionExpr = DbExpressionBuilder.NewCollection(collectionElements);
2281             PublishRelOp(_elementAliases.Next(), collectionExpr, inputInfo.PublishedVars);
2282
2283             return collectionExpr;
2284         }
2285
2286         /// <summary>
2287         /// Convert SingleRowTableOp into NewMultisetOp(1) - a single element
2288         /// collection. The element type of the collection doesn't really matter
2289         /// </summary>
2290         /// <param name="op">SingleRowTableOp</param>
2291         /// <param name="n">current subtree</param>
2292         /// <returns>CQT expression</returns>
2293         public override DbExpression Visit(SingleRowTableOp op, Node n)
2294         {
2295             DbNewInstanceExpression collectionExpr = DbExpressionBuilder.NewCollection(new [] { DbExpressionBuilder.Constant(1) });
2296             PublishRelOp(_singleRowTableAliases.Next(), collectionExpr, new VarInfoList());
2297             return collectionExpr;
2298         }
2299
2300         #endregion
2301
2302         #region Variable Definition Ops
2303         public override DbExpression Visit(VarDefOp op, Node n)
2304         {
2305             //
2306             // VarDef and VarDefList are handled in the conversion of the Ops in which they are valid (by calls to EnterVarDefScope/EnterVarDefListScope).
2307             // If this method is called a VarDefOp exists in an invalid location in the IQT
2308             //
2309             PlanCompiler.Assert(false, "Unexpected VarDefOp");
2310             throw EntityUtil.NotSupported(System.Data.Entity.Strings.Iqt_CTGen_UnexpectedVarDef);
2311         }
2312
2313         public override DbExpression Visit(VarDefListOp op, Node n)
2314         {
2315             //
2316             // VarDef and VarDefList are handled in the conversion of the Ops in which they are valid (by calls to EnterVarDefScope/EnterVarDefListScope).
2317             // If this method is called a VarDefListOp exists in an invalid location in the IQT
2318             //
2319             PlanCompiler.Assert(false, "Unexpected VarDefListOp");
2320             throw EntityUtil.NotSupported(System.Data.Entity.Strings.Iqt_CTGen_UnexpectedVarDefList);
2321         }
2322         #endregion
2323
2324         #region PhysicalOps
2325         /// <summary>
2326         /// Translates the PhysicalProjectOp. Handles two cases. If the child is a ProjectOp,
2327         /// then we simply piggyback on the ProjectOp method, but with our list of Vars.
2328         ///
2329         /// Otherwise, we visit the child, and then create a DbProjectExpression above it.
2330         ///
2331         /// The reason we special case the first scenario is because we do not want to add
2332         /// an extra Project over a Project-over-Sort expression tree. This causes bad
2333         /// problems later down the line
2334         /// </summary>
2335         /// <param name="op">the PhysicalProjectOp</param>
2336         /// <param name="n">current subtree</param>
2337         /// <returns>the CQT expression corresponding to this subtree</returns>
2338         public override DbExpression Visit(PhysicalProjectOp op, Node n)
2339         {
2340             PlanCompiler.Assert(n.Children.Count == 1, "more than one input to physicalProjectOp?");
2341
2342             //
2343             // Prune the output vars from the PhysicalProjectOp
2344             //
2345             VarList prunedOutputs = new VarList();
2346             foreach (Var v in op.Outputs)
2347             {
2348                 if (!prunedOutputs.Contains(v))
2349                 {
2350                     prunedOutputs.Add(v);
2351                 }
2352             }
2353             op.Outputs.Clear();
2354             op.Outputs.AddRange(prunedOutputs);
2355
2356             //
2357             // Build a Projection over the input with exactly the Vars that we want
2358             // 
2359             RelOpInfo sourceInfo = BuildProjection(n.Child0, op.Outputs);
2360
2361             return sourceInfo.Publisher;
2362         }
2363
2364         public override DbExpression Visit(SingleStreamNestOp op, Node n)
2365         {
2366             throw EntityUtil.NotSupported();
2367         }
2368         public override DbExpression Visit(MultiStreamNestOp op, Node n)
2369         {
2370             throw EntityUtil.NotSupported();
2371         }
2372         #endregion
2373
2374         #endregion
2375     }
2376 }