1 //---------------------------------------------------------------------
2 // <copyright file="Command.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.Collections.Generic;
11 using System.Data.Common;
12 using System.Data.Metadata.Edm;
13 using System.Data.Query.PlanCompiler;
14 using System.Diagnostics;
15 using System.Linq;
16 
17 namespace System.Data.Query.InternalTrees
18 {
19     /// <summary>
20     /// The Command object encapsulates all information relating to a single command.
21     /// It includes the expression tree in question, as well as the parameters to the
22     /// command.
23     /// Additionally, the Command class serves as a factory for building up different
24     /// nodes and Ops. Every node in the tree has a unique id, and this is enforced by
25     /// the node factory methods
26     /// </summary>
27     internal class Command
28     {
29         #region private state
30         private Dictionary<string, ParameterVar> m_parameterMap;
31         private List<Var> m_vars;
32         private List<Table> m_tables;
33         private Node m_root;
34         private MetadataWorkspace m_metadataWorkspace;
35         private TypeUsage m_boolType;
36         private TypeUsage m_intType;
37         private TypeUsage m_stringType;
38         private ConstantPredicateOp m_trueOp;
39         private ConstantPredicateOp m_falseOp;
40         private NodeInfoVisitor m_nodeInfoVisitor;
41         private PlanCompiler.KeyPullup m_keyPullupVisitor;
42         private int m_nextNodeId;
43         private int m_nextBranchDiscriminatorValue = 1000;
44 
45         private bool m_disableVarVecEnumCaching;
46         private Stack<VarVec.VarVecEnumerator> m_freeVarVecEnumerators;
47         private Stack<VarVec> m_freeVarVecs;
48 
49 
50         // set of referenced rel properties in this query
51         private HashSet<RelProperty> m_referencedRelProperties;
52         #endregion
53 
54         #region constructors
55         /// <summary>
56         /// Creates a new command
57         /// </summary>
Command(MetadataWorkspace metadataWorkspace)58         internal Command(MetadataWorkspace metadataWorkspace)
59         {
60             m_parameterMap = new Dictionary<string, ParameterVar>();
61             m_vars = new List<Var>();
62             m_tables = new List<Table>();
63             m_metadataWorkspace = metadataWorkspace;
64             if(!TryGetPrimitiveType(PrimitiveTypeKind.Boolean, out m_boolType))
65             {
66                 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderBooleanType);
67             }
68             if (!TryGetPrimitiveType(PrimitiveTypeKind.Int32, out m_intType))
69             {
70                 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderIntegerType);
71             }
72             if (!TryGetPrimitiveType(PrimitiveTypeKind.String, out m_stringType))
73             {
74                 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderStringType);
75             }
76             m_trueOp = new ConstantPredicateOp(m_boolType, true);
77             m_falseOp = new ConstantPredicateOp(m_boolType, false);
78             m_nodeInfoVisitor = new NodeInfoVisitor(this);
79             m_keyPullupVisitor = new PlanCompiler.KeyPullup(this);
80 
81             // FreeLists
82             m_freeVarVecEnumerators = new Stack<VarVec.VarVecEnumerator>();
83             m_freeVarVecs = new Stack<VarVec>();
84 
85             m_referencedRelProperties = new HashSet<RelProperty>();
86         }
87         #endregion
88 
89         #region public methods
90         /// <summary>
91         /// Gets the metadata workspace associated with this command
92         /// </summary>
93         internal MetadataWorkspace MetadataWorkspace { get { return m_metadataWorkspace; } }
94 
95         /// <summary>
96         /// Gets/sets the root node of the query
97         /// </summary>
98         internal Node Root { get { return m_root; } set { m_root = value; } }
99 
DisableVarVecEnumCaching()100         internal void DisableVarVecEnumCaching() { m_disableVarVecEnumCaching = true; }
101 
102         /// <summary>
103         /// Returns the next value for a UnionAll BranchDiscriminator.
104         /// </summary>
105         internal int NextBranchDiscriminatorValue { get { return m_nextBranchDiscriminatorValue++; } }
106 
107         /// <summary>
108         /// Returns the next value for a node id, without incrementing it.
109         /// </summary>
110         internal int NextNodeId { get { return m_nextNodeId; } }
111 
112         #region Metadata Helpers
113         /// <summary>
114         /// Helper routine to get the metadata representation for the bool type
115         /// </summary>
116         internal TypeUsage BooleanType
117         {
118             get { return m_boolType; }
119         }
120 
121         /// <summary>
122         /// Helper routine to get the metadata representation of the int type
123         /// </summary>
124         internal TypeUsage IntegerType
125         {
126             get { return m_intType; }
127         }
128 
129         /// <summary>
130         /// Helper routine to get the metadata representation of the string type
131         /// </summary>
132         internal TypeUsage StringType
133         {
134             get { return m_stringType; }
135         }
136 
137         /// <summary>
138         /// Get the primitive type by primitive type kind
139         /// </summary>
140         /// <param name="modelType">EdmMetadata.PrimitiveTypeKind of the primitive type</param>
141         /// <param name="type">A TypeUsage that represents the specified primitive type</param>
142         /// <returns><c>True</c> if the specified primitive type could be retrieved; otherwise <c>false</c>.</returns>
TryGetPrimitiveType(PrimitiveTypeKind modelType, out TypeUsage type)143         private bool TryGetPrimitiveType(PrimitiveTypeKind modelType, out TypeUsage type)
144         {
145             type = null;
146 
147             if (modelType == PrimitiveTypeKind.String)
148             {
149                 type = TypeUsage.CreateStringTypeUsage(m_metadataWorkspace.GetModelPrimitiveType(modelType),
150                                                        false /*unicode*/,
151                                                        false /*fixed*/);
152             }
153             else
154             {
155                 type = m_metadataWorkspace.GetCanonicalModelTypeUsage(modelType);
156             }
157 
158             return (null != type);
159         }
160         #endregion
161 
162         #region VarVec Creation
163         /// <summary>
164         /// VarVec constructor
165         /// </summary>
166         /// <returns>A new, empty, VarVec</returns>
CreateVarVec()167         internal VarVec CreateVarVec()
168         {
169             VarVec vec;
170             if (m_freeVarVecs.Count == 0)
171             {
172                 vec = new VarVec(this);
173             }
174             else
175             {
176                 vec = m_freeVarVecs.Pop();
177                 vec.Clear();
178             }
179             return vec;
180         }
181 
182         /// <summary>
183         /// Create a VarVec with a single Var
184         /// </summary>
185         /// <param name="v"></param>
186         /// <returns></returns>
CreateVarVec(Var v)187         internal VarVec CreateVarVec(Var v)
188         {
189             VarVec varset = CreateVarVec();
190             varset.Set(v);
191             return varset;
192         }
193 
194         /// <summary>
195         /// Create a VarVec with the set of specified vars
196         /// </summary>
197         /// <param name="v"></param>
198         /// <returns></returns>
CreateVarVec(IEnumerable<Var> v)199         internal VarVec CreateVarVec(IEnumerable<Var> v)
200         {
201             VarVec vec = CreateVarVec();
202             vec.InitFrom(v);
203             return vec;
204         }
205 
206         /// <summary>
207         /// Create a new VarVec from the input VarVec
208         /// </summary>
209         /// <param name="v"></param>
210         /// <returns></returns>
CreateVarVec(VarVec v)211         internal VarVec CreateVarVec(VarVec v)
212         {
213             VarVec vec = CreateVarVec();
214             vec.InitFrom(v);
215             return vec;
216         }
217 
218         /// <summary>
219         /// Release a VarVec to the freelist
220         /// </summary>
221         /// <param name="vec"></param>
ReleaseVarVec(VarVec vec)222         internal void ReleaseVarVec(VarVec vec)
223         {
224             m_freeVarVecs.Push(vec);
225         }
226         #endregion
227 
228         #region VarVecEnumerator
229         /// <summary>
230         /// Create a new enumerator for a VarVec; use a free one if its
231         /// available; otherwise, create a new one
232         /// </summary>
233         /// <param name="vec"></param>
234         /// <returns></returns>
GetVarVecEnumerator(VarVec vec)235         internal VarVec.VarVecEnumerator GetVarVecEnumerator(VarVec vec)
236         {
237             VarVec.VarVecEnumerator enumerator;
238 
239             if (m_disableVarVecEnumCaching ||
240                 m_freeVarVecEnumerators.Count == 0)
241             {
242                 enumerator = new VarVec.VarVecEnumerator(vec);
243             }
244             else
245             {
246                 enumerator = m_freeVarVecEnumerators.Pop();
247                 enumerator.Init(vec);
248             }
249             return enumerator;
250         }
251 
252         /// <summary>
253         /// Release an enumerator; keep it in a local stack for future use
254         /// </summary>
255         /// <param name="enumerator"></param>
ReleaseVarVecEnumerator(VarVec.VarVecEnumerator enumerator)256         internal void ReleaseVarVecEnumerator(VarVec.VarVecEnumerator enumerator)
257         {
258             if (!m_disableVarVecEnumCaching)
259             {
260                 m_freeVarVecEnumerators.Push(enumerator);
261             }
262         }
263         #endregion
264 
265         #region VarList
266         /// <summary>
267         /// Create an ordered list of Vars - initially empty
268         /// </summary>
269         /// <returns></returns>
CreateVarList()270         internal static VarList CreateVarList()
271         {
272             return new VarList();
273         }
274 
275         /// <summary>
276         /// Create an ordered list of Vars
277         /// </summary>
278         /// <param name="vars"></param>
279         /// <returns></returns>
CreateVarList(IEnumerable<Var> vars)280         internal static VarList CreateVarList(IEnumerable<Var> vars)
281         {
282             return new VarList(vars);
283         }
284         #endregion
285 
286         #region VarMap
CreateVarMap()287         internal VarMap CreateVarMap()
288         {
289             return new VarMap();
290         }
291 
292         #endregion
293 
294         #region Table Helpers
295 
NewTableId()296         private int NewTableId()
297         {
298             return m_tables.Count;
299         }
300 
301 
302         /// <summary>
303         /// Create a table whose element type is "elementType"
304         /// </summary>
305         /// <param name="elementType">type of each element (row) of the table</param>
306         /// <returns>a table definition object</returns>
CreateTableDefinition(TypeUsage elementType)307         internal static TableMD CreateTableDefinition(TypeUsage elementType)
308         {
309             return new TableMD(elementType, null);
310         }
311 
312         /// <summary>
313         /// Creates a new table definition based on an extent. The element type
314         /// of the extent manifests as the single column of the table
315         /// </summary>
316         /// <param name="extent">the metadata extent</param>
317         /// <returns>A new TableMD instance based on the extent</returns>
CreateTableDefinition(EntitySetBase extent)318         internal static TableMD CreateTableDefinition(EntitySetBase extent)
319         {
320             return new TableMD(TypeUsage.Create(extent.ElementType), extent);
321         }
322 
323         /// <summary>
324         /// Create a "flat" table definition object (ie) the table has one column
325         /// for each property of the specified row type
326         /// </summary>
327         /// <param name="type">the shape of each row of the table</param>
328         /// <returns>the table definition</returns>
CreateFlatTableDefinition(RowType type)329         internal TableMD CreateFlatTableDefinition(RowType type)
330         {
331             return CreateFlatTableDefinition(type.Properties, new List<EdmMember>(), null);
332         }
333 
334         /// <summary>
335         /// Create a "flat" table defintion. The table has one column for each property
336         /// specified, and the key columns of the table are those specified in the
337         /// keyMembers parameter
338         /// </summary>
339         /// <param name="properties">list of columns for the table</param>
340         /// <param name="keyMembers">the key columns (if any)</param>
341         /// <param name="entitySet">(OPTIONAL) entityset corresponding to this table</param>
342         /// <returns></returns>
CreateFlatTableDefinition(IEnumerable<EdmProperty> properties, IEnumerable<EdmMember> keyMembers, EntitySetBase entitySet)343         internal TableMD CreateFlatTableDefinition(IEnumerable<EdmProperty> properties, IEnumerable<EdmMember> keyMembers, EntitySetBase entitySet)
344         {
345             return new TableMD(properties, keyMembers, entitySet);
346         }
347 
348         /// <summary>
349         /// Creates a new table instance
350         /// </summary>
351         /// <param name="tableMetadata">table metadata</param>
352         /// <returns>A new Table instance with columns as defined in the specified metadata</returns>
CreateTableInstance(TableMD tableMetadata)353         internal Table CreateTableInstance(TableMD tableMetadata)
354         {
355             Table t = new Table(this, tableMetadata, NewTableId());
356             m_tables.Add(t);
357             return t;
358         }
359 
360         #endregion
361 
362         #region Var Access
363 
364         /// <summary>
365         /// All vars in the query
366         /// </summary>
367         internal IEnumerable<Var> Vars
368         {
369             get { return m_vars.Where(v => v.VarType != VarType.NotValid); }
370         }
371 
372         /// <summary>
373         /// Access an existing variable in the query (by its id)
374         /// </summary>
375         /// <param name="id">The ID of the variable to retrieve</param>
376         /// <returns>The variable with the specified ID</returns>
GetVar(int id)377         internal Var GetVar(int id)
378         {
379             Debug.Assert(m_vars[id].VarType != VarType.NotValid, "The var has been replaced by a different var and is no longer valid.");
380 
381             return m_vars[id];
382         }
383 
384         /// <summary>
385         /// Gets the ParameterVar that corresponds to a given named parameter
386         /// </summary>
387         /// <param name="paramName">The name of the parameter for which to retrieve the ParameterVar</param>
388         /// <returns>The ParameterVar that corresponds to the specified parameter</returns>
GetParameter(string paramName)389         internal ParameterVar GetParameter(string paramName)
390         {
391             return m_parameterMap[paramName];
392         }
393 
394         #endregion
395 
396         #region Var Creation
397 
NewVarId()398         private int NewVarId()
399         {
400             return m_vars.Count;
401         }
402 
403         /// <summary>
404         /// Creates a variable for a parameter in the query
405         /// </summary>
406         /// <param name="parameterName">The name of the parameter for which to create the var</param>
407         /// <param name="parameterType">The type of the parameter, and therefore the new var</param>
408         /// <returns>A new ParameterVar instance with the specified name and type</returns>
CreateParameterVar(string parameterName, TypeUsage parameterType)409         internal ParameterVar CreateParameterVar(string parameterName,
410             TypeUsage parameterType)
411         {
412             if (m_parameterMap.ContainsKey(parameterName))
413                 throw new Exception("duplicate parameter name: " + parameterName);
414             ParameterVar v = new ParameterVar(NewVarId(), parameterType, parameterName);
415             m_vars.Add(v);
416             m_parameterMap[parameterName] = v;
417             return v;
418         }
419 
420         /// <summary>
421         /// Creates a variable for the given parameter variable and replaces it in parameter map.
422         /// </summary>
423         /// <param name="oldVar">Parameter variable that needs to replaced.</param>
424         /// <param name="generateReplacementType">Delegate that generates the replacement parameter's type.</param>
425         /// <returns>A new ParameterVar instance created of <paramref name="oldVar"/>.</returns>
426         /// <remarks>
427         /// This method should be used only to replace external enum or strong spatial parameters with a counterpart whose
428         /// type is the underlying type of the enum type, or the union type contating the strong spatial type of the <paramref name="oldVar"/>.
429         /// The operation invalidates the <paramref name="oldVar"/>. After the operation has completed
430         /// the <paramref name="oldVar"/>) is invalidated internally and should no longer be used.
431         /// </remarks>Func<
ReplaceParameterVar(ParameterVar oldVar, Func<TypeUsage, TypeUsage> generateReplacementType)432         private ParameterVar ReplaceParameterVar(ParameterVar oldVar, Func<TypeUsage, TypeUsage> generateReplacementType)
433         {
434             Debug.Assert(oldVar != null, "oldVar != null");
435             Debug.Assert(m_vars.Contains(oldVar));
436             ParameterVar v = new ParameterVar(NewVarId(), generateReplacementType(oldVar.Type), oldVar.ParameterName);
437             m_parameterMap[oldVar.ParameterName] = v;
438             m_vars.Add(v);
439             return v;
440         }
441 
442         /// <summary>
443         /// Creates a variable for the given enum parameter variable and replaces it in parameter map.
444         /// </summary>
445         /// <param name="oldVar">Enum parameter variable that needs to replaced.</param>
446         /// <returns>A new ParameterVar instance created of <paramref name="oldVar"/>.</returns>
447         /// <remarks>
448         /// This method should be used only to replace external enum parameter with a counterpart whose
449         /// type is the underlying type of the enum type of the <paramref name="oldVar"/>.
450         /// The operation invalidates the <paramref name="oldVar"/>. After the operation has completed
451         /// the <paramref name="oldVar"/>) is invalidated internally and should no longer be used.
452         /// </remarks>
ReplaceEnumParameterVar(ParameterVar oldVar)453         internal ParameterVar ReplaceEnumParameterVar(ParameterVar oldVar)
454         {
455             return ReplaceParameterVar(oldVar, t => TypeHelpers.CreateEnumUnderlyingTypeUsage(t));
456         }
457 
458         /// <summary>
459         /// Creates a variable for the given spatial parameter variable and replaces it in parameter map.
460         /// </summary>
461         /// <param name="oldVar">Spatial parameter variable that needs to replaced.</param>
462         /// <returns>A new ParameterVar instance created of <paramref name="oldVar"/>.</returns>
463         /// <remarks>
464         /// This method should be used only to replace external strong spatial parameter with a counterpart whose
465         /// type is the appropriate union type for <paramref name="oldVar"/>.
466         /// The operation invalidates the <paramref name="oldVar"/>. After the operation has completed
467         /// the <paramref name="oldVar"/>) is invalidated internally and should no longer be used.
468         /// </remarks>
ReplaceStrongSpatialParameterVar(ParameterVar oldVar)469         internal ParameterVar ReplaceStrongSpatialParameterVar(ParameterVar oldVar)
470         {
471             return ReplaceParameterVar(oldVar, t => TypeHelpers.CreateSpatialUnionTypeUsage(t));
472         }
473 
474 
475         /// <summary>
476         /// Creates a new var for a table column
477         /// </summary>
478         /// <param name="table">The table instance that produces the column</param>
479         /// <param name="columnMD">column metadata</param>
480         /// <returns>A new ColumnVar instance that references the specified column in the given table</returns>
CreateColumnVar(Table table, ColumnMD columnMD)481         internal ColumnVar CreateColumnVar(Table table, ColumnMD columnMD)
482         {
483             // create a new column var now
484             ColumnVar c = new ColumnVar(NewVarId(), table, columnMD);
485             table.Columns.Add(c);
486             m_vars.Add(c);
487             return c;
488         }
489 
490         /// <summary>
491         /// Creates a computed var (ie) a variable that is computed by an expression
492         /// </summary>
493         /// <param name="type">The type of the result produced by the expression that defines the variable</param>
494         /// <returns>A new ComputedVar instance with the specified result type</returns>
CreateComputedVar(TypeUsage type)495         internal ComputedVar CreateComputedVar(TypeUsage type)
496         {
497             ComputedVar v = new ComputedVar(NewVarId(), type);
498             m_vars.Add(v);
499             return v;
500         }
501 
502         /// <summary>
503         /// Creates a SetOp Var of
504         /// </summary>
505         /// <param name="type">Datatype of the Var</param>
506         /// <returns>A new SetOp Var with the specified result type</returns>
CreateSetOpVar(TypeUsage type)507         internal SetOpVar CreateSetOpVar(TypeUsage type)
508         {
509             SetOpVar v = new SetOpVar(NewVarId(), type);
510             m_vars.Add(v);
511             return v;
512         }
513 
514         #endregion
515 
516         #region Node Creation
517         //
518         // The routines below help in node construction. All command tree nodes must go
519         // through these routines. These routines help to stamp each node with a unique
520         // id (the id is very helpful for debugging)
521         //
522 
523         /// <summary>
524         /// Creates a Node with zero children
525         /// </summary>
526         /// <param name="op">The operator that the Node should reference</param>
527         /// <returns>A new Node with zero children that references the specified Op</returns>
CreateNode(Op op)528         internal Node CreateNode(Op op)
529         {
530             return this.CreateNode(op, new List<Node>());
531         }
532 
533         /// <summary>
534         /// Creates a node with a single child Node
535         /// </summary>
536         /// <param name="op">The operator that the Node should reference</param>
537         /// <param name="arg1">The single child Node</param>
538         /// <returns>A new Node with the specified child Node, that references the specified Op</returns>
CreateNode(Op op, Node arg1)539         internal Node CreateNode(Op op, Node arg1)
540         {
541             List<Node> l = new List<Node>();
542             l.Add(arg1);
543             return this.CreateNode(op, l);
544         }
545 
546         /// <summary>
547         /// Creates a node with two child Nodes
548         /// </summary>
549         /// <param name="op">The operator that the Node should reference</param>
550         /// <param name="arg1">The first child Node</param>
551         /// <param name="arg2">the second child Node</param>
552         /// <returns>A new Node with the specified child Nodes, that references the specified Op</returns>
CreateNode(Op op, Node arg1, Node arg2)553         internal Node CreateNode(Op op, Node arg1, Node arg2)
554         {
555             List<Node> l = new List<Node>();
556             l.Add(arg1); l.Add(arg2);
557             return this.CreateNode(op, l);
558         }
559 
560         /// <summary>
561         /// Creates a node with 3 child Nodes
562         /// </summary>
563         /// <param name="op">The operator that the Node should reference</param>
564         /// <param name="arg1">The first child Node</param>
565         /// <param name="arg2">The second child Node</param>
566         /// <param name="arg3">The third child Node</param>
567         /// <returns>A new Node with the specified child Nodes, that references the specified Op</returns>
CreateNode(Op op, Node arg1, Node arg2, Node arg3)568         internal Node CreateNode(Op op, Node arg1, Node arg2, Node arg3)
569         {
570             List<Node> l = new List<Node>();
571             l.Add(arg1); l.Add(arg2); l.Add(arg3);
572             return this.CreateNode(op, l);
573         }
574 
575         /// <summary>
576         /// Create a Node with the specified list of child Nodes
577         /// </summary>
578         /// <param name="op">The operator that the Node should reference</param>
579         /// <param name="args">The list of child Nodes</param>
580         /// <returns>A new Node with the specified child nodes, that references the specified Op</returns>
CreateNode(Op op, IList<Node> args)581         internal Node CreateNode(Op op, IList<Node> args)
582         {
583             return new Node(m_nextNodeId++, op, new List<Node>(args));
584         }
585 
586         /// <summary>
587         /// Create a Node with the specified list of child Nodes
588         /// </summary>
589         /// <param name="op">The operator that the Node should reference</param>
590         /// <param name="args">The list of child Nodes</param>
591         /// <returns>A new Node with the specified child nodes, that references the specified Op</returns>
CreateNode(Op op, List<Node> args)592         internal Node CreateNode(Op op, List<Node> args)
593         {
594             return new Node(m_nextNodeId++, op, args);
595         }
596 
597         #endregion
598 
599         #region ScalarOps
600 
601         /// <summary>
602         /// Creates a new ConstantOp
603         /// </summary>
604         /// <param name="type">The type of the constant value</param>
605         /// <param name="value">The constant value (may be null)</param>
606         /// <returns>A new ConstantOp with the specified type and value</returns>
CreateConstantOp(TypeUsage type, object value)607         internal ConstantBaseOp CreateConstantOp(TypeUsage type, object value)
608         {
609             // create a NullOp if necessary
610             if (value == null)
611             {
612                 return new NullOp(type);
613             }
614             // Identify "safe" constants - the only safe ones are boolean (and we should
615             // probably include ints eventually)
616             else if (TypeSemantics.IsBooleanType(type))
617             {
618                 return new InternalConstantOp(type, value);
619             }
620             else
621             {
622                 return new ConstantOp(type, value);
623             }
624         }
625 
626         /// <summary>
627         /// Create an "internal" constantOp - only for use by the plan compiler to
628         /// represent internally generated constants.
629         /// User constants in the query should never get into this function
630         /// </summary>
631         /// <param name="type">datatype of the constant</param>
632         /// <param name="value">constant value</param>
633         /// <returns>a new "internal" constant op that represents the constant</returns>
CreateInternalConstantOp(TypeUsage type, object value)634         internal InternalConstantOp CreateInternalConstantOp(TypeUsage type, object value)
635         {
636             return new InternalConstantOp(type, value);
637         }
638 
639         /// <summary>
640         /// An internal constant that serves as a null sentinel, i.e. it is only ever used
641         /// to be checked whether it is null
642         /// </summary>
643         /// <returns></returns>
CreateNullSentinelOp()644         internal NullSentinelOp CreateNullSentinelOp()
645         {
646             return new NullSentinelOp(this.IntegerType, 1);
647         }
648 
649         /// <summary>
650         /// An "internal" null constant
651         /// </summary>
652         /// <param name="type">datatype of the null constant</param>
653         /// <returns>a new "internal" null constant op</returns>
CreateNullOp(TypeUsage type)654         internal NullOp CreateNullOp(TypeUsage type)
655         {
656             return new NullOp(type);
657         }
658 
659         /// <summary>
660         /// Create a constant predicateOp
661         /// </summary>
662         /// <param name="value">value of the constant predicate</param>
663         /// <returns></returns>
CreateConstantPredicateOp(bool value)664         internal ConstantPredicateOp CreateConstantPredicateOp(bool value)
665         {
666             return value ? m_trueOp : m_falseOp;
667         }
668 
669         /// <summary>
670         /// Create a constant predicate with value=true
671         /// </summary>
672         /// <returns></returns>
CreateTrueOp()673         internal ConstantPredicateOp CreateTrueOp()
674         {
675             return m_trueOp;
676         }
677         /// <summary>
678         /// Create a constant predicateOp with the value false
679         /// </summary>
680         /// <returns></returns>
CreateFalseOp()681         internal ConstantPredicateOp CreateFalseOp()
682         {
683             return m_falseOp;
684         }
685 
686         /// <summary>
687         /// Creates a new FunctionOp
688         /// </summary>
689         /// <param name="function">EdmFunction metadata that represents the function that is invoked by the Op</param>
690         /// <returns>A new FunctionOp that references the specified function metadata</returns>
CreateFunctionOp(EdmFunction function)691         internal FunctionOp CreateFunctionOp(EdmFunction function)
692         {
693             return new FunctionOp(function);
694         }
695 
696         /// <summary>
697         /// Creates a new TreatOp
698         /// </summary>
699         /// <param name="type">Type metadata that specifies the type that the child of the treat node should be treated as</param>
700         /// <returns>A new TreatOp that references the specified type metadata</returns>
CreateTreatOp(TypeUsage type)701         internal TreatOp CreateTreatOp(TypeUsage type)
702         {
703             return new TreatOp(type, false);
704         }
705 
706         /// <summary>
707         /// Create a "dummy" treatOp (i.e.) we can actually ignore the treatOp.
708         /// </summary>
709         /// <param name="type"></param>
710         /// <returns></returns>
CreateFakeTreatOp(TypeUsage type)711         internal TreatOp CreateFakeTreatOp(TypeUsage type)
712         {
713             return new TreatOp(type, true);
714         }
715 
716         /// <summary>
717         /// Creates a new IsOfOp, which tests if the argument is of the specified type or a promotable type
718         /// </summary>
719         /// <param name="isOfType">Type metadata that specifies the type with which the type of the argument should be compared</param>
720         /// <returns>A new IsOfOp that references the specified type metadata</returns>
CreateIsOfOp(TypeUsage isOfType)721         internal IsOfOp CreateIsOfOp(TypeUsage isOfType)
722         {
723             return new IsOfOp(isOfType, false/*only*/, m_boolType);
724         }
725         /// <summary>
726         /// Creates a new IsOfOp, which tests if the argument is of the specified type (and only the specified type)
727         /// </summary>
728         /// <param name="isOfType">Type metadata that specifies the type with which the type of the argument should be compared</param>
729         /// <returns>A new IsOfOp that references the specified type metadata</returns>
CreateIsOfOnlyOp(TypeUsage isOfType)730         internal IsOfOp CreateIsOfOnlyOp(TypeUsage isOfType)
731         {
732             return new IsOfOp(isOfType, true /* "only" */, m_boolType);
733         }
734 
735         /// <summary>
736         /// Creates a new CastOp
737         /// </summary>
738         /// <param name="type">Type metadata that represents the type to which the argument should be cast</param>
739         /// <returns>A new CastOp that references the specified type metadata</returns>
CreateCastOp(TypeUsage type)740         internal CastOp CreateCastOp(TypeUsage type)
741         {
742             return new CastOp(type);
743         }
744 
745         /// <summary>
746         /// Creates a new SoftCastOp and casts the input to the desired type.
747         ///
748         /// The caller is expected to determine if the cast is necessary or not
749         /// </summary>
750         /// <param name="type">Type metadata that represents the type to which the argument should be cast</param>
751         /// <returns>A new CastOp that references the specified type metadata</returns>
CreateSoftCastOp(TypeUsage type)752         internal SoftCastOp CreateSoftCastOp(TypeUsage type)
753         {
754             return new SoftCastOp(type);
755         }
756 
757         /// <summary>
758         /// Creates a new ComparisonOp of the specified type
759         /// </summary>
760         /// <param name="opType">An OpType that specifies one of the valid comparison OpTypes: EQ, GT, GE, NE, LT, LE</param>
761         /// <returns>A new ComparisonOp of the specified comparison OpType</returns>
CreateComparisonOp(OpType opType)762         internal ComparisonOp CreateComparisonOp(OpType opType)
763         {
764             return new ComparisonOp(opType, this.BooleanType);
765         }
766 
767         /// <summary>
768         /// Creates a new LikeOp
769         /// </summary>
770         /// <returns>The new LikeOp</returns>
CreateLikeOp()771         internal LikeOp CreateLikeOp()
772         {
773             return new LikeOp(this.BooleanType);
774         }
775 
776         /// <summary>
777         /// Creates a new ConditionalOp of the specified type
778         /// </summary>
779         /// <param name="opType">An OpType that specifies one of the valid condition operations: And, Or, Not, IsNull</param>
780         /// <returns>A new ConditionalOp with the specified conditional OpType</returns>
CreateConditionalOp(OpType opType)781         internal ConditionalOp CreateConditionalOp(OpType opType)
782         {
783             return new ConditionalOp(opType, this.BooleanType);
784         }
785 
786         /// <summary>
787         /// Creates a new CaseOp
788         /// </summary>
789         /// <param name="type">The result type of the CaseOp</param>
790         /// <returns>A new CaseOp with the specified result type</returns>
CreateCaseOp(TypeUsage type)791         internal CaseOp CreateCaseOp(TypeUsage type)
792         {
793             return new CaseOp(type);
794         }
795 
796         /// <summary>
797         /// Creates a new AggregateOp
798         /// </summary>
799         /// <param name="aggFunc">EdmFunction metadata that specifies the aggregate function</param>
800         /// <param name="distinctAgg">Indicates whether or not the aggregate is a distinct aggregate</param>
801         /// <returns>A new AggregateOp with the specified function metadata and distinct property</returns>
CreateAggregateOp(EdmFunction aggFunc, bool distinctAgg)802         internal AggregateOp CreateAggregateOp(EdmFunction aggFunc, bool distinctAgg)
803         {
804             return new AggregateOp(aggFunc, distinctAgg);
805         }
806 
807         /// <summary>
808         /// Creates a named type constructor
809         /// </summary>
810         /// <param name="type">Type metadata that specifies the type of the instance to construct</param>
811         /// <returns>A new NewInstanceOp with the specified result type</returns>
CreateNewInstanceOp(TypeUsage type)812         internal NewInstanceOp CreateNewInstanceOp(TypeUsage type)
813         {
814             return new NewInstanceOp(type);
815         }
816 
817         /// <summary>
818         /// Build out a new NewEntityOp constructing the entity <paramref name="type"/> scoped to the <paramref name="entitySet"/>.
819         /// </summary>
CreateScopedNewEntityOp(TypeUsage type, List<RelProperty> relProperties, EntitySet entitySet)820         internal NewEntityOp CreateScopedNewEntityOp(TypeUsage type, List<RelProperty> relProperties, EntitySet entitySet)
821         {
822             return new NewEntityOp(type, relProperties, true, entitySet);
823         }
824 
825         /// <summary>
826         /// Build out a new NewEntityOp constructing the uscoped entity <paramref name="type"/>.
827         /// </summary>
CreateNewEntityOp(TypeUsage type, List<RelProperty> relProperties)828         internal NewEntityOp CreateNewEntityOp(TypeUsage type, List<RelProperty> relProperties)
829         {
830             return new NewEntityOp(type, relProperties, false, null);
831         }
832 
833         /// <summary>
834         /// Create a discriminated named type constructor
835         /// </summary>
836         /// <param name="type">Type metadata that specifies the type of the instance to construct</param>
837         /// <param name="discriminatorMap">Mapping information including discriminator values</param>
838         /// <param name="entitySet">the entityset that this instance belongs to</param>
839         /// <param name="relProperties">list of rel properties that have corresponding values</param>
840         /// <returns>A new DiscriminatedNewInstanceOp with the specified result type and discrimination behavior</returns>
CreateDiscriminatedNewEntityOp(TypeUsage type, ExplicitDiscriminatorMap discriminatorMap, EntitySet entitySet, List<RelProperty> relProperties)841         internal DiscriminatedNewEntityOp CreateDiscriminatedNewEntityOp(TypeUsage type, ExplicitDiscriminatorMap discriminatorMap,
842             EntitySet entitySet, List<RelProperty> relProperties)
843         {
844             return new DiscriminatedNewEntityOp(type, discriminatorMap, entitySet, relProperties);
845         }
846 
847         /// <summary>
848         /// Creates a multiset constructor
849         /// </summary>
850         /// <param name="type">Type metadata that specifies the type of the multiset to construct</param>
851         /// <returns>A new NewMultiSetOp with the specified result type</returns>
CreateNewMultisetOp(TypeUsage type)852         internal NewMultisetOp CreateNewMultisetOp(TypeUsage type)
853         {
854             return new NewMultisetOp(type);
855         }
856 
857         /// <summary>
858         /// Creates a record constructor
859         /// </summary>
860         /// <param name="type">Type metadata that specifies that record type to construct</param>
861         /// <returns>A new NewRecordOp with the specified result type</returns>
CreateNewRecordOp(TypeUsage type)862         internal NewRecordOp CreateNewRecordOp(TypeUsage type)
863         {
864             return new NewRecordOp(type);
865         }
866 
867         /// <summary>
868         /// Creates a record constructor
869         /// </summary>
870         /// <param name="type">Type metadata that specifies that record type to construct</param>
871         /// <returns>A new NewRecordOp with the specified result type</returns>
CreateNewRecordOp(RowType type)872         internal NewRecordOp CreateNewRecordOp(RowType type)
873         {
874             return new NewRecordOp(TypeUsage.Create(type));
875         }
876 
877         /// <summary>
878         /// A variant of the above method to create a NewRecordOp. An additional
879         /// argument - fields - is supplied, and the semantics is that only these fields
880         /// have any values specified as part of the Node. All other fields are
881         /// considered to be null.
882         /// </summary>
883         /// <param name="type"></param>
884         /// <param name="fields"></param>
885         /// <returns></returns>
CreateNewRecordOp(TypeUsage type, List<EdmProperty> fields)886         internal NewRecordOp CreateNewRecordOp(TypeUsage type,
887             List<EdmProperty> fields)
888         {
889             return new NewRecordOp(type, fields);
890         }
891 
892         /// <summary>
893         /// Creates a new VarRefOp
894         /// </summary>
895         /// <param name="v">The variable to reference</param>
896         /// <returns>A new VarRefOp that references the specified variable</returns>
CreateVarRefOp(Var v)897         internal VarRefOp CreateVarRefOp(Var v)
898         {
899             return new VarRefOp(v);
900         }
901         /// <summary>
902         /// Creates a new ArithmeticOp of the specified type
903         /// </summary>
904         /// <param name="opType">An OpType that specifies one of the valid arithmetic operations: Plus, Minus, Multiply, Divide, Modulo, UnaryMinus</param>
905         /// <param name="type">Type metadata that specifies the result type of the arithmetic operation</param>
906         /// <returns>A new ArithmeticOp of the specified arithmetic OpType</returns>
CreateArithmeticOp(OpType opType, TypeUsage type)907         internal ArithmeticOp CreateArithmeticOp(OpType opType, TypeUsage type)
908         {
909             return new ArithmeticOp(opType, type);
910         }
911 
912         /// <summary>
913         /// Creates a new PropertyOp
914         /// </summary>
915         /// <param name="prop">EdmProperty metadata that specifies the property</param>
916         /// <returns>A new PropertyOp that references the specified property metadata</returns>
CreatePropertyOp(EdmMember prop)917         internal PropertyOp CreatePropertyOp(EdmMember prop)
918         {
919             //
920             // Track all rel-properties
921             //
922             NavigationProperty navProp = prop as NavigationProperty;
923             if (navProp != null)
924             {
925                 RelProperty relProperty = new RelProperty(navProp.RelationshipType, navProp.FromEndMember, navProp.ToEndMember);
926                 AddRelPropertyReference(relProperty);
927                 RelProperty inverseRelProperty = new RelProperty(navProp.RelationshipType, navProp.ToEndMember, navProp.FromEndMember);
928                 AddRelPropertyReference(inverseRelProperty);
929             }
930 
931             // Actually create the propertyOp
932             return new PropertyOp(Helper.GetModelTypeUsage(prop), prop);
933         }
934 
935         /// <summary>
936         /// Create a "relationship" propertyOp
937         /// </summary>
938         /// <param name="prop">the relationship property</param>
939         /// <returns>a RelPropertyOp</returns>
CreateRelPropertyOp(RelProperty prop)940         internal RelPropertyOp CreateRelPropertyOp(RelProperty prop)
941         {
942             AddRelPropertyReference(prop);
943             return new RelPropertyOp(prop.ToEnd.TypeUsage, prop);
944         }
945 
946         /// <summary>
947         /// Creates a new RefOp
948         /// </summary>
949         /// <param name="entitySet">The EntitySet to which the ref refers</param>
950         /// <param name="type">The result type of the RefOp</param>
951         /// <returns>A new RefOp that references the specified EntitySet and has the specified result type</returns>
CreateRefOp(EntitySet entitySet, TypeUsage type)952         internal RefOp CreateRefOp(EntitySet entitySet, TypeUsage type)
953         {
954             return new RefOp(entitySet, type);
955         }
956 
957         /// <summary>
958         /// Creates a new ExistsOp
959         /// </summary>
960         /// <returns>A new ExistsOp</returns>
CreateExistsOp()961         internal ExistsOp CreateExistsOp()
962         {
963             return new ExistsOp(this.BooleanType);
964         }
965         /// <summary>
966         /// Creates a new ElementOp
967         /// </summary>
968         /// <param name="type">Type metadata that specifies the result (element) type</param>
969         /// <returns>A new ElementOp with the specified result type</returns>
CreateElementOp(TypeUsage type)970         internal ElementOp CreateElementOp(TypeUsage type)
971         {
972             return new ElementOp(type);
973         }
974 
975         /// <summary>
976         /// Creates a new GetEntityRefOp: a ref-extractor (from an entity instance) Op
977         /// </summary>
978         /// <param name="type">Type metadata that specifies the result type</param>
979         /// <returns>A new GetEntityKeyOp with the specified result type</returns>
CreateGetEntityRefOp(TypeUsage type)980         internal GetEntityRefOp CreateGetEntityRefOp(TypeUsage type)
981         {
982             return new GetEntityRefOp(type);
983         }
984         /// <summary>
985         /// Creates a new GetRefKeyOp: a key-extractor (from a ref instance) Op
986         /// </summary>
987         /// <param name="type">Type metadata that specifies the result type</param>
988         /// <returns>A new GetRefKeyOp with the specified result type</returns>
CreateGetRefKeyOp(TypeUsage type)989         internal GetRefKeyOp CreateGetRefKeyOp(TypeUsage type)
990         {
991             return new GetRefKeyOp(type);
992         }
993 
994         /// <summary>
995         /// Creates a new CollectOp
996         /// </summary>
997         /// <param name="type">Type metadata that specifies the result type of the Nest operation</param>
998         /// <returns>A new NestOp with the specified result type</returns>
CreateCollectOp(TypeUsage type)999         internal CollectOp CreateCollectOp(TypeUsage type)
1000         {
1001             return new CollectOp(type);
1002         }
1003 
1004         /// <summary>
1005         /// Create a DerefOp
1006         /// </summary>
1007         /// <param name="type">Entity type of the target entity</param>
1008         /// <returns>a DerefOp</returns>
CreateDerefOp(TypeUsage type)1009         internal DerefOp CreateDerefOp(TypeUsage type)
1010         {
1011             return new DerefOp(type);
1012         }
1013 
1014         /// <summary>
1015         /// Create a new NavigateOp node
1016         /// </summary>
1017         /// <param name="type">the output type of the navigateOp</param>
1018         /// <param name="relProperty">the relationship property</param>
1019         /// <returns>the navigateOp</returns>
CreateNavigateOp(TypeUsage type, RelProperty relProperty)1020         internal NavigateOp CreateNavigateOp(TypeUsage type, RelProperty relProperty)
1021         {
1022             // keep track of rel-properties
1023             AddRelPropertyReference(relProperty);
1024             return new NavigateOp(type, relProperty);
1025         }
1026 
1027         #endregion
1028 
1029         #region AncillaryOps
1030 
1031         /// <summary>
1032         /// Creates a VarDefListOp
1033         /// </summary>
1034         /// <returns>A new VarDefListOp</returns>
CreateVarDefListOp()1035         internal VarDefListOp CreateVarDefListOp()
1036         {
1037             return VarDefListOp.Instance;
1038         }
1039         /// <summary>
1040         /// Creates a VarDefOp (for a computed var)
1041         /// </summary>
1042         /// <param name="v">The computed var</param>
1043         /// <returns>A new VarDefOp that references the computed var</returns>
CreateVarDefOp(Var v)1044         internal VarDefOp CreateVarDefOp(Var v)
1045         {
1046             return new VarDefOp(v);
1047         }
1048 
1049         /// <summary>
1050         /// Create a VarDefOp and the associated node for an expression.
1051         /// We create a computedVar first - of the same type as the expression, and
1052         /// then create a VarDefOp for the computed Var. Finally, we create a Node for
1053         /// the VarDefOp
1054         /// </summary>
1055         /// <param name="definingExpr"></param>
1056         /// <param name="computedVar">new Var produced</param>
1057         /// <returns></returns>
CreateVarDefNode(Node definingExpr, out Var computedVar)1058         internal Node CreateVarDefNode(Node definingExpr, out Var computedVar)
1059         {
1060             Debug.Assert(definingExpr.Op != null);
1061             ScalarOp scalarOp = definingExpr.Op as ScalarOp;
1062             Debug.Assert(scalarOp != null);
1063             computedVar = this.CreateComputedVar(scalarOp.Type);
1064             VarDefOp varDefOp = this.CreateVarDefOp(computedVar);
1065             Node varDefNode = this.CreateNode(varDefOp, definingExpr);
1066             return varDefNode;
1067         }
1068 
1069         /// <summary>
1070         /// Creates a VarDefListOp with a single child - a VarDefOp created as in the function
1071         /// above.
1072         /// </summary>
1073         /// <param name="definingExpr"></param>
1074         /// <param name="computedVar">the computed Var produced</param>
1075         /// <returns></returns>
CreateVarDefListNode(Node definingExpr, out Var computedVar)1076         internal Node CreateVarDefListNode(Node definingExpr, out Var computedVar)
1077         {
1078             Node varDefNode = this.CreateVarDefNode(definingExpr, out computedVar);
1079             VarDefListOp op = this.CreateVarDefListOp();
1080             Node varDefListNode = this.CreateNode(op, varDefNode);
1081             return varDefListNode;
1082         }
1083         #endregion
1084 
1085         #region RelOps
1086 
1087         /// <summary>
1088         /// Creates a new ScanTableOp
1089         /// </summary>
1090         /// <param name="tableMetadata">A Table metadata instance that specifies the table that should be scanned</param>
1091         /// <returns>A new ScanTableOp that references a new Table instance based on the specified table metadata</returns>
CreateScanTableOp(TableMD tableMetadata)1092         internal ScanTableOp CreateScanTableOp(TableMD tableMetadata)
1093         {
1094             Table table = this.CreateTableInstance(tableMetadata);
1095             return CreateScanTableOp(table);
1096         }
1097         /// <summary>
1098         /// A variant of the above
1099         /// </summary>
1100         /// <param name="table">The table instance</param>
1101         /// <returns>a new ScanTableOp</returns>
CreateScanTableOp(Table table)1102         internal ScanTableOp CreateScanTableOp(Table table)
1103         {
1104             return new ScanTableOp(table);
1105         }
1106 
1107         /// <summary>
1108         /// Creates an instance of a ScanViewOp
1109         /// </summary>
1110         /// <param name="table">the table instance</param>
1111         /// <returns>a new ScanViewOp</returns>
CreateScanViewOp(Table table)1112         internal ScanViewOp CreateScanViewOp(Table table)
1113         {
1114             return new ScanViewOp(table);
1115         }
1116         /// <summary>
1117         /// Creates an instance of a ScanViewOp
1118         /// </summary>
1119         /// <param name="tableMetadata">the table metadata</param>
1120         /// <returns>a new ScanViewOp</returns>
CreateScanViewOp(TableMD tableMetadata)1121         internal ScanViewOp CreateScanViewOp(TableMD tableMetadata)
1122         {
1123             Table table = this.CreateTableInstance(tableMetadata);
1124             return this.CreateScanViewOp(table);
1125         }
1126         /// <summary>
1127         /// Creates a new UnnestOp, which creates a streaming result from a scalar (non-RelOp) value
1128         /// </summary>
1129         /// <param name="v">The Var that indicates the value to unnest</param>
1130         /// <returns>A new UnnestOp that targets the specified Var</returns>
CreateUnnestOp(Var v)1131         internal UnnestOp CreateUnnestOp(Var v)
1132         {
1133             Table t = this.CreateTableInstance(Command.CreateTableDefinition(TypeHelpers.GetEdmType<CollectionType>(v.Type).TypeUsage));
1134             return CreateUnnestOp(v, t);
1135         }
1136 
1137         /// <summary>
1138         /// Creates a new UnnestOp - a variant of the above with the Table supplied
1139         /// </summary>
1140         /// <param name="v">the unnest Var</param>
1141         /// <param name="t">the table instance</param>
1142         /// <returns>a new UnnestOp</returns>
CreateUnnestOp(Var v, Table t)1143         internal UnnestOp CreateUnnestOp(Var v, Table t)
1144         {
1145             return new UnnestOp(v, t);
1146         }
1147 
1148         /// <summary>
1149         /// Creates a new FilterOp
1150         /// </summary>
1151         /// <returns>A new FilterOp</returns>
CreateFilterOp()1152         internal FilterOp CreateFilterOp()
1153         {
1154             return FilterOp.Instance;
1155         }
1156 
1157         /// <summary>
1158         /// Creates a new ProjectOp
1159         /// </summary>
1160         /// <param name="vars">A VarSet that specifies the Vars produced by the projection</param>
1161         /// <returns>A new ProjectOp with the specified output VarSet</returns>
CreateProjectOp(VarVec vars)1162         internal ProjectOp CreateProjectOp(VarVec vars)
1163         {
1164             return new ProjectOp(vars);
1165         }
1166         /// <summary>
1167         /// A variant of the above where the ProjectOp produces exactly one var
1168         /// </summary>
1169         /// <param name="v"></param>
1170         /// <returns></returns>
CreateProjectOp(Var v)1171         internal ProjectOp CreateProjectOp(Var v)
1172         {
1173             VarVec varSet = this.CreateVarVec();
1174             varSet.Set(v);
1175             return new ProjectOp(varSet);
1176         }
1177 
1178         #region JoinOps
1179 
1180         /// <summary>
1181         /// Creates a new InnerJoinOp
1182         /// </summary>
1183         /// <returns>A new InnerJoinOp</returns>
CreateInnerJoinOp()1184         internal InnerJoinOp CreateInnerJoinOp()
1185         {
1186             return InnerJoinOp.Instance;
1187         }
1188 
1189         /// <summary>
1190         /// Creates a new LeftOuterJoinOp
1191         /// </summary>
1192         /// <returns>A new LeftOuterJoinOp</returns>
CreateLeftOuterJoinOp()1193         internal LeftOuterJoinOp CreateLeftOuterJoinOp()
1194         {
1195             return LeftOuterJoinOp.Instance;
1196         }
1197 
1198         /// <summary>
1199         /// Creates a new FullOuterJoinOp
1200         /// </summary>
1201         /// <returns>A new FullOuterJoinOp</returns>
CreateFullOuterJoinOp()1202         internal FullOuterJoinOp CreateFullOuterJoinOp()
1203         {
1204             return FullOuterJoinOp.Instance;
1205         }
1206 
1207         /// <summary>
1208         /// Creates a new CrossJoinOp
1209         /// </summary>
1210         /// <returns>A new CrossJoinOp</returns>
CreateCrossJoinOp()1211         internal CrossJoinOp CreateCrossJoinOp()
1212         {
1213             return CrossJoinOp.Instance;
1214         }
1215 
1216         #endregion
1217 
1218         #region ApplyOps
1219 
1220         /// <summary>
1221         /// Creates a new CrossApplyOp
1222         /// </summary>
1223         /// <returns>A new CrossApplyOp</returns>
CreateCrossApplyOp()1224         internal CrossApplyOp CreateCrossApplyOp()
1225         {
1226             return CrossApplyOp.Instance;
1227         }
1228         /// <summary>
1229         /// Creates a new OuterApplyOp
1230         /// </summary>
1231         /// <returns>A new OuterApplyOp</returns>
CreateOuterApplyOp()1232         internal OuterApplyOp CreateOuterApplyOp()
1233         {
1234             return OuterApplyOp.Instance;
1235         }
1236 
1237         #endregion
1238 
1239         #region SortKeys
1240 
1241         /// <summary>
1242         /// Creates a new SortKey with the specified var, order and collation
1243         /// </summary>
1244         /// <param name="v">The variable to sort on</param>
1245         /// <param name="asc">The sort order (true for ascending, false for descending)</param>
1246         /// <param name="collation">The sort collation</param>
1247         /// <returns>A new SortKey with the specified var, order and collation</returns>
CreateSortKey(Var v, bool asc, string collation)1248         internal static SortKey CreateSortKey(Var v, bool asc, string collation)
1249         {
1250             return new SortKey(v, asc, collation);
1251         }
1252         /// <summary>
1253         /// Creates a new SortKey with the specified var and order
1254         /// </summary>
1255         /// <param name="v">The variable to sort on</param>
1256         /// <param name="asc">The sort order (true for ascending, false for descending)</param>
1257         /// <returns>A new SortKey with the specified var and order</returns>
CreateSortKey(Var v, bool asc)1258         internal static SortKey CreateSortKey(Var v, bool asc)
1259         {
1260             return new SortKey(v, asc, "");
1261         }
1262 
1263         /// <summary>
1264         /// Creates a new SortKey with the specified var
1265         /// </summary>
1266         /// <param name="v">The variable to sort on</param>
1267         /// <returns>A new SortKey with the specified var</returns>
CreateSortKey(Var v)1268         internal static SortKey CreateSortKey(Var v)
1269         {
1270             return new SortKey(v, true, "");
1271         }
1272 
1273         #endregion
1274 
1275         /// <summary>
1276         /// Creates a new SortOp
1277         /// </summary>
1278         /// <param name="sortKeys">The list of SortKeys that define the sort var, order and collation for each sort key</param>
1279         /// <returns>A new SortOp with the specified sort keys</returns>
CreateSortOp(List<SortKey> sortKeys)1280         internal SortOp CreateSortOp(List<SortKey> sortKeys)
1281         {
1282             return new SortOp(sortKeys);
1283         }
1284 
1285         /// <summary>
1286         /// Creates a new ConstrainedSortOp
1287         /// </summary>
1288         /// <param name="sortKeys">The list of SortKeys that define the sort var, order and collation for each sort key</param>
1289         /// <returns>A new ConstrainedSortOp with the specified sort keys and a default WithTies value of false</returns>
CreateConstrainedSortOp(List<SortKey> sortKeys)1290         internal ConstrainedSortOp CreateConstrainedSortOp(List<SortKey> sortKeys)
1291         {
1292             return new ConstrainedSortOp(sortKeys, false);
1293         }
1294 
1295         /// <summary>
1296         /// Creates a new ConstrainedSortOp
1297         /// </summary>
1298         /// <param name="sortKeys">The list of SortKeys that define the sort var, order and collation for each sort key</param>
1299         /// <param name="withTies">The value to use for the WithTies property of the new ConstrainedSortOp</param>
1300         /// <returns>A new ConstrainedSortOp with the specified sort keys and WithTies value</returns>
CreateConstrainedSortOp(List<SortKey> sortKeys, bool withTies)1301         internal ConstrainedSortOp CreateConstrainedSortOp(List<SortKey> sortKeys, bool withTies)
1302         {
1303             return new ConstrainedSortOp(sortKeys, withTies);
1304         }
1305 
1306         /// <summary>
1307         /// Creates a new GroupByOp
1308         /// </summary>
1309         /// <param name="gbyKeys">A VarSet that specifies the Key variables produced by the GroupByOp</param>
1310         /// <param name="outputs">A VarSet that specifies all (Key and Aggregate) variables produced by the GroupByOp</param>
1311         /// <returns>A new GroupByOp with the specified key and output VarSets</returns>
CreateGroupByOp(VarVec gbyKeys, VarVec outputs)1312         internal GroupByOp CreateGroupByOp(VarVec gbyKeys, VarVec outputs)
1313         {
1314             return new GroupByOp(gbyKeys, outputs);
1315         }
1316 
1317         /// <summary>
1318         /// Creates a new GroupByIntoOp
1319         /// </summary>
1320         /// <param name="gbyKeys">A VarSet that specifies the Key variables produced by the GroupByOp</param>
1321         /// <param name="outputs">A VarSet that specifies the vars from the input that represent the real grouping input</param>
1322         /// <param name="inputs">A VarSet that specifies all (Key and Aggregate) variables produced by the GroupByOp</param>
1323         /// <returns>A new GroupByOp with the specified key and output VarSets</returns>
CreateGroupByIntoOp(VarVec gbyKeys, VarVec inputs, VarVec outputs)1324         internal GroupByIntoOp CreateGroupByIntoOp(VarVec gbyKeys, VarVec inputs, VarVec outputs)
1325         {
1326             return new GroupByIntoOp(gbyKeys, inputs, outputs);
1327         }
1328 
1329         /// <summary>
1330         /// Creates a new DistinctOp
1331         /// <param name="keyVars">list of key vars</param>
1332         /// </summary>
1333         /// <returns>A new DistinctOp</returns>
CreateDistinctOp(VarVec keyVars)1334         internal DistinctOp CreateDistinctOp(VarVec keyVars)
1335         {
1336             return new DistinctOp(keyVars);
1337         }
1338         /// <summary>
1339         /// An overload of the above - where the distinct has exactly one key
1340         /// </summary>
1341         /// <param name="keyVar"></param>
1342         /// <returns></returns>
CreateDistinctOp(Var keyVar)1343         internal DistinctOp CreateDistinctOp(Var keyVar)
1344         {
1345             return new DistinctOp(this.CreateVarVec(keyVar));
1346         }
1347 
1348         /// <summary>
1349         /// Creates a new UnionAllOp
1350         /// </summary>
1351         /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param>
1352         /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param>
1353         /// <returns>A UnionAllOp that references the specified left and right Vars</returns>
CreateUnionAllOp(VarMap leftMap, VarMap rightMap)1354         internal UnionAllOp CreateUnionAllOp(VarMap leftMap, VarMap rightMap)
1355         {
1356             return CreateUnionAllOp(leftMap, rightMap, null);
1357         }
1358 
1359         /// <summary>
1360         /// Creates a new UnionAllOp, with a branch descriminator.
1361         /// </summary>
1362         /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param>
1363         /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param>
1364         /// <param name="branchDiscriminator">Var that contains the branch discrimination value (may be null until key pullup occurs)</param>
1365         /// <returns>A UnionAllOp that references the specified left and right Vars</returns>
CreateUnionAllOp(VarMap leftMap, VarMap rightMap, Var branchDiscriminator)1366         internal UnionAllOp CreateUnionAllOp(VarMap leftMap, VarMap rightMap, Var branchDiscriminator)
1367         {
1368             Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch");
1369             VarVec vec = this.CreateVarVec();
1370             foreach (Var v in leftMap.Keys)
1371             {
1372                 vec.Set(v);
1373             }
1374             return new UnionAllOp(vec, leftMap, rightMap, branchDiscriminator);
1375         }
1376 
1377         /// <summary>
1378         /// Creates a new IntersectOp
1379         /// </summary>
1380         /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param>
1381         /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param>
1382         /// <returns>An IntersectOp that references the specified left and right Vars</returns>
CreateIntersectOp(VarMap leftMap, VarMap rightMap)1383         internal IntersectOp CreateIntersectOp(VarMap leftMap, VarMap rightMap)
1384         {
1385             Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch");
1386             VarVec vec = this.CreateVarVec();
1387             foreach (Var v in leftMap.Keys)
1388             {
1389                 vec.Set(v);
1390             }
1391             return new IntersectOp(vec, leftMap, rightMap);
1392         }
1393         /// <summary>
1394         /// Creates a new ExceptOp
1395         /// </summary>
1396         /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param>
1397         /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param>
1398         /// <returns>An ExceptOp that references the specified left and right Vars</returns>
CreateExceptOp(VarMap leftMap, VarMap rightMap)1399         internal ExceptOp CreateExceptOp(VarMap leftMap, VarMap rightMap)
1400         {
1401             Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch");
1402             VarVec vec = this.CreateVarVec();
1403             foreach (Var v in leftMap.Keys)
1404             {
1405                 vec.Set(v);
1406             }
1407             return new ExceptOp(vec, leftMap, rightMap);
1408         }
1409 
1410         /// <summary>
1411         /// Create a single-row-op (the relop analog of Element)
1412         /// </summary>
1413         /// <returns></returns>
CreateSingleRowOp()1414         internal SingleRowOp CreateSingleRowOp()
1415         {
1416             return SingleRowOp.Instance;
1417         }
1418 
1419         /// <summary>
1420         /// Create a SingleRowTableOp - a table with exactly one row (and no columns)
1421         /// </summary>
1422         /// <returns></returns>
CreateSingleRowTableOp()1423         internal SingleRowTableOp CreateSingleRowTableOp()
1424         {
1425             return SingleRowTableOp.Instance;
1426         }
1427 
1428         #endregion
1429 
1430         #region PhysicalOps
1431         /// <summary>
1432         /// Create a PhysicalProjectOp - with a columnMap describing the output
1433         /// </summary>
1434         /// <param name="outputVars">list of output vars</param>
1435         /// <param name="columnMap">columnmap describing the output element</param>
1436         /// <returns></returns>
CreatePhysicalProjectOp(VarList outputVars, SimpleCollectionColumnMap columnMap)1437         internal PhysicalProjectOp CreatePhysicalProjectOp(VarList outputVars, SimpleCollectionColumnMap columnMap)
1438         {
1439             return new PhysicalProjectOp(outputVars, columnMap);
1440         }
1441         /// <summary>
1442         /// Create a physicalProjectOp - with a single column output
1443         /// </summary>
1444         /// <param name="outputVar">the output element</param>
1445         /// <returns></returns>
CreatePhysicalProjectOp(Var outputVar)1446         internal PhysicalProjectOp CreatePhysicalProjectOp(Var outputVar)
1447         {
1448             VarList varList = Command.CreateVarList();
1449             varList.Add(outputVar);
1450             VarRefColumnMap varRefColumnMap = new VarRefColumnMap(outputVar);
1451 
1452             SimpleCollectionColumnMap collectionColumnMap = new SimpleCollectionColumnMap(
1453                 TypeUtils.CreateCollectionType(varRefColumnMap.Type),   // type
1454                 null,                                                   // name
1455                 varRefColumnMap,                                        // element map
1456                 new SimpleColumnMap[0],                                 // keys
1457                 new SimpleColumnMap[0]);                                // foreign keys
1458             return CreatePhysicalProjectOp(varList, collectionColumnMap);
1459         }
1460 
1461         /// <summary>
1462         /// Another overload - with an additional discriminatorValue.
1463         /// Should this be a subtype instead?
1464         /// </summary>
1465         /// <param name="collectionVar">the collectionVar</param>
1466         /// <param name="columnMap">column map for the collection element</param>
1467         /// <param name="flattenedElementVars">elementVars with any nested collections pulled up</param>
1468         /// <param name="keys">keys specific to this collection</param>
1469         /// <param name="sortKeys">sort keys specific to this collecion</param>
1470         /// <param name="discriminatorValue">discriminator value for this collection (under the current nestOp)</param>
1471         /// <returns>a new CollectionInfo instance</returns>
CreateCollectionInfo(Var collectionVar, ColumnMap columnMap, VarList flattenedElementVars, VarVec keys, List<InternalTrees.SortKey> sortKeys, object discriminatorValue)1472         internal static CollectionInfo CreateCollectionInfo(Var collectionVar, ColumnMap columnMap, VarList flattenedElementVars, VarVec keys, List<InternalTrees.SortKey> sortKeys, object discriminatorValue)
1473         {
1474             return new CollectionInfo(collectionVar, columnMap, flattenedElementVars, keys, sortKeys, discriminatorValue);
1475         }
1476 
1477         /// <summary>
1478         /// Create a singleStreamNestOp
1479         /// </summary>
1480         /// <param name="keys">keys for the nest operation</param>
1481         /// <param name="prefixSortKeys">list of prefix sort keys</param>
1482         /// <param name="postfixSortKeys">list of postfix sort keys</param>
1483         /// <param name="outputVars">List of outputVars</param>
1484         /// <param name="collectionInfoList">CollectionInfo for each collection </param>
1485         /// <param name="discriminatorVar">Var describing the discriminator</param>
1486         /// <returns></returns>
CreateSingleStreamNestOp(VarVec keys, List<SortKey> prefixSortKeys, List<SortKey> postfixSortKeys, VarVec outputVars, List<CollectionInfo> collectionInfoList, Var discriminatorVar)1487         internal SingleStreamNestOp CreateSingleStreamNestOp(VarVec keys,
1488             List<SortKey> prefixSortKeys, List<SortKey> postfixSortKeys,
1489             VarVec outputVars,
1490             List<CollectionInfo> collectionInfoList, Var discriminatorVar)
1491         {
1492             return new SingleStreamNestOp(keys, prefixSortKeys, postfixSortKeys, outputVars, collectionInfoList, discriminatorVar);
1493         }
1494 
1495         /// <summary>
1496         /// Create a MultiStreamNestOp
1497         /// </summary>
1498         /// <param name="prefixSortKeys">list of prefix sort keys</param>
1499         /// <param name="outputVars">List of outputVars</param>
1500         /// <param name="collectionInfoList">CollectionInfo for each collection element</param>
1501         /// <returns></returns>
CreateMultiStreamNestOp(List<SortKey> prefixSortKeys, VarVec outputVars, List<CollectionInfo> collectionInfoList)1502         internal MultiStreamNestOp CreateMultiStreamNestOp(List<SortKey> prefixSortKeys, VarVec outputVars,
1503             List<CollectionInfo> collectionInfoList)
1504         {
1505             return new MultiStreamNestOp(prefixSortKeys, outputVars, collectionInfoList);
1506         }
1507         #endregion
1508 
1509         #region NodeInfo
1510         /// <summary>
1511         /// Get auxilliary information for a Node
1512         /// </summary>
1513         /// <param name="n">the node</param>
1514         /// <returns>node info for this node</returns>
GetNodeInfo(Node n)1515         internal NodeInfo GetNodeInfo(Node n)
1516         {
1517             return n.GetNodeInfo(this);
1518         }
1519 
1520         /// <summary>
1521         /// Get extended node information for a RelOpNode
1522         /// </summary>
1523         /// <param name="n">the node</param>
1524         /// <returns>extended node info for this node</returns>
GetExtendedNodeInfo(Node n)1525         internal ExtendedNodeInfo GetExtendedNodeInfo(Node n)
1526         {
1527             return n.GetExtendedNodeInfo(this);
1528         }
1529         /// <summary>
1530         /// Recompute the nodeinfo for a node, but only if has already been computed
1531         /// </summary>
1532         /// <param name="n">Node in question</param>
RecomputeNodeInfo(Node n)1533         internal void RecomputeNodeInfo(Node n)
1534         {
1535             m_nodeInfoVisitor.RecomputeNodeInfo(n);
1536         }
1537         #endregion
1538 
1539         #region KeyInfo
1540         /// <summary>
1541         /// Pulls up keys if necessary and gets the key information for a Node
1542         /// </summary>
1543         /// <param name="n">node</param>
1544         /// <returns>key information</returns>
PullupKeys(Node n)1545         internal KeyVec PullupKeys(Node n)
1546         {
1547             return m_keyPullupVisitor.GetKeys(n);
1548         }
1549         #endregion
1550 
1551         #region Type Comparisons
1552         //
1553         // The functions described in this region are used through out the
1554         // PlanCompiler to reason about type equality. Make sure that you
1555         // use these and these alone
1556         //
1557 
1558         /// <summary>
1559         /// Check to see if two types are considered "equal" for the purposes
1560         /// of the plan compiler.
1561         /// Two types are considered to be equal if their "identities" are equal.
1562         /// </summary>
1563         /// <param name="x"></param>
1564         /// <param name="y"></param>
1565         /// <returns>true, if the types are "equal"</returns>
EqualTypes(TypeUsage x, TypeUsage y)1566         internal static bool EqualTypes(TypeUsage x, TypeUsage y)
1567         {
1568             return PlanCompiler.TypeUsageEqualityComparer.Instance.Equals(x, y);
1569         }
1570         /// <summary>
1571         /// Check to see if two types are considered "equal" for the purposes
1572         /// of the plan compiler
1573         /// </summary>
1574         /// <param name="x"></param>
1575         /// <param name="y"></param>
1576         /// <returns>true, if the types are "equal"</returns>
EqualTypes(EdmType x, EdmType y)1577         internal static bool EqualTypes(EdmType x, EdmType y)
1578         {
1579             return PlanCompiler.TypeUsageEqualityComparer.Equals(x, y);
1580         }
1581         #endregion
1582 
1583         #region Builder Methods
1584         /// <summary>
1585         /// Builds out a UNION-ALL ladder from a sequence of node,var pairs.
1586         /// Assumption: Each node produces exactly one Var
1587         ///
1588         /// If the input sequence has zero elements, we return null
1589         /// If the input sequence has one element, we return that single element
1590         /// Otherwise, we build out a UnionAll ladder from each of the inputs. If the input sequence was {A,B,C,D},
1591         /// we build up a union-all ladder that looks like
1592         ///     (((A UA B) UA C) UA D)
1593         /// </summary>
1594         /// <param name="inputNodes">list of input nodes - one for each branch</param>
1595         /// <param name="inputVars">list of input vars - N for each branch</param>
1596         /// <param name="resultNode">the resulting union-all subtree</param>
1597         /// <param name="resultVar">the output vars from the union-all subtree</param>
BuildUnionAllLadder( IList<Node> inputNodes, IList<Var> inputVars, out Node resultNode, out IList<Var> resultVars)1598         internal void BuildUnionAllLadder(
1599             IList<Node> inputNodes, IList<Var> inputVars,
1600             out Node resultNode, out IList<Var> resultVars)
1601         {
1602             if (inputNodes.Count == 0)
1603             {
1604                 resultNode = null;
1605                 resultVars = null;
1606                 return;
1607             }
1608 
1609             int varPerNode = inputVars.Count / inputNodes.Count;
1610             Debug.Assert((inputVars.Count % inputNodes.Count == 0) && (varPerNode >= 1), "Inconsistent nodes/vars count:" + inputNodes.Count + "," + inputVars.Count);
1611 
1612             if (inputNodes.Count == 1)
1613             {
1614                 resultNode = inputNodes[0];
1615                 resultVars = inputVars;
1616                 return;
1617             }
1618 
1619             List<Var> unionAllVars = new List<Var>();
1620 
1621             Node unionAllNode = inputNodes[0];
1622             for (int j = 0; j < varPerNode; j++)
1623             {
1624                 unionAllVars.Add(inputVars[j]);
1625             }
1626 
1627             for (int i = 1; i < inputNodes.Count; i++)
1628             {
1629                 VarMap leftVarMap = this.CreateVarMap();
1630                 VarMap rightVarMap = this.CreateVarMap();
1631                 List<Var> setOpVars = new List<Var>();
1632                 for (int j = 0; j < varPerNode; j++)
1633                 {
1634                     SetOpVar newVar = this.CreateSetOpVar(unionAllVars[j].Type);
1635                     setOpVars.Add(newVar);
1636                     leftVarMap.Add(newVar, unionAllVars[j]);
1637                     rightVarMap.Add(newVar, inputVars[i * varPerNode + j]);
1638                 }
1639                 Op unionAllOp = this.CreateUnionAllOp(leftVarMap, rightVarMap);
1640                 unionAllNode = this.CreateNode(unionAllOp, unionAllNode, inputNodes[i]);
1641                 unionAllVars = setOpVars;
1642             }
1643 
1644             resultNode = unionAllNode;
1645             resultVars = unionAllVars;
1646         }
1647 
1648         /// <summary>
1649         /// A simplified version of the method above - each branch can produce only one var
1650         /// </summary>
1651         /// <param name="inputNodes"></param>
1652         /// <param name="inputVars"></param>
1653         /// <param name="resultNode"></param>
1654         /// <param name="resultVar"></param>
BuildUnionAllLadder(IList<Node> inputNodes, IList<Var> inputVars, out Node resultNode, out Var resultVar)1655         internal void BuildUnionAllLadder(IList<Node> inputNodes, IList<Var> inputVars,
1656             out Node resultNode, out Var resultVar)
1657         {
1658             Debug.Assert(inputNodes.Count == inputVars.Count, "Count mismatch:" + inputNodes.Count + "," + inputVars.Count);
1659             IList<Var> varList;
1660             BuildUnionAllLadder(inputNodes, inputVars, out resultNode, out varList);
1661             if (varList != null && varList.Count > 0)
1662             {
1663                 resultVar = varList[0];
1664             }
1665             else
1666             {
1667                 resultVar = null;
1668             }
1669         }
1670 
1671         /// <summary>
1672         /// Build a projectOp tree over the input.
1673         /// This function builds a projectOp tree over the input. The Outputs (vars) of the project are the
1674         /// list of vars from the input (inputVars), plus one computed Var for each of the computed expressions
1675         /// (computedExpressions)
1676         /// </summary>
1677         /// <param name="inputNode">the input relop to the project</param>
1678         /// <param name="inputVars">List of vars from the input that need to be projected</param>
1679         /// <param name="computedExpressions">list (possibly empty) of any computed expressions</param>
1680         /// <returns></returns>
BuildProject(Node inputNode, IEnumerable<Var> inputVars, IEnumerable<Node> computedExpressions)1681         internal Node BuildProject(Node inputNode, IEnumerable<Var> inputVars,
1682             IEnumerable<Node> computedExpressions)
1683         {
1684             Debug.Assert(inputNode.Op.IsRelOp, "Expected a RelOp. Found " + inputNode.Op.OpType);
1685 
1686             VarDefListOp varDefListOp = this.CreateVarDefListOp();
1687             Node varDefListNode = this.CreateNode(varDefListOp);
1688             VarVec projectVars = this.CreateVarVec(inputVars);
1689             foreach (Node expr in computedExpressions)
1690             {
1691                 Var v = this.CreateComputedVar(expr.Op.Type);
1692                 projectVars.Set(v);
1693                 VarDefOp varDefOp = this.CreateVarDefOp(v);
1694                 Node varDefNode = this.CreateNode(varDefOp, expr);
1695                 varDefListNode.Children.Add(varDefNode);
1696             }
1697             Node projectNode = this.CreateNode(
1698                 this.CreateProjectOp(projectVars),
1699                 inputNode,
1700                 varDefListNode);
1701             return projectNode;
1702         }
1703 
1704         /// <summary>
1705         /// A "simpler" builder method for ProjectOp. The assumption is that the only output is the
1706         /// (var corresponding to) the computedExpression. None of the Vars of the "input" are projected out
1707         ///
1708         /// The single output Var is returned in the "outputVar" parameter
1709         /// </summary>
1710         /// <param name="input">the input relop</param>
1711         /// <param name="computedExpression">the computed expression</param>
1712         /// <param name="projectVar">(output) the computed var corresponding to the computed expression</param>
1713         /// <returns>the new project subtree node</returns>
BuildProject(Node input, Node computedExpression, out Var projectVar)1714         internal Node BuildProject(Node input, Node computedExpression, out Var projectVar)
1715         {
1716             Node projectNode = BuildProject(input, new Var[] { }, new Node[] { computedExpression });
1717             projectVar = ((ProjectOp)projectNode.Op).Outputs.First;
1718             return projectNode;
1719         }
1720 
1721         /// <summary>
1722         /// Build the equivalent of an OfTypeExpression over the input (ie) produce the set of values from the
1723         /// input that are of the desired type (exactly of the desired type, if the "includeSubtypes" parameter is false).
1724         ///
1725         /// Further more, "update" the result element type to be the desired type.
1726         ///
1727         /// We accomplish this by first building a FilterOp with an IsOf (or an IsOfOnly) predicate for the desired
1728         /// type. We then build out a ProjectOp over the FilterOp, where we introduce a "Fake" TreatOp over the input
1729         /// element to cast it to the right type. The "Fake" TreatOp is only there for "compile-time" typing reasons,
1730         /// and will be ignored in the rest of the plan compiler
1731         /// </summary>
1732         /// <param name="inputNode">the input collection</param>
1733         /// <param name="inputVar">the single Var produced by the input collection</param>
1734         /// <param name="desiredType">the desired element type </param>
1735         /// <param name="includeSubtypes">do we include subtypes of the desired element type</param>
1736         /// <param name="resultNode">the result subtree</param>
1737         /// <param name="resultVar">the single Var produced by the result subtree</param>
BuildOfTypeTree(Node inputNode, Var inputVar, TypeUsage desiredType, bool includeSubtypes, out Node resultNode, out Var resultVar)1738         internal void BuildOfTypeTree(Node inputNode, Var inputVar, TypeUsage desiredType, bool includeSubtypes,
1739             out Node resultNode, out Var resultVar)
1740         {
1741             Op isOfOp = includeSubtypes ? this.CreateIsOfOp(desiredType) : this.CreateIsOfOnlyOp(desiredType);
1742             Node predicate = this.CreateNode(isOfOp, this.CreateNode(this.CreateVarRefOp(inputVar)));
1743             Node filterNode = this.CreateNode(this.CreateFilterOp(), inputNode, predicate);
1744 
1745             resultNode = BuildFakeTreatProject(filterNode, inputVar, desiredType, out resultVar);
1746         }
1747 
1748         /// Builds out a ProjectOp over the input that introduces a "Fake" TreatOp over the input Var to cast it to the desired type
1749         /// The "Fake" TreatOp is only there for "compile-time" typing reasons, and will be ignored in the rest of the plan compiler.
1750         /// </summary>
1751         /// <param name="inputNode">the input collection</param>
1752         /// <param name="inputVar">the single Var produced by the input collection</param>
1753         /// <param name="desiredType">the desired element type </param>
1754         /// <param name="resultVar">the single Var produced by the result subtree</param>
1755         /// <returns>the result subtree</returns>
BuildFakeTreatProject(Node inputNode, Var inputVar, TypeUsage desiredType, out Var resultVar)1756         internal Node BuildFakeTreatProject(Node inputNode, Var inputVar, TypeUsage desiredType, out Var resultVar)
1757         {
1758             Node treatNode = this.CreateNode(this.CreateFakeTreatOp(desiredType),
1759                 this.CreateNode(this.CreateVarRefOp(inputVar)));
1760             Node resultNode = this.BuildProject(inputNode, treatNode, out resultVar);
1761             return resultNode;
1762         }
1763 
1764         /// <summary>
1765         /// Build a comparisonOp over the input arguments. Build SoftCasts over the inputs, if we need
1766         /// to.
1767         /// </summary>
1768         /// <param name="opType">the comparison optype</param>
1769         /// <param name="arg0">Arg 0</param>
1770         /// <param name="arg1">Arg 1</param>
1771         /// <returns>the resulting comparison tree</returns>
BuildComparison(OpType opType, Node arg0, Node arg1)1772         internal Node BuildComparison(OpType opType, Node arg0, Node arg1)
1773         {
1774             if (!Command.EqualTypes(arg0.Op.Type, arg1.Op.Type))
1775             {
1776                 TypeUsage commonType = TypeHelpers.GetCommonTypeUsage(arg0.Op.Type, arg1.Op.Type);
1777                 Debug.Assert(commonType != null, "No common type for " + arg0.Op.Type + " and " + arg1.Op.Type);
1778                 if (!EqualTypes(commonType, arg0.Op.Type))
1779                 {
1780                     arg0 = this.CreateNode(this.CreateSoftCastOp(commonType), arg0);
1781                 }
1782                 if (!EqualTypes(commonType, arg1.Op.Type))
1783                 {
1784                     arg1 = this.CreateNode(this.CreateSoftCastOp(commonType), arg1);
1785                 }
1786             }
1787             Node newNode = this.CreateNode(this.CreateComparisonOp(opType), arg0, arg1);
1788             return newNode;
1789         }
1790 
1791         /// <summary>
1792         /// Build up a CollectOp over a relop tree
1793         /// </summary>
1794         /// <param name="relOpNode">the relop tree</param>
1795         /// <param name="relOpVar">the single output var from the relop tree</param>
1796         /// <returns></returns>
BuildCollect(Node relOpNode, Var relOpVar)1797         internal Node BuildCollect(Node relOpNode, Var relOpVar)
1798         {
1799             Node physicalProjectNode = this.CreateNode(this.CreatePhysicalProjectOp(relOpVar), relOpNode);
1800             TypeUsage collectOpType = TypeHelpers.CreateCollectionTypeUsage(relOpVar.Type);
1801             Node collectNode = this.CreateNode(this.CreateCollectOp(collectOpType), physicalProjectNode);
1802             return collectNode;
1803         }
1804         #endregion
1805 
1806         #region Rel Properties
1807         /// <summary>
1808         /// Mark this rel-property as "referenced" in the current query, if the target
1809         /// end has multiplicity of one (or zero_or_one)
1810         /// </summary>
1811         /// <param name="relProperty">the rel-property</param>
AddRelPropertyReference(RelProperty relProperty)1812         private void AddRelPropertyReference(RelProperty relProperty)
1813         {
1814             if (relProperty.ToEnd.RelationshipMultiplicity != RelationshipMultiplicity.Many &&
1815                 !m_referencedRelProperties.Contains(relProperty))
1816             {
1817                 m_referencedRelProperties.Add(relProperty);
1818             }
1819         }
1820 
1821         /// <summary>
1822         /// The set of referenced rel properties in the current query
1823         /// </summary>
1824         internal HashSet<RelProperty> ReferencedRelProperties
1825         {
1826             get { return m_referencedRelProperties; }
1827         }
1828 
1829         /// <summary>
1830         /// Is this rel-property referenced in the query so far
1831         /// </summary>
1832         /// <param name="relProperty">the rel-property</param>
1833         /// <returns>true, if the rel property was referenced in the query</returns>
IsRelPropertyReferenced(RelProperty relProperty)1834         internal bool IsRelPropertyReferenced(RelProperty relProperty)
1835         {
1836             bool ret = m_referencedRelProperties.Contains(relProperty);
1837             return ret;
1838         }
1839         #endregion
1840 
1841         #endregion
1842     }
1843 
1844 }
1845