1 //---------------------------------------------------------------------
2 // <copyright file="Command.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
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;
17 namespace System.Data.Query.InternalTrees
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
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
27 internal class Command
30 private Dictionary<string, ParameterVar> m_parameterMap;
31 private List<Var> m_vars;
32 private List<Table> m_tables;
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;
45 private bool m_disableVarVecEnumCaching;
46 private Stack<VarVec.VarVecEnumerator> m_freeVarVecEnumerators;
47 private Stack<VarVec> m_freeVarVecs;
50 // set of referenced rel properties in this query
51 private HashSet<RelProperty> m_referencedRelProperties;
56 /// Creates a new command
58 internal Command(MetadataWorkspace metadataWorkspace)
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))
66 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderBooleanType);
68 if (!TryGetPrimitiveType(PrimitiveTypeKind.Int32, out m_intType))
70 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderIntegerType);
72 if (!TryGetPrimitiveType(PrimitiveTypeKind.String, out m_stringType))
74 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderStringType);
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);
82 m_freeVarVecEnumerators = new Stack<VarVec.VarVecEnumerator>();
83 m_freeVarVecs = new Stack<VarVec>();
85 m_referencedRelProperties = new HashSet<RelProperty>();
89 #region public methods
91 /// Gets the metadata workspace associated with this command
93 internal MetadataWorkspace MetadataWorkspace { get { return m_metadataWorkspace; } }
96 /// Gets/sets the root node of the query
98 internal Node Root { get { return m_root; } set { m_root = value; } }
100 internal void DisableVarVecEnumCaching() { m_disableVarVecEnumCaching = true; }
103 /// Returns the next value for a UnionAll BranchDiscriminator.
105 internal int NextBranchDiscriminatorValue { get { return m_nextBranchDiscriminatorValue++; } }
108 /// Returns the next value for a node id, without incrementing it.
110 internal int NextNodeId { get { return m_nextNodeId; } }
112 #region Metadata Helpers
114 /// Helper routine to get the metadata representation for the bool type
116 internal TypeUsage BooleanType
118 get { return m_boolType; }
122 /// Helper routine to get the metadata representation of the int type
124 internal TypeUsage IntegerType
126 get { return m_intType; }
130 /// Helper routine to get the metadata representation of the string type
132 internal TypeUsage StringType
134 get { return m_stringType; }
138 /// Get the primitive type by primitive type kind
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>
143 private bool TryGetPrimitiveType(PrimitiveTypeKind modelType, out TypeUsage type)
147 if (modelType == PrimitiveTypeKind.String)
149 type = TypeUsage.CreateStringTypeUsage(m_metadataWorkspace.GetModelPrimitiveType(modelType),
155 type = m_metadataWorkspace.GetCanonicalModelTypeUsage(modelType);
158 return (null != type);
162 #region VarVec Creation
164 /// VarVec constructor
166 /// <returns>A new, empty, VarVec</returns>
167 internal VarVec CreateVarVec()
170 if (m_freeVarVecs.Count == 0)
172 vec = new VarVec(this);
176 vec = m_freeVarVecs.Pop();
183 /// Create a VarVec with a single Var
185 /// <param name="v"></param>
186 /// <returns></returns>
187 internal VarVec CreateVarVec(Var v)
189 VarVec varset = CreateVarVec();
195 /// Create a VarVec with the set of specified vars
197 /// <param name="v"></param>
198 /// <returns></returns>
199 internal VarVec CreateVarVec(IEnumerable<Var> v)
201 VarVec vec = CreateVarVec();
207 /// Create a new VarVec from the input VarVec
209 /// <param name="v"></param>
210 /// <returns></returns>
211 internal VarVec CreateVarVec(VarVec v)
213 VarVec vec = CreateVarVec();
219 /// Release a VarVec to the freelist
221 /// <param name="vec"></param>
222 internal void ReleaseVarVec(VarVec vec)
224 m_freeVarVecs.Push(vec);
228 #region VarVecEnumerator
230 /// Create a new enumerator for a VarVec; use a free one if its
231 /// available; otherwise, create a new one
233 /// <param name="vec"></param>
234 /// <returns></returns>
235 internal VarVec.VarVecEnumerator GetVarVecEnumerator(VarVec vec)
237 VarVec.VarVecEnumerator enumerator;
239 if (m_disableVarVecEnumCaching ||
240 m_freeVarVecEnumerators.Count == 0)
242 enumerator = new VarVec.VarVecEnumerator(vec);
246 enumerator = m_freeVarVecEnumerators.Pop();
247 enumerator.Init(vec);
253 /// Release an enumerator; keep it in a local stack for future use
255 /// <param name="enumerator"></param>
256 internal void ReleaseVarVecEnumerator(VarVec.VarVecEnumerator enumerator)
258 if (!m_disableVarVecEnumCaching)
260 m_freeVarVecEnumerators.Push(enumerator);
267 /// Create an ordered list of Vars - initially empty
269 /// <returns></returns>
270 internal static VarList CreateVarList()
272 return new VarList();
276 /// Create an ordered list of Vars
278 /// <param name="vars"></param>
279 /// <returns></returns>
280 internal static VarList CreateVarList(IEnumerable<Var> vars)
282 return new VarList(vars);
287 internal VarMap CreateVarMap()
294 #region Table Helpers
296 private int NewTableId()
298 return m_tables.Count;
303 /// Create a table whose element type is "elementType"
305 /// <param name="elementType">type of each element (row) of the table</param>
306 /// <returns>a table definition object</returns>
307 internal static TableMD CreateTableDefinition(TypeUsage elementType)
309 return new TableMD(elementType, null);
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
316 /// <param name="extent">the metadata extent</param>
317 /// <returns>A new TableMD instance based on the extent</returns>
318 internal static TableMD CreateTableDefinition(EntitySetBase extent)
320 return new TableMD(TypeUsage.Create(extent.ElementType), extent);
324 /// Create a "flat" table definition object (ie) the table has one column
325 /// for each property of the specified row type
327 /// <param name="type">the shape of each row of the table</param>
328 /// <returns>the table definition</returns>
329 internal TableMD CreateFlatTableDefinition(RowType type)
331 return CreateFlatTableDefinition(type.Properties, new List<EdmMember>(), null);
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
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>
343 internal TableMD CreateFlatTableDefinition(IEnumerable<EdmProperty> properties, IEnumerable<EdmMember> keyMembers, EntitySetBase entitySet)
345 return new TableMD(properties, keyMembers, entitySet);
349 /// Creates a new table instance
351 /// <param name="tableMetadata">table metadata</param>
352 /// <returns>A new Table instance with columns as defined in the specified metadata</returns>
353 internal Table CreateTableInstance(TableMD tableMetadata)
355 Table t = new Table(this, tableMetadata, NewTableId());
365 /// All vars in the query
367 internal IEnumerable<Var> Vars
369 get { return m_vars.Where(v => v.VarType != VarType.NotValid); }
373 /// Access an existing variable in the query (by its id)
375 /// <param name="id">The ID of the variable to retrieve</param>
376 /// <returns>The variable with the specified ID</returns>
377 internal Var GetVar(int id)
379 Debug.Assert(m_vars[id].VarType != VarType.NotValid, "The var has been replaced by a different var and is no longer valid.");
385 /// Gets the ParameterVar that corresponds to a given named parameter
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>
389 internal ParameterVar GetParameter(string paramName)
391 return m_parameterMap[paramName];
398 private int NewVarId()
404 /// Creates a variable for a parameter in the query
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>
409 internal ParameterVar CreateParameterVar(string parameterName,
410 TypeUsage parameterType)
412 if (m_parameterMap.ContainsKey(parameterName))
413 throw new Exception("duplicate parameter name: " + parameterName);
414 ParameterVar v = new ParameterVar(NewVarId(), parameterType, parameterName);
416 m_parameterMap[parameterName] = v;
421 /// Creates a variable for the given parameter variable and replaces it in parameter map.
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>
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.
432 private ParameterVar ReplaceParameterVar(ParameterVar oldVar, Func<TypeUsage, TypeUsage> generateReplacementType)
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;
443 /// Creates a variable for the given enum parameter variable and replaces it in parameter map.
445 /// <param name="oldVar">Enum parameter variable that needs to replaced.</param>
446 /// <returns>A new ParameterVar instance created of <paramref name="oldVar"/>.</returns>
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.
453 internal ParameterVar ReplaceEnumParameterVar(ParameterVar oldVar)
455 return ReplaceParameterVar(oldVar, t => TypeHelpers.CreateEnumUnderlyingTypeUsage(t));
459 /// Creates a variable for the given spatial parameter variable and replaces it in parameter map.
461 /// <param name="oldVar">Spatial parameter variable that needs to replaced.</param>
462 /// <returns>A new ParameterVar instance created of <paramref name="oldVar"/>.</returns>
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.
469 internal ParameterVar ReplaceStrongSpatialParameterVar(ParameterVar oldVar)
471 return ReplaceParameterVar(oldVar, t => TypeHelpers.CreateSpatialUnionTypeUsage(t));
476 /// Creates a new var for a table column
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>
481 internal ColumnVar CreateColumnVar(Table table, ColumnMD columnMD)
483 // create a new column var now
484 ColumnVar c = new ColumnVar(NewVarId(), table, columnMD);
485 table.Columns.Add(c);
491 /// Creates a computed var (ie) a variable that is computed by an expression
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>
495 internal ComputedVar CreateComputedVar(TypeUsage type)
497 ComputedVar v = new ComputedVar(NewVarId(), type);
503 /// Creates a SetOp Var of
505 /// <param name="type">Datatype of the Var</param>
506 /// <returns>A new SetOp Var with the specified result type</returns>
507 internal SetOpVar CreateSetOpVar(TypeUsage type)
509 SetOpVar v = new SetOpVar(NewVarId(), type);
516 #region Node Creation
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)
524 /// Creates a Node with zero children
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>
528 internal Node CreateNode(Op op)
530 return this.CreateNode(op, new List<Node>());
534 /// Creates a node with a single child Node
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>
539 internal Node CreateNode(Op op, Node arg1)
541 List<Node> l = new List<Node>();
543 return this.CreateNode(op, l);
547 /// Creates a node with two child Nodes
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>
553 internal Node CreateNode(Op op, Node arg1, Node arg2)
555 List<Node> l = new List<Node>();
556 l.Add(arg1); l.Add(arg2);
557 return this.CreateNode(op, l);
561 /// Creates a node with 3 child Nodes
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>
568 internal Node CreateNode(Op op, Node arg1, Node arg2, Node arg3)
570 List<Node> l = new List<Node>();
571 l.Add(arg1); l.Add(arg2); l.Add(arg3);
572 return this.CreateNode(op, l);
576 /// Create a Node with the specified list of child Nodes
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>
581 internal Node CreateNode(Op op, IList<Node> args)
583 return new Node(m_nextNodeId++, op, new List<Node>(args));
587 /// Create a Node with the specified list of child Nodes
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>
592 internal Node CreateNode(Op op, List<Node> args)
594 return new Node(m_nextNodeId++, op, args);
602 /// Creates a new ConstantOp
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>
607 internal ConstantBaseOp CreateConstantOp(TypeUsage type, object value)
609 // create a NullOp if necessary
612 return new NullOp(type);
614 // Identify "safe" constants - the only safe ones are boolean (and we should
615 // probably include ints eventually)
616 else if (TypeSemantics.IsBooleanType(type))
618 return new InternalConstantOp(type, value);
622 return new ConstantOp(type, value);
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
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>
634 internal InternalConstantOp CreateInternalConstantOp(TypeUsage type, object value)
636 return new InternalConstantOp(type, value);
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
643 /// <returns></returns>
644 internal NullSentinelOp CreateNullSentinelOp()
646 return new NullSentinelOp(this.IntegerType, 1);
650 /// An "internal" null constant
652 /// <param name="type">datatype of the null constant</param>
653 /// <returns>a new "internal" null constant op</returns>
654 internal NullOp CreateNullOp(TypeUsage type)
656 return new NullOp(type);
660 /// Create a constant predicateOp
662 /// <param name="value">value of the constant predicate</param>
663 /// <returns></returns>
664 internal ConstantPredicateOp CreateConstantPredicateOp(bool value)
666 return value ? m_trueOp : m_falseOp;
670 /// Create a constant predicate with value=true
672 /// <returns></returns>
673 internal ConstantPredicateOp CreateTrueOp()
678 /// Create a constant predicateOp with the value false
680 /// <returns></returns>
681 internal ConstantPredicateOp CreateFalseOp()
687 /// Creates a new FunctionOp
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>
691 internal FunctionOp CreateFunctionOp(EdmFunction function)
693 return new FunctionOp(function);
697 /// Creates a new TreatOp
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>
701 internal TreatOp CreateTreatOp(TypeUsage type)
703 return new TreatOp(type, false);
707 /// Create a "dummy" treatOp (i.e.) we can actually ignore the treatOp.
709 /// <param name="type"></param>
710 /// <returns></returns>
711 internal TreatOp CreateFakeTreatOp(TypeUsage type)
713 return new TreatOp(type, true);
717 /// Creates a new IsOfOp, which tests if the argument is of the specified type or a promotable type
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>
721 internal IsOfOp CreateIsOfOp(TypeUsage isOfType)
723 return new IsOfOp(isOfType, false/*only*/, m_boolType);
726 /// Creates a new IsOfOp, which tests if the argument is of the specified type (and only the specified type)
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>
730 internal IsOfOp CreateIsOfOnlyOp(TypeUsage isOfType)
732 return new IsOfOp(isOfType, true /* "only" */, m_boolType);
736 /// Creates a new CastOp
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>
740 internal CastOp CreateCastOp(TypeUsage type)
742 return new CastOp(type);
746 /// Creates a new SoftCastOp and casts the input to the desired type.
748 /// The caller is expected to determine if the cast is necessary or not
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>
752 internal SoftCastOp CreateSoftCastOp(TypeUsage type)
754 return new SoftCastOp(type);
758 /// Creates a new ComparisonOp of the specified type
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>
762 internal ComparisonOp CreateComparisonOp(OpType opType)
764 return new ComparisonOp(opType, this.BooleanType);
768 /// Creates a new LikeOp
770 /// <returns>The new LikeOp</returns>
771 internal LikeOp CreateLikeOp()
773 return new LikeOp(this.BooleanType);
777 /// Creates a new ConditionalOp of the specified type
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>
781 internal ConditionalOp CreateConditionalOp(OpType opType)
783 return new ConditionalOp(opType, this.BooleanType);
787 /// Creates a new CaseOp
789 /// <param name="type">The result type of the CaseOp</param>
790 /// <returns>A new CaseOp with the specified result type</returns>
791 internal CaseOp CreateCaseOp(TypeUsage type)
793 return new CaseOp(type);
797 /// Creates a new AggregateOp
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>
802 internal AggregateOp CreateAggregateOp(EdmFunction aggFunc, bool distinctAgg)
804 return new AggregateOp(aggFunc, distinctAgg);
808 /// Creates a named type constructor
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>
812 internal NewInstanceOp CreateNewInstanceOp(TypeUsage type)
814 return new NewInstanceOp(type);
818 /// Build out a new NewEntityOp constructing the entity <paramref name="type"/> scoped to the <paramref name="entitySet"/>.
820 internal NewEntityOp CreateScopedNewEntityOp(TypeUsage type, List<RelProperty> relProperties, EntitySet entitySet)
822 return new NewEntityOp(type, relProperties, true, entitySet);
826 /// Build out a new NewEntityOp constructing the uscoped entity <paramref name="type"/>.
828 internal NewEntityOp CreateNewEntityOp(TypeUsage type, List<RelProperty> relProperties)
830 return new NewEntityOp(type, relProperties, false, null);
834 /// Create a discriminated named type constructor
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>
841 internal DiscriminatedNewEntityOp CreateDiscriminatedNewEntityOp(TypeUsage type, ExplicitDiscriminatorMap discriminatorMap,
842 EntitySet entitySet, List<RelProperty> relProperties)
844 return new DiscriminatedNewEntityOp(type, discriminatorMap, entitySet, relProperties);
848 /// Creates a multiset constructor
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>
852 internal NewMultisetOp CreateNewMultisetOp(TypeUsage type)
854 return new NewMultisetOp(type);
858 /// Creates a record constructor
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>
862 internal NewRecordOp CreateNewRecordOp(TypeUsage type)
864 return new NewRecordOp(type);
868 /// Creates a record constructor
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>
872 internal NewRecordOp CreateNewRecordOp(RowType type)
874 return new NewRecordOp(TypeUsage.Create(type));
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.
883 /// <param name="type"></param>
884 /// <param name="fields"></param>
885 /// <returns></returns>
886 internal NewRecordOp CreateNewRecordOp(TypeUsage type,
887 List<EdmProperty> fields)
889 return new NewRecordOp(type, fields);
893 /// Creates a new VarRefOp
895 /// <param name="v">The variable to reference</param>
896 /// <returns>A new VarRefOp that references the specified variable</returns>
897 internal VarRefOp CreateVarRefOp(Var v)
899 return new VarRefOp(v);
902 /// Creates a new ArithmeticOp of the specified type
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>
907 internal ArithmeticOp CreateArithmeticOp(OpType opType, TypeUsage type)
909 return new ArithmeticOp(opType, type);
913 /// Creates a new PropertyOp
915 /// <param name="prop">EdmProperty metadata that specifies the property</param>
916 /// <returns>A new PropertyOp that references the specified property metadata</returns>
917 internal PropertyOp CreatePropertyOp(EdmMember prop)
920 // Track all rel-properties
922 NavigationProperty navProp = prop as NavigationProperty;
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);
931 // Actually create the propertyOp
932 return new PropertyOp(Helper.GetModelTypeUsage(prop), prop);
936 /// Create a "relationship" propertyOp
938 /// <param name="prop">the relationship property</param>
939 /// <returns>a RelPropertyOp</returns>
940 internal RelPropertyOp CreateRelPropertyOp(RelProperty prop)
942 AddRelPropertyReference(prop);
943 return new RelPropertyOp(prop.ToEnd.TypeUsage, prop);
947 /// Creates a new RefOp
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>
952 internal RefOp CreateRefOp(EntitySet entitySet, TypeUsage type)
954 return new RefOp(entitySet, type);
958 /// Creates a new ExistsOp
960 /// <returns>A new ExistsOp</returns>
961 internal ExistsOp CreateExistsOp()
963 return new ExistsOp(this.BooleanType);
966 /// Creates a new ElementOp
968 /// <param name="type">Type metadata that specifies the result (element) type</param>
969 /// <returns>A new ElementOp with the specified result type</returns>
970 internal ElementOp CreateElementOp(TypeUsage type)
972 return new ElementOp(type);
976 /// Creates a new GetEntityRefOp: a ref-extractor (from an entity instance) Op
978 /// <param name="type">Type metadata that specifies the result type</param>
979 /// <returns>A new GetEntityKeyOp with the specified result type</returns>
980 internal GetEntityRefOp CreateGetEntityRefOp(TypeUsage type)
982 return new GetEntityRefOp(type);
985 /// Creates a new GetRefKeyOp: a key-extractor (from a ref instance) Op
987 /// <param name="type">Type metadata that specifies the result type</param>
988 /// <returns>A new GetRefKeyOp with the specified result type</returns>
989 internal GetRefKeyOp CreateGetRefKeyOp(TypeUsage type)
991 return new GetRefKeyOp(type);
995 /// Creates a new CollectOp
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>
999 internal CollectOp CreateCollectOp(TypeUsage type)
1001 return new CollectOp(type);
1005 /// Create a DerefOp
1007 /// <param name="type">Entity type of the target entity</param>
1008 /// <returns>a DerefOp</returns>
1009 internal DerefOp CreateDerefOp(TypeUsage type)
1011 return new DerefOp(type);
1015 /// Create a new NavigateOp node
1017 /// <param name="type">the output type of the navigateOp</param>
1018 /// <param name="relProperty">the relationship property</param>
1019 /// <returns>the navigateOp</returns>
1020 internal NavigateOp CreateNavigateOp(TypeUsage type, RelProperty relProperty)
1022 // keep track of rel-properties
1023 AddRelPropertyReference(relProperty);
1024 return new NavigateOp(type, relProperty);
1029 #region AncillaryOps
1032 /// Creates a VarDefListOp
1034 /// <returns>A new VarDefListOp</returns>
1035 internal VarDefListOp CreateVarDefListOp()
1037 return VarDefListOp.Instance;
1040 /// Creates a VarDefOp (for a computed var)
1042 /// <param name="v">The computed var</param>
1043 /// <returns>A new VarDefOp that references the computed var</returns>
1044 internal VarDefOp CreateVarDefOp(Var v)
1046 return new VarDefOp(v);
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
1055 /// <param name="definingExpr"></param>
1056 /// <param name="computedVar">new Var produced</param>
1057 /// <returns></returns>
1058 internal Node CreateVarDefNode(Node definingExpr, out Var computedVar)
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);
1070 /// Creates a VarDefListOp with a single child - a VarDefOp created as in the function
1073 /// <param name="definingExpr"></param>
1074 /// <param name="computedVar">the computed Var produced</param>
1075 /// <returns></returns>
1076 internal Node CreateVarDefListNode(Node definingExpr, out Var computedVar)
1078 Node varDefNode = this.CreateVarDefNode(definingExpr, out computedVar);
1079 VarDefListOp op = this.CreateVarDefListOp();
1080 Node varDefListNode = this.CreateNode(op, varDefNode);
1081 return varDefListNode;
1088 /// Creates a new ScanTableOp
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>
1092 internal ScanTableOp CreateScanTableOp(TableMD tableMetadata)
1094 Table table = this.CreateTableInstance(tableMetadata);
1095 return CreateScanTableOp(table);
1098 /// A variant of the above
1100 /// <param name="table">The table instance</param>
1101 /// <returns>a new ScanTableOp</returns>
1102 internal ScanTableOp CreateScanTableOp(Table table)
1104 return new ScanTableOp(table);
1108 /// Creates an instance of a ScanViewOp
1110 /// <param name="table">the table instance</param>
1111 /// <returns>a new ScanViewOp</returns>
1112 internal ScanViewOp CreateScanViewOp(Table table)
1114 return new ScanViewOp(table);
1117 /// Creates an instance of a ScanViewOp
1119 /// <param name="tableMetadata">the table metadata</param>
1120 /// <returns>a new ScanViewOp</returns>
1121 internal ScanViewOp CreateScanViewOp(TableMD tableMetadata)
1123 Table table = this.CreateTableInstance(tableMetadata);
1124 return this.CreateScanViewOp(table);
1127 /// Creates a new UnnestOp, which creates a streaming result from a scalar (non-RelOp) value
1129 /// <param name="v">The Var that indicates the value to unnest</param>
1130 /// <returns>A new UnnestOp that targets the specified Var</returns>
1131 internal UnnestOp CreateUnnestOp(Var v)
1133 Table t = this.CreateTableInstance(Command.CreateTableDefinition(TypeHelpers.GetEdmType<CollectionType>(v.Type).TypeUsage));
1134 return CreateUnnestOp(v, t);
1138 /// Creates a new UnnestOp - a variant of the above with the Table supplied
1140 /// <param name="v">the unnest Var</param>
1141 /// <param name="t">the table instance</param>
1142 /// <returns>a new UnnestOp</returns>
1143 internal UnnestOp CreateUnnestOp(Var v, Table t)
1145 return new UnnestOp(v, t);
1149 /// Creates a new FilterOp
1151 /// <returns>A new FilterOp</returns>
1152 internal FilterOp CreateFilterOp()
1154 return FilterOp.Instance;
1158 /// Creates a new ProjectOp
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>
1162 internal ProjectOp CreateProjectOp(VarVec vars)
1164 return new ProjectOp(vars);
1167 /// A variant of the above where the ProjectOp produces exactly one var
1169 /// <param name="v"></param>
1170 /// <returns></returns>
1171 internal ProjectOp CreateProjectOp(Var v)
1173 VarVec varSet = this.CreateVarVec();
1175 return new ProjectOp(varSet);
1181 /// Creates a new InnerJoinOp
1183 /// <returns>A new InnerJoinOp</returns>
1184 internal InnerJoinOp CreateInnerJoinOp()
1186 return InnerJoinOp.Instance;
1190 /// Creates a new LeftOuterJoinOp
1192 /// <returns>A new LeftOuterJoinOp</returns>
1193 internal LeftOuterJoinOp CreateLeftOuterJoinOp()
1195 return LeftOuterJoinOp.Instance;
1199 /// Creates a new FullOuterJoinOp
1201 /// <returns>A new FullOuterJoinOp</returns>
1202 internal FullOuterJoinOp CreateFullOuterJoinOp()
1204 return FullOuterJoinOp.Instance;
1208 /// Creates a new CrossJoinOp
1210 /// <returns>A new CrossJoinOp</returns>
1211 internal CrossJoinOp CreateCrossJoinOp()
1213 return CrossJoinOp.Instance;
1221 /// Creates a new CrossApplyOp
1223 /// <returns>A new CrossApplyOp</returns>
1224 internal CrossApplyOp CreateCrossApplyOp()
1226 return CrossApplyOp.Instance;
1229 /// Creates a new OuterApplyOp
1231 /// <returns>A new OuterApplyOp</returns>
1232 internal OuterApplyOp CreateOuterApplyOp()
1234 return OuterApplyOp.Instance;
1242 /// Creates a new SortKey with the specified var, order and collation
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>
1248 internal static SortKey CreateSortKey(Var v, bool asc, string collation)
1250 return new SortKey(v, asc, collation);
1253 /// Creates a new SortKey with the specified var and order
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>
1258 internal static SortKey CreateSortKey(Var v, bool asc)
1260 return new SortKey(v, asc, "");
1264 /// Creates a new SortKey with the specified var
1266 /// <param name="v">The variable to sort on</param>
1267 /// <returns>A new SortKey with the specified var</returns>
1268 internal static SortKey CreateSortKey(Var v)
1270 return new SortKey(v, true, "");
1276 /// Creates a new SortOp
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>
1280 internal SortOp CreateSortOp(List<SortKey> sortKeys)
1282 return new SortOp(sortKeys);
1286 /// Creates a new ConstrainedSortOp
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>
1290 internal ConstrainedSortOp CreateConstrainedSortOp(List<SortKey> sortKeys)
1292 return new ConstrainedSortOp(sortKeys, false);
1296 /// Creates a new ConstrainedSortOp
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>
1301 internal ConstrainedSortOp CreateConstrainedSortOp(List<SortKey> sortKeys, bool withTies)
1303 return new ConstrainedSortOp(sortKeys, withTies);
1307 /// Creates a new GroupByOp
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>
1312 internal GroupByOp CreateGroupByOp(VarVec gbyKeys, VarVec outputs)
1314 return new GroupByOp(gbyKeys, outputs);
1318 /// Creates a new GroupByIntoOp
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>
1324 internal GroupByIntoOp CreateGroupByIntoOp(VarVec gbyKeys, VarVec inputs, VarVec outputs)
1326 return new GroupByIntoOp(gbyKeys, inputs, outputs);
1330 /// Creates a new DistinctOp
1331 /// <param name="keyVars">list of key vars</param>
1333 /// <returns>A new DistinctOp</returns>
1334 internal DistinctOp CreateDistinctOp(VarVec keyVars)
1336 return new DistinctOp(keyVars);
1339 /// An overload of the above - where the distinct has exactly one key
1341 /// <param name="keyVar"></param>
1342 /// <returns></returns>
1343 internal DistinctOp CreateDistinctOp(Var keyVar)
1345 return new DistinctOp(this.CreateVarVec(keyVar));
1349 /// Creates a new UnionAllOp
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>
1354 internal UnionAllOp CreateUnionAllOp(VarMap leftMap, VarMap rightMap)
1356 return CreateUnionAllOp(leftMap, rightMap, null);
1360 /// Creates a new UnionAllOp, with a branch descriminator.
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>
1366 internal UnionAllOp CreateUnionAllOp(VarMap leftMap, VarMap rightMap, Var branchDiscriminator)
1368 Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch");
1369 VarVec vec = this.CreateVarVec();
1370 foreach (Var v in leftMap.Keys)
1374 return new UnionAllOp(vec, leftMap, rightMap, branchDiscriminator);
1378 /// Creates a new IntersectOp
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>
1383 internal IntersectOp CreateIntersectOp(VarMap leftMap, VarMap rightMap)
1385 Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch");
1386 VarVec vec = this.CreateVarVec();
1387 foreach (Var v in leftMap.Keys)
1391 return new IntersectOp(vec, leftMap, rightMap);
1394 /// Creates a new ExceptOp
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>
1399 internal ExceptOp CreateExceptOp(VarMap leftMap, VarMap rightMap)
1401 Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch");
1402 VarVec vec = this.CreateVarVec();
1403 foreach (Var v in leftMap.Keys)
1407 return new ExceptOp(vec, leftMap, rightMap);
1411 /// Create a single-row-op (the relop analog of Element)
1413 /// <returns></returns>
1414 internal SingleRowOp CreateSingleRowOp()
1416 return SingleRowOp.Instance;
1420 /// Create a SingleRowTableOp - a table with exactly one row (and no columns)
1422 /// <returns></returns>
1423 internal SingleRowTableOp CreateSingleRowTableOp()
1425 return SingleRowTableOp.Instance;
1432 /// Create a PhysicalProjectOp - with a columnMap describing the output
1434 /// <param name="outputVars">list of output vars</param>
1435 /// <param name="columnMap">columnmap describing the output element</param>
1436 /// <returns></returns>
1437 internal PhysicalProjectOp CreatePhysicalProjectOp(VarList outputVars, SimpleCollectionColumnMap columnMap)
1439 return new PhysicalProjectOp(outputVars, columnMap);
1442 /// Create a physicalProjectOp - with a single column output
1444 /// <param name="outputVar">the output element</param>
1445 /// <returns></returns>
1446 internal PhysicalProjectOp CreatePhysicalProjectOp(Var outputVar)
1448 VarList varList = Command.CreateVarList();
1449 varList.Add(outputVar);
1450 VarRefColumnMap varRefColumnMap = new VarRefColumnMap(outputVar);
1452 SimpleCollectionColumnMap collectionColumnMap = new SimpleCollectionColumnMap(
1453 TypeUtils.CreateCollectionType(varRefColumnMap.Type), // type
1455 varRefColumnMap, // element map
1456 new SimpleColumnMap[0], // keys
1457 new SimpleColumnMap[0]); // foreign keys
1458 return CreatePhysicalProjectOp(varList, collectionColumnMap);
1462 /// Another overload - with an additional discriminatorValue.
1463 /// Should this be a subtype instead?
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>
1472 internal static CollectionInfo CreateCollectionInfo(Var collectionVar, ColumnMap columnMap, VarList flattenedElementVars, VarVec keys, List<InternalTrees.SortKey> sortKeys, object discriminatorValue)
1474 return new CollectionInfo(collectionVar, columnMap, flattenedElementVars, keys, sortKeys, discriminatorValue);
1478 /// Create a singleStreamNestOp
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>
1487 internal SingleStreamNestOp CreateSingleStreamNestOp(VarVec keys,
1488 List<SortKey> prefixSortKeys, List<SortKey> postfixSortKeys,
1490 List<CollectionInfo> collectionInfoList, Var discriminatorVar)
1492 return new SingleStreamNestOp(keys, prefixSortKeys, postfixSortKeys, outputVars, collectionInfoList, discriminatorVar);
1496 /// Create a MultiStreamNestOp
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>
1502 internal MultiStreamNestOp CreateMultiStreamNestOp(List<SortKey> prefixSortKeys, VarVec outputVars,
1503 List<CollectionInfo> collectionInfoList)
1505 return new MultiStreamNestOp(prefixSortKeys, outputVars, collectionInfoList);
1511 /// Get auxilliary information for a Node
1513 /// <param name="n">the node</param>
1514 /// <returns>node info for this node</returns>
1515 internal NodeInfo GetNodeInfo(Node n)
1517 return n.GetNodeInfo(this);
1521 /// Get extended node information for a RelOpNode
1523 /// <param name="n">the node</param>
1524 /// <returns>extended node info for this node</returns>
1525 internal ExtendedNodeInfo GetExtendedNodeInfo(Node n)
1527 return n.GetExtendedNodeInfo(this);
1530 /// Recompute the nodeinfo for a node, but only if has already been computed
1532 /// <param name="n">Node in question</param>
1533 internal void RecomputeNodeInfo(Node n)
1535 m_nodeInfoVisitor.RecomputeNodeInfo(n);
1541 /// Pulls up keys if necessary and gets the key information for a Node
1543 /// <param name="n">node</param>
1544 /// <returns>key information</returns>
1545 internal KeyVec PullupKeys(Node n)
1547 return m_keyPullupVisitor.GetKeys(n);
1551 #region Type Comparisons
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
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.
1563 /// <param name="x"></param>
1564 /// <param name="y"></param>
1565 /// <returns>true, if the types are "equal"</returns>
1566 internal static bool EqualTypes(TypeUsage x, TypeUsage y)
1568 return PlanCompiler.TypeUsageEqualityComparer.Instance.Equals(x, y);
1571 /// Check to see if two types are considered "equal" for the purposes
1572 /// of the plan compiler
1574 /// <param name="x"></param>
1575 /// <param name="y"></param>
1576 /// <returns>true, if the types are "equal"</returns>
1577 internal static bool EqualTypes(EdmType x, EdmType y)
1579 return PlanCompiler.TypeUsageEqualityComparer.Equals(x, y);
1583 #region Builder Methods
1585 /// Builds out a UNION-ALL ladder from a sequence of node,var pairs.
1586 /// Assumption: Each node produces exactly one Var
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)
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>
1598 internal void BuildUnionAllLadder(
1599 IList<Node> inputNodes, IList<Var> inputVars,
1600 out Node resultNode, out IList<Var> resultVars)
1602 if (inputNodes.Count == 0)
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);
1612 if (inputNodes.Count == 1)
1614 resultNode = inputNodes[0];
1615 resultVars = inputVars;
1619 List<Var> unionAllVars = new List<Var>();
1621 Node unionAllNode = inputNodes[0];
1622 for (int j = 0; j < varPerNode; j++)
1624 unionAllVars.Add(inputVars[j]);
1627 for (int i = 1; i < inputNodes.Count; i++)
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++)
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]);
1639 Op unionAllOp = this.CreateUnionAllOp(leftVarMap, rightVarMap);
1640 unionAllNode = this.CreateNode(unionAllOp, unionAllNode, inputNodes[i]);
1641 unionAllVars = setOpVars;
1644 resultNode = unionAllNode;
1645 resultVars = unionAllVars;
1649 /// A simplified version of the method above - each branch can produce only one var
1651 /// <param name="inputNodes"></param>
1652 /// <param name="inputVars"></param>
1653 /// <param name="resultNode"></param>
1654 /// <param name="resultVar"></param>
1655 internal void BuildUnionAllLadder(IList<Node> inputNodes, IList<Var> inputVars,
1656 out Node resultNode, out Var resultVar)
1658 Debug.Assert(inputNodes.Count == inputVars.Count, "Count mismatch:" + inputNodes.Count + "," + inputVars.Count);
1660 BuildUnionAllLadder(inputNodes, inputVars, out resultNode, out varList);
1661 if (varList != null && varList.Count > 0)
1663 resultVar = varList[0];
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)
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>
1681 internal Node BuildProject(Node inputNode, IEnumerable<Var> inputVars,
1682 IEnumerable<Node> computedExpressions)
1684 Debug.Assert(inputNode.Op.IsRelOp, "Expected a RelOp. Found " + inputNode.Op.OpType);
1686 VarDefListOp varDefListOp = this.CreateVarDefListOp();
1687 Node varDefListNode = this.CreateNode(varDefListOp);
1688 VarVec projectVars = this.CreateVarVec(inputVars);
1689 foreach (Node expr in computedExpressions)
1691 Var v = this.CreateComputedVar(expr.Op.Type);
1693 VarDefOp varDefOp = this.CreateVarDefOp(v);
1694 Node varDefNode = this.CreateNode(varDefOp, expr);
1695 varDefListNode.Children.Add(varDefNode);
1697 Node projectNode = this.CreateNode(
1698 this.CreateProjectOp(projectVars),
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
1708 /// The single output Var is returned in the "outputVar" parameter
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>
1714 internal Node BuildProject(Node input, Node computedExpression, out Var projectVar)
1716 Node projectNode = BuildProject(input, new Var[] { }, new Node[] { computedExpression });
1717 projectVar = ((ProjectOp)projectNode.Op).Outputs.First;
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).
1725 /// Further more, "update" the result element type to be the desired type.
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
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>
1738 internal void BuildOfTypeTree(Node inputNode, Var inputVar, TypeUsage desiredType, bool includeSubtypes,
1739 out Node resultNode, out Var resultVar)
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);
1745 resultNode = BuildFakeTreatProject(filterNode, inputVar, desiredType, out resultVar);
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.
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>
1756 internal Node BuildFakeTreatProject(Node inputNode, Var inputVar, TypeUsage desiredType, out Var resultVar)
1758 Node treatNode = this.CreateNode(this.CreateFakeTreatOp(desiredType),
1759 this.CreateNode(this.CreateVarRefOp(inputVar)));
1760 Node resultNode = this.BuildProject(inputNode, treatNode, out resultVar);
1765 /// Build a comparisonOp over the input arguments. Build SoftCasts over the inputs, if we need
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>
1772 internal Node BuildComparison(OpType opType, Node arg0, Node arg1)
1774 if (!Command.EqualTypes(arg0.Op.Type, arg1.Op.Type))
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))
1780 arg0 = this.CreateNode(this.CreateSoftCastOp(commonType), arg0);
1782 if (!EqualTypes(commonType, arg1.Op.Type))
1784 arg1 = this.CreateNode(this.CreateSoftCastOp(commonType), arg1);
1787 Node newNode = this.CreateNode(this.CreateComparisonOp(opType), arg0, arg1);
1792 /// Build up a CollectOp over a relop tree
1794 /// <param name="relOpNode">the relop tree</param>
1795 /// <param name="relOpVar">the single output var from the relop tree</param>
1796 /// <returns></returns>
1797 internal Node BuildCollect(Node relOpNode, Var relOpVar)
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);
1806 #region Rel Properties
1808 /// Mark this rel-property as "referenced" in the current query, if the target
1809 /// end has multiplicity of one (or zero_or_one)
1811 /// <param name="relProperty">the rel-property</param>
1812 private void AddRelPropertyReference(RelProperty relProperty)
1814 if (relProperty.ToEnd.RelationshipMultiplicity != RelationshipMultiplicity.Many &&
1815 !m_referencedRelProperties.Contains(relProperty))
1817 m_referencedRelProperties.Add(relProperty);
1822 /// The set of referenced rel properties in the current query
1824 internal HashSet<RelProperty> ReferencedRelProperties
1826 get { return m_referencedRelProperties; }
1830 /// Is this rel-property referenced in the query so far
1832 /// <param name="relProperty">the rel-property</param>
1833 /// <returns>true, if the rel property was referenced in the query</returns>
1834 internal bool IsRelPropertyReferenced(RelProperty relProperty)
1836 bool ret = m_referencedRelProperties.Contains(relProperty);