You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			1845 lines
		
	
	
		
			75 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1845 lines
		
	
	
		
			75 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //---------------------------------------------------------------------
 | |
| // <copyright file="Command.cs" company="Microsoft">
 | |
| //      Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| // </copyright>
 | |
| //
 | |
| // @owner  Microsoft
 | |
| // @backupOwner Microsoft
 | |
| //---------------------------------------------------------------------
 | |
| 
 | |
| using System.Collections.Generic;
 | |
| using System.Data.Common;
 | |
| using System.Data.Metadata.Edm;
 | |
| using System.Data.Query.PlanCompiler;
 | |
| using System.Diagnostics;
 | |
| using System.Linq;
 | |
| 
 | |
| namespace System.Data.Query.InternalTrees
 | |
| {
 | |
|     /// <summary>
 | |
|     /// The Command object encapsulates all information relating to a single command.
 | |
|     /// It includes the expression tree in question, as well as the parameters to the
 | |
|     /// command.
 | |
|     /// Additionally, the Command class serves as a factory for building up different
 | |
|     /// nodes and Ops. Every node in the tree has a unique id, and this is enforced by
 | |
|     /// the node factory methods
 | |
|     /// </summary>
 | |
|     internal class Command
 | |
|     {
 | |
|         #region private state
 | |
|         private Dictionary<string, ParameterVar> m_parameterMap;
 | |
|         private List<Var> m_vars;
 | |
|         private List<Table> m_tables;
 | |
|         private Node m_root;
 | |
|         private MetadataWorkspace m_metadataWorkspace;
 | |
|         private TypeUsage m_boolType;
 | |
|         private TypeUsage m_intType;
 | |
|         private TypeUsage m_stringType;
 | |
|         private ConstantPredicateOp m_trueOp;
 | |
|         private ConstantPredicateOp m_falseOp;
 | |
|         private NodeInfoVisitor m_nodeInfoVisitor;
 | |
|         private PlanCompiler.KeyPullup m_keyPullupVisitor;
 | |
|         private int m_nextNodeId;
 | |
|         private int m_nextBranchDiscriminatorValue = 1000;
 | |
| 
 | |
|         private bool m_disableVarVecEnumCaching;
 | |
|         private Stack<VarVec.VarVecEnumerator> m_freeVarVecEnumerators;
 | |
|         private Stack<VarVec> m_freeVarVecs;
 | |
|         
 | |
| 
 | |
|         // set of referenced rel properties in this query
 | |
|         private HashSet<RelProperty> m_referencedRelProperties;
 | |
|         #endregion
 | |
| 
 | |
|         #region constructors
 | |
|         /// <summary>
 | |
|         /// Creates a new command
 | |
|         /// </summary>
 | |
|         internal Command(MetadataWorkspace metadataWorkspace)
 | |
|         {
 | |
|             m_parameterMap = new Dictionary<string, ParameterVar>();
 | |
|             m_vars = new List<Var>();
 | |
|             m_tables = new List<Table>();
 | |
|             m_metadataWorkspace = metadataWorkspace;
 | |
|             if(!TryGetPrimitiveType(PrimitiveTypeKind.Boolean, out m_boolType))
 | |
|             {
 | |
|                 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderBooleanType);
 | |
|             }
 | |
|             if (!TryGetPrimitiveType(PrimitiveTypeKind.Int32, out m_intType))
 | |
|             {
 | |
|                 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderIntegerType);
 | |
|             }
 | |
|             if (!TryGetPrimitiveType(PrimitiveTypeKind.String, out m_stringType))
 | |
|             {
 | |
|                 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderStringType);
 | |
|             }
 | |
|             m_trueOp = new ConstantPredicateOp(m_boolType, true);
 | |
|             m_falseOp = new ConstantPredicateOp(m_boolType, false);
 | |
|             m_nodeInfoVisitor = new NodeInfoVisitor(this);
 | |
|             m_keyPullupVisitor = new PlanCompiler.KeyPullup(this);
 | |
| 
 | |
|             // FreeLists
 | |
|             m_freeVarVecEnumerators = new Stack<VarVec.VarVecEnumerator>();
 | |
|             m_freeVarVecs = new Stack<VarVec>();
 | |
| 
 | |
|             m_referencedRelProperties = new HashSet<RelProperty>();
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region public methods
 | |
|         /// <summary>
 | |
|         /// Gets the metadata workspace associated with this command
 | |
|         /// </summary>
 | |
|         internal MetadataWorkspace MetadataWorkspace { get { return m_metadataWorkspace; } }
 | |
|                 
 | |
|         /// <summary>
 | |
|         /// Gets/sets the root node of the query
 | |
|         /// </summary>
 | |
|         internal Node Root { get { return m_root; } set { m_root = value; } }
 | |
| 
 | |
|         internal void DisableVarVecEnumCaching() { m_disableVarVecEnumCaching = true; } 
 | |
|                 
 | |
|         /// <summary>
 | |
|         /// Returns the next value for a UnionAll BranchDiscriminator.
 | |
|         /// </summary>
 | |
|         internal int NextBranchDiscriminatorValue { get { return m_nextBranchDiscriminatorValue++; } }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Returns the next value for a node id, without incrementing it. 
 | |
|         /// </summary>
 | |
|         internal int NextNodeId { get { return m_nextNodeId; } }
 | |
| 
 | |
|         #region Metadata Helpers
 | |
|         /// <summary>
 | |
|         /// Helper routine to get the metadata representation for the bool type
 | |
|         /// </summary>
 | |
|         internal TypeUsage BooleanType
 | |
|         {
 | |
|             get { return m_boolType; }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Helper routine to get the metadata representation of the int type
 | |
|         /// </summary>
 | |
|         internal TypeUsage IntegerType
 | |
|         {
 | |
|             get { return m_intType; }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Helper routine to get the metadata representation of the string type
 | |
|         /// </summary>
 | |
|         internal TypeUsage StringType
 | |
|         {
 | |
|             get { return m_stringType; }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Get the primitive type by primitive type kind
 | |
|         /// </summary>
 | |
|         /// <param name="modelType">EdmMetadata.PrimitiveTypeKind of the primitive type</param>
 | |
|         /// <param name="type">A TypeUsage that represents the specified primitive type</param>
 | |
|         /// <returns><c>True</c> if the specified primitive type could be retrieved; otherwise <c>false</c>.</returns>
 | |
|         private bool TryGetPrimitiveType(PrimitiveTypeKind modelType, out TypeUsage type)
 | |
|         {
 | |
|             type = null;
 | |
| 
 | |
|             if (modelType == PrimitiveTypeKind.String)
 | |
|             {
 | |
|                 type = TypeUsage.CreateStringTypeUsage(m_metadataWorkspace.GetModelPrimitiveType(modelType), 
 | |
|                                                        false /*unicode*/, 
 | |
|                                                        false /*fixed*/);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 type = m_metadataWorkspace.GetCanonicalModelTypeUsage(modelType);
 | |
|             }
 | |
| 
 | |
|             return (null != type);
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region VarVec Creation
 | |
|         /// <summary>
 | |
|         /// VarVec constructor
 | |
|         /// </summary>
 | |
|         /// <returns>A new, empty, VarVec</returns>
 | |
|         internal VarVec CreateVarVec()
 | |
|         {
 | |
|             VarVec vec;
 | |
|             if (m_freeVarVecs.Count == 0)
 | |
|             {
 | |
|                 vec = new VarVec(this);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 vec = m_freeVarVecs.Pop();
 | |
|                 vec.Clear();
 | |
|             }
 | |
|             return vec;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a VarVec with a single Var
 | |
|         /// </summary>
 | |
|         /// <param name="v"></param>
 | |
|         /// <returns></returns>
 | |
|         internal VarVec CreateVarVec(Var v)
 | |
|         {
 | |
|             VarVec varset = CreateVarVec();
 | |
|             varset.Set(v);
 | |
|             return varset;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a VarVec with the set of specified vars
 | |
|         /// </summary>
 | |
|         /// <param name="v"></param>
 | |
|         /// <returns></returns>
 | |
|         internal VarVec CreateVarVec(IEnumerable<Var> v)
 | |
|         {
 | |
|             VarVec vec = CreateVarVec();
 | |
|             vec.InitFrom(v);
 | |
|             return vec;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a new VarVec from the input VarVec
 | |
|         /// </summary>
 | |
|         /// <param name="v"></param>
 | |
|         /// <returns></returns>
 | |
|         internal VarVec CreateVarVec(VarVec v)
 | |
|         {
 | |
|             VarVec vec = CreateVarVec();
 | |
|             vec.InitFrom(v);
 | |
|             return vec;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Release a VarVec to the freelist
 | |
|         /// </summary>
 | |
|         /// <param name="vec"></param>
 | |
|         internal void ReleaseVarVec(VarVec vec)
 | |
|         {
 | |
|             m_freeVarVecs.Push(vec);
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region VarVecEnumerator
 | |
|         /// <summary>
 | |
|         /// Create a new enumerator for a VarVec; use a free one if its
 | |
|         /// available; otherwise, create a new one
 | |
|         /// </summary>
 | |
|         /// <param name="vec"></param>
 | |
|         /// <returns></returns>
 | |
|         internal VarVec.VarVecEnumerator GetVarVecEnumerator(VarVec vec)
 | |
|         {
 | |
|             VarVec.VarVecEnumerator enumerator;
 | |
| 
 | |
|             if (m_disableVarVecEnumCaching ||
 | |
|                 m_freeVarVecEnumerators.Count == 0)
 | |
|             {
 | |
|                 enumerator = new VarVec.VarVecEnumerator(vec);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 enumerator = m_freeVarVecEnumerators.Pop();
 | |
|                 enumerator.Init(vec);
 | |
|             }
 | |
|             return enumerator;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Release an enumerator; keep it in a local stack for future use
 | |
|         /// </summary>
 | |
|         /// <param name="enumerator"></param>
 | |
|         internal void ReleaseVarVecEnumerator(VarVec.VarVecEnumerator enumerator)
 | |
|         {
 | |
|             if (!m_disableVarVecEnumCaching)
 | |
|             {
 | |
|                 m_freeVarVecEnumerators.Push(enumerator);
 | |
|             }
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region VarList
 | |
|         /// <summary>
 | |
|         /// Create an ordered list of Vars - initially empty
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         internal static VarList CreateVarList()
 | |
|         {
 | |
|             return new VarList();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create an ordered list of Vars
 | |
|         /// </summary>
 | |
|         /// <param name="vars"></param>
 | |
|         /// <returns></returns>
 | |
|         internal static VarList CreateVarList(IEnumerable<Var> vars)
 | |
|         {
 | |
|             return new VarList(vars);
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region VarMap
 | |
|         internal VarMap CreateVarMap()
 | |
|         {
 | |
|             return new VarMap();
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Table Helpers
 | |
| 
 | |
|         private int NewTableId()
 | |
|         {
 | |
|             return m_tables.Count;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a table whose element type is "elementType"
 | |
|         /// </summary>
 | |
|         /// <param name="elementType">type of each element (row) of the table</param>
 | |
|         /// <returns>a table definition object</returns>
 | |
|         internal static TableMD CreateTableDefinition(TypeUsage elementType)
 | |
|         {
 | |
|             return new TableMD(elementType, null);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new table definition based on an extent. The element type
 | |
|         /// of the extent manifests as the single column of the table
 | |
|         /// </summary>
 | |
|         /// <param name="extent">the metadata extent</param>
 | |
|         /// <returns>A new TableMD instance based on the extent</returns>
 | |
|         internal static TableMD CreateTableDefinition(EntitySetBase extent)
 | |
|         {
 | |
|             return new TableMD(TypeUsage.Create(extent.ElementType), extent);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a "flat" table definition object (ie) the table has one column 
 | |
|         /// for each property of the specified row type
 | |
|         /// </summary>
 | |
|         /// <param name="type">the shape of each row of the table</param>
 | |
|         /// <returns>the table definition</returns>
 | |
|         internal TableMD CreateFlatTableDefinition(RowType type)
 | |
|         {
 | |
|             return CreateFlatTableDefinition(type.Properties, new List<EdmMember>(), null);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a "flat" table defintion. The table has one column for each property
 | |
|         /// specified, and the key columns of the table are those specified in the 
 | |
|         /// keyMembers parameter
 | |
|         /// </summary>
 | |
|         /// <param name="properties">list of columns for the table</param>
 | |
|         /// <param name="keyMembers">the key columns (if any)</param>
 | |
|         /// <param name="entitySet">(OPTIONAL) entityset corresponding to this table</param>
 | |
|         /// <returns></returns>
 | |
|         internal TableMD CreateFlatTableDefinition(IEnumerable<EdmProperty> properties, IEnumerable<EdmMember> keyMembers, EntitySetBase entitySet)
 | |
|         {
 | |
|             return new TableMD(properties, keyMembers, entitySet);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new table instance
 | |
|         /// </summary>
 | |
|         /// <param name="tableMetadata">table metadata</param>
 | |
|         /// <returns>A new Table instance with columns as defined in the specified metadata</returns>
 | |
|         internal Table CreateTableInstance(TableMD tableMetadata)
 | |
|         {
 | |
|             Table t = new Table(this, tableMetadata, NewTableId());
 | |
|             m_tables.Add(t);
 | |
|             return t;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Var Access
 | |
| 
 | |
|         /// <summary>
 | |
|         /// All vars in the query
 | |
|         /// </summary>
 | |
|         internal IEnumerable<Var> Vars
 | |
|         {
 | |
|             get { return m_vars.Where(v => v.VarType != VarType.NotValid); }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Access an existing variable in the query (by its id)
 | |
|         /// </summary>
 | |
|         /// <param name="id">The ID of the variable to retrieve</param>
 | |
|         /// <returns>The variable with the specified ID</returns>
 | |
|         internal Var GetVar(int id)
 | |
|         {
 | |
|             Debug.Assert(m_vars[id].VarType != VarType.NotValid, "The var has been replaced by a different var and is no longer valid.");
 | |
| 
 | |
|             return m_vars[id];
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets the ParameterVar that corresponds to a given named parameter
 | |
|         /// </summary>
 | |
|         /// <param name="paramName">The name of the parameter for which to retrieve the ParameterVar</param>
 | |
|         /// <returns>The ParameterVar that corresponds to the specified parameter</returns>
 | |
|         internal ParameterVar GetParameter(string paramName)
 | |
|         {
 | |
|             return m_parameterMap[paramName];
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Var Creation
 | |
| 
 | |
|         private int NewVarId()
 | |
|         {
 | |
|             return m_vars.Count;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a variable for a parameter in the query
 | |
|         /// </summary>
 | |
|         /// <param name="parameterName">The name of the parameter for which to create the var</param>
 | |
|         /// <param name="parameterType">The type of the parameter, and therefore the new var</param>
 | |
|         /// <returns>A new ParameterVar instance with the specified name and type</returns>
 | |
|         internal ParameterVar CreateParameterVar(string parameterName,
 | |
|             TypeUsage parameterType)
 | |
|         {
 | |
|             if (m_parameterMap.ContainsKey(parameterName))
 | |
|                 throw new Exception("duplicate parameter name: " + parameterName);
 | |
|             ParameterVar v = new ParameterVar(NewVarId(), parameterType, parameterName);
 | |
|             m_vars.Add(v);
 | |
|             m_parameterMap[parameterName] = v;
 | |
|             return v;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a variable for the given parameter variable and replaces it in parameter map.
 | |
|         /// </summary>
 | |
|         /// <param name="oldVar">Parameter variable that needs to replaced.</param>
 | |
|         /// <param name="generateReplacementType">Delegate that generates the replacement parameter's type.</param>
 | |
|         /// <returns>A new ParameterVar instance created of <paramref name="oldVar"/>.</returns>
 | |
|         /// <remarks>
 | |
|         /// This method should be used only to replace external enum or strong spatial parameters with a counterpart whose
 | |
|         /// type is the underlying type of the enum type, or the union type contating the strong spatial type of the <paramref name="oldVar"/>.
 | |
|         /// The operation invalidates the <paramref name="oldVar"/>. After the operation has completed 
 | |
|         /// the <paramref name="oldVar"/>) is invalidated internally and should no longer be used.
 | |
|         /// </remarks>Func<
 | |
|         private ParameterVar ReplaceParameterVar(ParameterVar oldVar, Func<TypeUsage, TypeUsage> generateReplacementType)
 | |
|         {
 | |
|             Debug.Assert(oldVar != null, "oldVar != null");
 | |
|             Debug.Assert(m_vars.Contains(oldVar));
 | |
|             ParameterVar v = new ParameterVar(NewVarId(), generateReplacementType(oldVar.Type), oldVar.ParameterName);
 | |
|             m_parameterMap[oldVar.ParameterName] = v;
 | |
|             m_vars.Add(v);
 | |
|             return v;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a variable for the given enum parameter variable and replaces it in parameter map.
 | |
|         /// </summary>
 | |
|         /// <param name="oldVar">Enum parameter variable that needs to replaced.</param>
 | |
|         /// <returns>A new ParameterVar instance created of <paramref name="oldVar"/>.</returns>
 | |
|         /// <remarks>
 | |
|         /// This method should be used only to replace external enum parameter with a counterpart whose
 | |
|         /// type is the underlying type of the enum type of the <paramref name="oldVar"/>.
 | |
|         /// The operation invalidates the <paramref name="oldVar"/>. After the operation has completed 
 | |
|         /// the <paramref name="oldVar"/>) is invalidated internally and should no longer be used.
 | |
|         /// </remarks>
 | |
|         internal ParameterVar ReplaceEnumParameterVar(ParameterVar oldVar)
 | |
|         {
 | |
|             return ReplaceParameterVar(oldVar, t => TypeHelpers.CreateEnumUnderlyingTypeUsage(t));
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a variable for the given spatial parameter variable and replaces it in parameter map.
 | |
|         /// </summary>
 | |
|         /// <param name="oldVar">Spatial parameter variable that needs to replaced.</param>
 | |
|         /// <returns>A new ParameterVar instance created of <paramref name="oldVar"/>.</returns>
 | |
|         /// <remarks>
 | |
|         /// This method should be used only to replace external strong spatial parameter with a counterpart whose
 | |
|         /// type is the appropriate union type for <paramref name="oldVar"/>.
 | |
|         /// The operation invalidates the <paramref name="oldVar"/>. After the operation has completed 
 | |
|         /// the <paramref name="oldVar"/>) is invalidated internally and should no longer be used.
 | |
|         /// </remarks>
 | |
|         internal ParameterVar ReplaceStrongSpatialParameterVar(ParameterVar oldVar)
 | |
|         {
 | |
|             return ReplaceParameterVar(oldVar, t => TypeHelpers.CreateSpatialUnionTypeUsage(t));
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new var for a table column
 | |
|         /// </summary>
 | |
|         /// <param name="table">The table instance that produces the column</param>
 | |
|         /// <param name="columnMD">column metadata</param>
 | |
|         /// <returns>A new ColumnVar instance that references the specified column in the given table</returns>
 | |
|         internal ColumnVar CreateColumnVar(Table table, ColumnMD columnMD)
 | |
|         {
 | |
|             // create a new column var now
 | |
|             ColumnVar c = new ColumnVar(NewVarId(), table, columnMD);
 | |
|             table.Columns.Add(c);
 | |
|             m_vars.Add(c);
 | |
|             return c;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a computed var (ie) a variable that is computed by an expression
 | |
|         /// </summary>
 | |
|         /// <param name="type">The type of the result produced by the expression that defines the variable</param>
 | |
|         /// <returns>A new ComputedVar instance with the specified result type</returns>
 | |
|         internal ComputedVar CreateComputedVar(TypeUsage type)
 | |
|         {
 | |
|             ComputedVar v = new ComputedVar(NewVarId(), type);
 | |
|             m_vars.Add(v);
 | |
|             return v;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a SetOp Var of
 | |
|         /// </summary>
 | |
|         /// <param name="type">Datatype of the Var</param>
 | |
|         /// <returns>A new SetOp Var with the specified result type</returns>
 | |
|         internal SetOpVar CreateSetOpVar(TypeUsage type)
 | |
|         {
 | |
|             SetOpVar v = new SetOpVar(NewVarId(), type);
 | |
|             m_vars.Add(v);
 | |
|             return v;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Node Creation
 | |
|         //
 | |
|         // The routines below help in node construction. All command tree nodes must go
 | |
|         // through these routines. These routines help to stamp each node with a unique
 | |
|         // id (the id is very helpful for debugging)
 | |
|         //
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a Node with zero children
 | |
|         /// </summary>
 | |
|         /// <param name="op">The operator that the Node should reference</param>
 | |
|         /// <returns>A new Node with zero children that references the specified Op</returns>
 | |
|         internal Node CreateNode(Op op)
 | |
|         {
 | |
|             return this.CreateNode(op, new List<Node>());
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a node with a single child Node
 | |
|         /// </summary>
 | |
|         /// <param name="op">The operator that the Node should reference</param>
 | |
|         /// <param name="arg1">The single child Node</param>
 | |
|         /// <returns>A new Node with the specified child Node, that references the specified Op</returns>
 | |
|         internal Node CreateNode(Op op, Node arg1)
 | |
|         {
 | |
|             List<Node> l = new List<Node>();
 | |
|             l.Add(arg1);
 | |
|             return this.CreateNode(op, l);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a node with two child Nodes
 | |
|         /// </summary>
 | |
|         /// <param name="op">The operator that the Node should reference</param>
 | |
|         /// <param name="arg1">The first child Node</param>
 | |
|         /// <param name="arg2">the second child Node</param>
 | |
|         /// <returns>A new Node with the specified child Nodes, that references the specified Op</returns>
 | |
|         internal Node CreateNode(Op op, Node arg1, Node arg2)
 | |
|         {
 | |
|             List<Node> l = new List<Node>();
 | |
|             l.Add(arg1); l.Add(arg2);
 | |
|             return this.CreateNode(op, l);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a node with 3 child Nodes
 | |
|         /// </summary>
 | |
|         /// <param name="op">The operator that the Node should reference</param>
 | |
|         /// <param name="arg1">The first child Node</param>
 | |
|         /// <param name="arg2">The second child Node</param>
 | |
|         /// <param name="arg3">The third child Node</param>
 | |
|         /// <returns>A new Node with the specified child Nodes, that references the specified Op</returns>
 | |
|         internal Node CreateNode(Op op, Node arg1, Node arg2, Node arg3)
 | |
|         {
 | |
|             List<Node> l = new List<Node>();
 | |
|             l.Add(arg1); l.Add(arg2); l.Add(arg3);
 | |
|             return this.CreateNode(op, l);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a Node with the specified list of child Nodes
 | |
|         /// </summary>
 | |
|         /// <param name="op">The operator that the Node should reference</param>
 | |
|         /// <param name="args">The list of child Nodes</param>
 | |
|         /// <returns>A new Node with the specified child nodes, that references the specified Op</returns>
 | |
|         internal Node CreateNode(Op op, IList<Node> args)
 | |
|         {
 | |
|             return new Node(m_nextNodeId++, op, new List<Node>(args));
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a Node with the specified list of child Nodes
 | |
|         /// </summary>
 | |
|         /// <param name="op">The operator that the Node should reference</param>
 | |
|         /// <param name="args">The list of child Nodes</param>
 | |
|         /// <returns>A new Node with the specified child nodes, that references the specified Op</returns>
 | |
|         internal Node CreateNode(Op op, List<Node> args)
 | |
|         {
 | |
|             return new Node(m_nextNodeId++, op, args);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ScalarOps
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new ConstantOp
 | |
|         /// </summary>
 | |
|         /// <param name="type">The type of the constant value</param>
 | |
|         /// <param name="value">The constant value (may be null)</param>
 | |
|         /// <returns>A new ConstantOp with the specified type and value</returns>
 | |
|         internal ConstantBaseOp CreateConstantOp(TypeUsage type, object value)
 | |
|         {
 | |
|             // create a NullOp if necessary
 | |
|             if (value == null)
 | |
|             {
 | |
|                 return new NullOp(type);
 | |
|             }
 | |
|             // Identify "safe" constants - the only safe ones are boolean (and we should
 | |
|             // probably include ints eventually)
 | |
|             else if (TypeSemantics.IsBooleanType(type))
 | |
|             {
 | |
|                 return new InternalConstantOp(type, value);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 return new ConstantOp(type, value);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create an "internal" constantOp - only for use by the plan compiler to 
 | |
|         /// represent internally generated constants.
 | |
|         /// User constants in the query should never get into this function
 | |
|         /// </summary>
 | |
|         /// <param name="type">datatype of the constant</param>
 | |
|         /// <param name="value">constant value</param>
 | |
|         /// <returns>a new "internal" constant op that represents the constant</returns>
 | |
|         internal InternalConstantOp CreateInternalConstantOp(TypeUsage type, object value)
 | |
|         {
 | |
|             return new InternalConstantOp(type, value);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// An internal constant that serves as a null sentinel, i.e. it is only ever used
 | |
|         /// to be checked whether it is null
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         internal NullSentinelOp CreateNullSentinelOp()
 | |
|         {
 | |
|             return new NullSentinelOp(this.IntegerType, 1);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// An "internal" null constant
 | |
|         /// </summary>
 | |
|         /// <param name="type">datatype of the null constant</param>
 | |
|         /// <returns>a new "internal" null constant op</returns>
 | |
|         internal NullOp CreateNullOp(TypeUsage type)
 | |
|         {
 | |
|             return new NullOp(type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a constant predicateOp
 | |
|         /// </summary>
 | |
|         /// <param name="value">value of the constant predicate</param>
 | |
|         /// <returns></returns>
 | |
|         internal ConstantPredicateOp CreateConstantPredicateOp(bool value)
 | |
|         {
 | |
|             return value ? m_trueOp : m_falseOp;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a constant predicate with value=true
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         internal ConstantPredicateOp CreateTrueOp()
 | |
|         {
 | |
|             return m_trueOp;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Create a constant predicateOp with the value false
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         internal ConstantPredicateOp CreateFalseOp()
 | |
|         {
 | |
|             return m_falseOp;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new FunctionOp
 | |
|         /// </summary>
 | |
|         /// <param name="function">EdmFunction metadata that represents the function that is invoked by the Op</param>
 | |
|         /// <returns>A new FunctionOp that references the specified function metadata</returns>
 | |
|         internal FunctionOp CreateFunctionOp(EdmFunction function)
 | |
|         {
 | |
|             return new FunctionOp(function);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new TreatOp
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that specifies the type that the child of the treat node should be treated as</param>
 | |
|         /// <returns>A new TreatOp that references the specified type metadata</returns>
 | |
|         internal TreatOp CreateTreatOp(TypeUsage type)
 | |
|         {
 | |
|             return new TreatOp(type, false);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a "dummy" treatOp (i.e.) we can actually ignore the treatOp.
 | |
|         /// </summary>
 | |
|         /// <param name="type"></param>
 | |
|         /// <returns></returns>
 | |
|         internal TreatOp CreateFakeTreatOp(TypeUsage type)
 | |
|         {
 | |
|             return new TreatOp(type, true);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new IsOfOp, which tests if the argument is of the specified type or a promotable type
 | |
|         /// </summary>
 | |
|         /// <param name="isOfType">Type metadata that specifies the type with which the type of the argument should be compared</param>
 | |
|         /// <returns>A new IsOfOp that references the specified type metadata</returns>
 | |
|         internal IsOfOp CreateIsOfOp(TypeUsage isOfType)
 | |
|         {
 | |
|             return new IsOfOp(isOfType, false/*only*/, m_boolType);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Creates a new IsOfOp, which tests if the argument is of the specified type (and only the specified type)
 | |
|         /// </summary>
 | |
|         /// <param name="isOfType">Type metadata that specifies the type with which the type of the argument should be compared</param>
 | |
|         /// <returns>A new IsOfOp that references the specified type metadata</returns>
 | |
|         internal IsOfOp CreateIsOfOnlyOp(TypeUsage isOfType)
 | |
|         {
 | |
|             return new IsOfOp(isOfType, true /* "only" */, m_boolType);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new CastOp
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that represents the type to which the argument should be cast</param>
 | |
|         /// <returns>A new CastOp that references the specified type metadata</returns>
 | |
|         internal CastOp CreateCastOp(TypeUsage type)
 | |
|         {
 | |
|             return new CastOp(type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new SoftCastOp and casts the input to the desired type.
 | |
|         /// 
 | |
|         /// The caller is expected to determine if the cast is necessary or not
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that represents the type to which the argument should be cast</param>
 | |
|         /// <returns>A new CastOp that references the specified type metadata</returns>
 | |
|         internal SoftCastOp CreateSoftCastOp(TypeUsage type)
 | |
|         {
 | |
|             return new SoftCastOp(type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new ComparisonOp of the specified type
 | |
|         /// </summary>
 | |
|         /// <param name="opType">An OpType that specifies one of the valid comparison OpTypes: EQ, GT, GE, NE, LT, LE</param>
 | |
|         /// <returns>A new ComparisonOp of the specified comparison OpType</returns>
 | |
|         internal ComparisonOp CreateComparisonOp(OpType opType)
 | |
|         {
 | |
|             return new ComparisonOp(opType, this.BooleanType);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new LikeOp
 | |
|         /// </summary>
 | |
|         /// <returns>The new LikeOp</returns>
 | |
|         internal LikeOp CreateLikeOp()
 | |
|         {
 | |
|             return new LikeOp(this.BooleanType);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new ConditionalOp of the specified type
 | |
|         /// </summary>
 | |
|         /// <param name="opType">An OpType that specifies one of the valid condition operations: And, Or, Not, IsNull</param>
 | |
|         /// <returns>A new ConditionalOp with the specified conditional OpType</returns>
 | |
|         internal ConditionalOp CreateConditionalOp(OpType opType)
 | |
|         {
 | |
|             return new ConditionalOp(opType, this.BooleanType);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new CaseOp
 | |
|         /// </summary>
 | |
|         /// <param name="type">The result type of the CaseOp</param>
 | |
|         /// <returns>A new CaseOp with the specified result type</returns>
 | |
|         internal CaseOp CreateCaseOp(TypeUsage type)
 | |
|         {
 | |
|             return new CaseOp(type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new AggregateOp
 | |
|         /// </summary>
 | |
|         /// <param name="aggFunc">EdmFunction metadata that specifies the aggregate function</param>
 | |
|         /// <param name="distinctAgg">Indicates whether or not the aggregate is a distinct aggregate</param>
 | |
|         /// <returns>A new AggregateOp with the specified function metadata and distinct property</returns>
 | |
|         internal AggregateOp CreateAggregateOp(EdmFunction aggFunc, bool distinctAgg)
 | |
|         {
 | |
|             return new AggregateOp(aggFunc, distinctAgg);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a named type constructor
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that specifies the type of the instance to construct</param>
 | |
|         /// <returns>A new NewInstanceOp with the specified result type</returns>
 | |
|         internal NewInstanceOp CreateNewInstanceOp(TypeUsage type)
 | |
|         {
 | |
|             return new NewInstanceOp(type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Build out a new NewEntityOp constructing the entity <paramref name="type"/> scoped to the <paramref name="entitySet"/>.
 | |
|         /// </summary>
 | |
|         internal NewEntityOp CreateScopedNewEntityOp(TypeUsage type, List<RelProperty> relProperties, EntitySet entitySet)
 | |
|         {
 | |
|             return new NewEntityOp(type, relProperties, true, entitySet);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Build out a new NewEntityOp constructing the uscoped entity <paramref name="type"/>.
 | |
|         /// </summary>
 | |
|         internal NewEntityOp CreateNewEntityOp(TypeUsage type, List<RelProperty> relProperties)
 | |
|         {
 | |
|             return new NewEntityOp(type, relProperties, false, null);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a discriminated named type constructor
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that specifies the type of the instance to construct</param>
 | |
|         /// <param name="discriminatorMap">Mapping information including discriminator values</param>
 | |
|         /// <param name="entitySet">the entityset that this instance belongs to</param>
 | |
|         /// <param name="relProperties">list of rel properties that have corresponding values</param>
 | |
|         /// <returns>A new DiscriminatedNewInstanceOp with the specified result type and discrimination behavior</returns>
 | |
|         internal DiscriminatedNewEntityOp CreateDiscriminatedNewEntityOp(TypeUsage type, ExplicitDiscriminatorMap discriminatorMap,
 | |
|             EntitySet entitySet, List<RelProperty> relProperties)
 | |
|         {
 | |
|             return new DiscriminatedNewEntityOp(type, discriminatorMap, entitySet, relProperties);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a multiset constructor
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that specifies the type of the multiset to construct</param>
 | |
|         /// <returns>A new NewMultiSetOp with the specified result type</returns>
 | |
|         internal NewMultisetOp CreateNewMultisetOp(TypeUsage type)
 | |
|         {
 | |
|             return new NewMultisetOp(type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a record constructor
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that specifies that record type to construct</param>
 | |
|         /// <returns>A new NewRecordOp with the specified result type</returns>
 | |
|         internal NewRecordOp CreateNewRecordOp(TypeUsage type)
 | |
|         {
 | |
|             return new NewRecordOp(type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a record constructor
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that specifies that record type to construct</param>
 | |
|         /// <returns>A new NewRecordOp with the specified result type</returns>
 | |
|         internal NewRecordOp CreateNewRecordOp(RowType type)
 | |
|         {
 | |
|             return new NewRecordOp(TypeUsage.Create(type));
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// A variant of the above method to create a NewRecordOp. An additional
 | |
|         /// argument - fields - is supplied, and the semantics is that only these fields
 | |
|         /// have any values specified as part of the Node. All other fields are
 | |
|         /// considered to be null.
 | |
|         /// </summary>
 | |
|         /// <param name="type"></param>
 | |
|         /// <param name="fields"></param>
 | |
|         /// <returns></returns>
 | |
|         internal NewRecordOp CreateNewRecordOp(TypeUsage type,
 | |
|             List<EdmProperty> fields)
 | |
|         {
 | |
|             return new NewRecordOp(type, fields);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new VarRefOp
 | |
|         /// </summary>
 | |
|         /// <param name="v">The variable to reference</param>
 | |
|         /// <returns>A new VarRefOp that references the specified variable</returns>
 | |
|         internal VarRefOp CreateVarRefOp(Var v)
 | |
|         {
 | |
|             return new VarRefOp(v);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Creates a new ArithmeticOp of the specified type
 | |
|         /// </summary>
 | |
|         /// <param name="opType">An OpType that specifies one of the valid arithmetic operations: Plus, Minus, Multiply, Divide, Modulo, UnaryMinus</param>
 | |
|         /// <param name="type">Type metadata that specifies the result type of the arithmetic operation</param>
 | |
|         /// <returns>A new ArithmeticOp of the specified arithmetic OpType</returns>
 | |
|         internal ArithmeticOp CreateArithmeticOp(OpType opType, TypeUsage type)
 | |
|         {
 | |
|             return new ArithmeticOp(opType, type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new PropertyOp
 | |
|         /// </summary>
 | |
|         /// <param name="prop">EdmProperty metadata that specifies the property</param>
 | |
|         /// <returns>A new PropertyOp that references the specified property metadata</returns>
 | |
|         internal PropertyOp CreatePropertyOp(EdmMember prop)
 | |
|         {
 | |
|             //
 | |
|             // Track all rel-properties
 | |
|             //
 | |
|             NavigationProperty navProp = prop as NavigationProperty;
 | |
|             if (navProp != null)
 | |
|             {
 | |
|                 RelProperty relProperty = new RelProperty(navProp.RelationshipType, navProp.FromEndMember, navProp.ToEndMember);
 | |
|                 AddRelPropertyReference(relProperty);
 | |
|                 RelProperty inverseRelProperty = new RelProperty(navProp.RelationshipType, navProp.ToEndMember, navProp.FromEndMember);
 | |
|                 AddRelPropertyReference(inverseRelProperty);
 | |
|             }
 | |
| 
 | |
|             // Actually create the propertyOp
 | |
|             return new PropertyOp(Helper.GetModelTypeUsage(prop), prop);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a "relationship" propertyOp
 | |
|         /// </summary>
 | |
|         /// <param name="prop">the relationship property</param>
 | |
|         /// <returns>a RelPropertyOp</returns>
 | |
|         internal RelPropertyOp CreateRelPropertyOp(RelProperty prop)
 | |
|         {
 | |
|             AddRelPropertyReference(prop);
 | |
|             return new RelPropertyOp(prop.ToEnd.TypeUsage, prop);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new RefOp
 | |
|         /// </summary>
 | |
|         /// <param name="entitySet">The EntitySet to which the ref refers</param>
 | |
|         /// <param name="type">The result type of the RefOp</param>
 | |
|         /// <returns>A new RefOp that references the specified EntitySet and has the specified result type</returns>
 | |
|         internal RefOp CreateRefOp(EntitySet entitySet, TypeUsage type)
 | |
|         {
 | |
|             return new RefOp(entitySet, type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new ExistsOp
 | |
|         /// </summary>
 | |
|         /// <returns>A new ExistsOp</returns>
 | |
|         internal ExistsOp CreateExistsOp()
 | |
|         {
 | |
|             return new ExistsOp(this.BooleanType);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Creates a new ElementOp
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that specifies the result (element) type</param>
 | |
|         /// <returns>A new ElementOp with the specified result type</returns>
 | |
|         internal ElementOp CreateElementOp(TypeUsage type)
 | |
|         {
 | |
|             return new ElementOp(type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new GetEntityRefOp: a ref-extractor (from an entity instance) Op
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that specifies the result type</param>
 | |
|         /// <returns>A new GetEntityKeyOp with the specified result type</returns>
 | |
|         internal GetEntityRefOp CreateGetEntityRefOp(TypeUsage type)
 | |
|         {
 | |
|             return new GetEntityRefOp(type);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Creates a new GetRefKeyOp: a key-extractor (from a ref instance) Op
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that specifies the result type</param>
 | |
|         /// <returns>A new GetRefKeyOp with the specified result type</returns>
 | |
|         internal GetRefKeyOp CreateGetRefKeyOp(TypeUsage type)
 | |
|         {
 | |
|             return new GetRefKeyOp(type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new CollectOp
 | |
|         /// </summary>
 | |
|         /// <param name="type">Type metadata that specifies the result type of the Nest operation</param>
 | |
|         /// <returns>A new NestOp with the specified result type</returns>
 | |
|         internal CollectOp CreateCollectOp(TypeUsage type)
 | |
|         {
 | |
|             return new CollectOp(type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a DerefOp
 | |
|         /// </summary>
 | |
|         /// <param name="type">Entity type of the target entity</param>
 | |
|         /// <returns>a DerefOp</returns>
 | |
|         internal DerefOp CreateDerefOp(TypeUsage type)
 | |
|         {
 | |
|             return new DerefOp(type);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a new NavigateOp node
 | |
|         /// </summary>
 | |
|         /// <param name="type">the output type of the navigateOp</param>
 | |
|         /// <param name="relProperty">the relationship property</param>
 | |
|         /// <returns>the navigateOp</returns>
 | |
|         internal NavigateOp CreateNavigateOp(TypeUsage type, RelProperty relProperty)
 | |
|         {
 | |
|             // keep track of rel-properties
 | |
|             AddRelPropertyReference(relProperty);
 | |
|             return new NavigateOp(type, relProperty);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region AncillaryOps
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a VarDefListOp
 | |
|         /// </summary>
 | |
|         /// <returns>A new VarDefListOp</returns>
 | |
|         internal VarDefListOp CreateVarDefListOp()
 | |
|         {
 | |
|             return VarDefListOp.Instance;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Creates a VarDefOp (for a computed var)
 | |
|         /// </summary>
 | |
|         /// <param name="v">The computed var</param>
 | |
|         /// <returns>A new VarDefOp that references the computed var</returns>
 | |
|         internal VarDefOp CreateVarDefOp(Var v)
 | |
|         {
 | |
|             return new VarDefOp(v);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a VarDefOp and the associated node for an expression.
 | |
|         /// We create a computedVar first - of the same type as the expression, and
 | |
|         /// then create a VarDefOp for the computed Var. Finally, we create a Node for
 | |
|         /// the VarDefOp
 | |
|         /// </summary>
 | |
|         /// <param name="definingExpr"></param>
 | |
|         /// <param name="computedVar">new Var produced</param>
 | |
|         /// <returns></returns>
 | |
|         internal Node CreateVarDefNode(Node definingExpr, out Var computedVar)
 | |
|         {
 | |
|             Debug.Assert(definingExpr.Op != null);
 | |
|             ScalarOp scalarOp = definingExpr.Op as ScalarOp;
 | |
|             Debug.Assert(scalarOp != null);
 | |
|             computedVar = this.CreateComputedVar(scalarOp.Type);
 | |
|             VarDefOp varDefOp = this.CreateVarDefOp(computedVar);
 | |
|             Node varDefNode = this.CreateNode(varDefOp, definingExpr);
 | |
|             return varDefNode;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a VarDefListOp with a single child - a VarDefOp created as in the function
 | |
|         /// above.
 | |
|         /// </summary>
 | |
|         /// <param name="definingExpr"></param>
 | |
|         /// <param name="computedVar">the computed Var produced</param>
 | |
|         /// <returns></returns>
 | |
|         internal Node CreateVarDefListNode(Node definingExpr, out Var computedVar)
 | |
|         {
 | |
|             Node varDefNode = this.CreateVarDefNode(definingExpr, out computedVar);
 | |
|             VarDefListOp op = this.CreateVarDefListOp();
 | |
|             Node varDefListNode = this.CreateNode(op, varDefNode);
 | |
|             return varDefListNode;
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region RelOps
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new ScanTableOp
 | |
|         /// </summary>
 | |
|         /// <param name="tableMetadata">A Table metadata instance that specifies the table that should be scanned</param>
 | |
|         /// <returns>A new ScanTableOp that references a new Table instance based on the specified table metadata</returns>
 | |
|         internal ScanTableOp CreateScanTableOp(TableMD tableMetadata)
 | |
|         {
 | |
|             Table table = this.CreateTableInstance(tableMetadata);
 | |
|             return CreateScanTableOp(table);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// A variant of the above
 | |
|         /// </summary>
 | |
|         /// <param name="table">The table instance</param>
 | |
|         /// <returns>a new ScanTableOp</returns>
 | |
|         internal ScanTableOp CreateScanTableOp(Table table)
 | |
|         {
 | |
|             return new ScanTableOp(table);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates an instance of a ScanViewOp
 | |
|         /// </summary>
 | |
|         /// <param name="table">the table instance</param>
 | |
|         /// <returns>a new ScanViewOp</returns>
 | |
|         internal ScanViewOp CreateScanViewOp(Table table)
 | |
|         {
 | |
|             return new ScanViewOp(table);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Creates an instance of a ScanViewOp
 | |
|         /// </summary>
 | |
|         /// <param name="tableMetadata">the table metadata</param>
 | |
|         /// <returns>a new ScanViewOp</returns>
 | |
|         internal ScanViewOp CreateScanViewOp(TableMD tableMetadata)
 | |
|         {
 | |
|             Table table = this.CreateTableInstance(tableMetadata);
 | |
|             return this.CreateScanViewOp(table);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Creates a new UnnestOp, which creates a streaming result from a scalar (non-RelOp) value
 | |
|         /// </summary>
 | |
|         /// <param name="v">The Var that indicates the value to unnest</param>
 | |
|         /// <returns>A new UnnestOp that targets the specified Var</returns>
 | |
|         internal UnnestOp CreateUnnestOp(Var v)
 | |
|         {
 | |
|             Table t = this.CreateTableInstance(Command.CreateTableDefinition(TypeHelpers.GetEdmType<CollectionType>(v.Type).TypeUsage));
 | |
|             return CreateUnnestOp(v, t);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new UnnestOp - a variant of the above with the Table supplied
 | |
|         /// </summary>
 | |
|         /// <param name="v">the unnest Var</param>
 | |
|         /// <param name="t">the table instance</param>
 | |
|         /// <returns>a new UnnestOp</returns>
 | |
|         internal UnnestOp CreateUnnestOp(Var v, Table t)
 | |
|         {
 | |
|             return new UnnestOp(v, t);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new FilterOp
 | |
|         /// </summary>
 | |
|         /// <returns>A new FilterOp</returns>
 | |
|         internal FilterOp CreateFilterOp()
 | |
|         {
 | |
|             return FilterOp.Instance;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new ProjectOp
 | |
|         /// </summary>
 | |
|         /// <param name="vars">A VarSet that specifies the Vars produced by the projection</param>
 | |
|         /// <returns>A new ProjectOp with the specified output VarSet</returns>
 | |
|         internal ProjectOp CreateProjectOp(VarVec vars)
 | |
|         {
 | |
|             return new ProjectOp(vars);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// A variant of the above where the ProjectOp produces exactly one var
 | |
|         /// </summary>
 | |
|         /// <param name="v"></param>
 | |
|         /// <returns></returns>
 | |
|         internal ProjectOp CreateProjectOp(Var v)
 | |
|         {
 | |
|             VarVec varSet = this.CreateVarVec();
 | |
|             varSet.Set(v);
 | |
|             return new ProjectOp(varSet);
 | |
|         }
 | |
| 
 | |
|         #region JoinOps
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new InnerJoinOp
 | |
|         /// </summary>
 | |
|         /// <returns>A new InnerJoinOp</returns>
 | |
|         internal InnerJoinOp CreateInnerJoinOp()
 | |
|         {
 | |
|             return InnerJoinOp.Instance;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new LeftOuterJoinOp
 | |
|         /// </summary>
 | |
|         /// <returns>A new LeftOuterJoinOp</returns>
 | |
|         internal LeftOuterJoinOp CreateLeftOuterJoinOp()
 | |
|         {
 | |
|             return LeftOuterJoinOp.Instance;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new FullOuterJoinOp
 | |
|         /// </summary>
 | |
|         /// <returns>A new FullOuterJoinOp</returns>
 | |
|         internal FullOuterJoinOp CreateFullOuterJoinOp()
 | |
|         {
 | |
|             return FullOuterJoinOp.Instance;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new CrossJoinOp
 | |
|         /// </summary>
 | |
|         /// <returns>A new CrossJoinOp</returns>
 | |
|         internal CrossJoinOp CreateCrossJoinOp()
 | |
|         {
 | |
|             return CrossJoinOp.Instance;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ApplyOps
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new CrossApplyOp
 | |
|         /// </summary>
 | |
|         /// <returns>A new CrossApplyOp</returns>
 | |
|         internal CrossApplyOp CreateCrossApplyOp()
 | |
|         {
 | |
|             return CrossApplyOp.Instance;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Creates a new OuterApplyOp
 | |
|         /// </summary>
 | |
|         /// <returns>A new OuterApplyOp</returns>
 | |
|         internal OuterApplyOp CreateOuterApplyOp()
 | |
|         {
 | |
|             return OuterApplyOp.Instance;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region SortKeys
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new SortKey with the specified var, order and collation
 | |
|         /// </summary>
 | |
|         /// <param name="v">The variable to sort on</param>
 | |
|         /// <param name="asc">The sort order (true for ascending, false for descending)</param>
 | |
|         /// <param name="collation">The sort collation</param>
 | |
|         /// <returns>A new SortKey with the specified var, order and collation</returns>
 | |
|         internal static SortKey CreateSortKey(Var v, bool asc, string collation)
 | |
|         {
 | |
|             return new SortKey(v, asc, collation);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Creates a new SortKey with the specified var and order
 | |
|         /// </summary>
 | |
|         /// <param name="v">The variable to sort on</param>
 | |
|         /// <param name="asc">The sort order (true for ascending, false for descending)</param>
 | |
|         /// <returns>A new SortKey with the specified var and order</returns>
 | |
|         internal static SortKey CreateSortKey(Var v, bool asc)
 | |
|         {
 | |
|             return new SortKey(v, asc, "");
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new SortKey with the specified var
 | |
|         /// </summary>
 | |
|         /// <param name="v">The variable to sort on</param>
 | |
|         /// <returns>A new SortKey with the specified var</returns>
 | |
|         internal static SortKey CreateSortKey(Var v)
 | |
|         {
 | |
|             return new SortKey(v, true, "");
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new SortOp
 | |
|         /// </summary>
 | |
|         /// <param name="sortKeys">The list of SortKeys that define the sort var, order and collation for each sort key</param>
 | |
|         /// <returns>A new SortOp with the specified sort keys</returns>
 | |
|         internal SortOp CreateSortOp(List<SortKey> sortKeys)
 | |
|         {
 | |
|             return new SortOp(sortKeys);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new ConstrainedSortOp
 | |
|         /// </summary>
 | |
|         /// <param name="sortKeys">The list of SortKeys that define the sort var, order and collation for each sort key</param>
 | |
|         /// <returns>A new ConstrainedSortOp with the specified sort keys and a default WithTies value of false</returns>
 | |
|         internal ConstrainedSortOp CreateConstrainedSortOp(List<SortKey> sortKeys)
 | |
|         {
 | |
|             return new ConstrainedSortOp(sortKeys, false);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new ConstrainedSortOp
 | |
|         /// </summary>
 | |
|         /// <param name="sortKeys">The list of SortKeys that define the sort var, order and collation for each sort key</param>
 | |
|         /// <param name="withTies">The value to use for the WithTies property of the new ConstrainedSortOp</param>
 | |
|         /// <returns>A new ConstrainedSortOp with the specified sort keys and WithTies value</returns>
 | |
|         internal ConstrainedSortOp CreateConstrainedSortOp(List<SortKey> sortKeys, bool withTies)
 | |
|         {
 | |
|             return new ConstrainedSortOp(sortKeys, withTies);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new GroupByOp
 | |
|         /// </summary>
 | |
|         /// <param name="gbyKeys">A VarSet that specifies the Key variables produced by the GroupByOp</param>
 | |
|         /// <param name="outputs">A VarSet that specifies all (Key and Aggregate) variables produced by the GroupByOp</param>
 | |
|         /// <returns>A new GroupByOp with the specified key and output VarSets</returns>
 | |
|         internal GroupByOp CreateGroupByOp(VarVec gbyKeys, VarVec outputs)
 | |
|         {
 | |
|             return new GroupByOp(gbyKeys, outputs);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new GroupByIntoOp
 | |
|         /// </summary>
 | |
|         /// <param name="gbyKeys">A VarSet that specifies the Key variables produced by the GroupByOp</param>
 | |
|         /// <param name="outputs">A VarSet that specifies the vars from the input that represent the real grouping input</param>
 | |
|         /// <param name="inputs">A VarSet that specifies all (Key and Aggregate) variables produced by the GroupByOp</param>
 | |
|         /// <returns>A new GroupByOp with the specified key and output VarSets</returns>
 | |
|         internal GroupByIntoOp CreateGroupByIntoOp(VarVec gbyKeys, VarVec inputs, VarVec outputs)
 | |
|         {
 | |
|             return new GroupByIntoOp(gbyKeys, inputs, outputs);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new DistinctOp
 | |
|         /// <param name="keyVars">list of key vars</param>
 | |
|         /// </summary>
 | |
|         /// <returns>A new DistinctOp</returns>
 | |
|         internal DistinctOp CreateDistinctOp(VarVec keyVars)
 | |
|         {
 | |
|             return new DistinctOp(keyVars);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// An overload of the above - where the distinct has exactly one key
 | |
|         /// </summary>
 | |
|         /// <param name="keyVar"></param>
 | |
|         /// <returns></returns>
 | |
|         internal DistinctOp CreateDistinctOp(Var keyVar)
 | |
|         {
 | |
|             return new DistinctOp(this.CreateVarVec(keyVar));
 | |
|         }
 | |
|         
 | |
|         /// <summary>
 | |
|         /// Creates a new UnionAllOp
 | |
|         /// </summary>
 | |
|         /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param>
 | |
|         /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param>
 | |
|         /// <returns>A UnionAllOp that references the specified left and right Vars</returns>
 | |
|         internal UnionAllOp CreateUnionAllOp(VarMap leftMap, VarMap rightMap)
 | |
|         {
 | |
|             return CreateUnionAllOp(leftMap, rightMap, null);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new UnionAllOp, with a branch descriminator.
 | |
|         /// </summary>
 | |
|         /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param>
 | |
|         /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param>
 | |
|         /// <param name="branchDiscriminator">Var that contains the branch discrimination value (may be null until key pullup occurs)</param>
 | |
|         /// <returns>A UnionAllOp that references the specified left and right Vars</returns>
 | |
|         internal UnionAllOp CreateUnionAllOp(VarMap leftMap, VarMap rightMap, Var branchDiscriminator) 
 | |
|         {
 | |
|             Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch");
 | |
|             VarVec vec = this.CreateVarVec();
 | |
|             foreach (Var v in leftMap.Keys)
 | |
|             {
 | |
|                 vec.Set(v);
 | |
|             }
 | |
|             return new UnionAllOp(vec, leftMap, rightMap, branchDiscriminator);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Creates a new IntersectOp
 | |
|         /// </summary>
 | |
|         /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param>
 | |
|         /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param>
 | |
|         /// <returns>An IntersectOp that references the specified left and right Vars</returns>
 | |
|         internal IntersectOp CreateIntersectOp(VarMap leftMap, VarMap rightMap)
 | |
|         {
 | |
|             Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch");
 | |
|             VarVec vec = this.CreateVarVec();
 | |
|             foreach (Var v in leftMap.Keys)
 | |
|             {
 | |
|                 vec.Set(v);
 | |
|             }
 | |
|             return new IntersectOp(vec, leftMap, rightMap);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Creates a new ExceptOp
 | |
|         /// </summary>
 | |
|         /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param>
 | |
|         /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param>
 | |
|         /// <returns>An ExceptOp that references the specified left and right Vars</returns>
 | |
|         internal ExceptOp CreateExceptOp(VarMap leftMap, VarMap rightMap)
 | |
|         {
 | |
|             Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch");
 | |
|             VarVec vec = this.CreateVarVec();
 | |
|             foreach (Var v in leftMap.Keys)
 | |
|             {
 | |
|                 vec.Set(v);
 | |
|             }
 | |
|             return new ExceptOp(vec, leftMap, rightMap);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a single-row-op (the relop analog of Element)
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         internal SingleRowOp CreateSingleRowOp()
 | |
|         {
 | |
|             return SingleRowOp.Instance;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a SingleRowTableOp - a table with exactly one row (and no columns)
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         internal SingleRowTableOp CreateSingleRowTableOp()
 | |
|         {
 | |
|             return SingleRowTableOp.Instance;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region PhysicalOps
 | |
|         /// <summary>
 | |
|         /// Create a PhysicalProjectOp - with a columnMap describing the output
 | |
|         /// </summary>
 | |
|         /// <param name="outputVars">list of output vars</param>
 | |
|         /// <param name="columnMap">columnmap describing the output element</param>
 | |
|         /// <returns></returns>
 | |
|         internal PhysicalProjectOp CreatePhysicalProjectOp(VarList outputVars, SimpleCollectionColumnMap columnMap)
 | |
|         {
 | |
|             return new PhysicalProjectOp(outputVars, columnMap);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Create a physicalProjectOp - with a single column output
 | |
|         /// </summary>
 | |
|         /// <param name="outputVar">the output element</param>
 | |
|         /// <returns></returns>
 | |
|         internal PhysicalProjectOp CreatePhysicalProjectOp(Var outputVar)
 | |
|         {
 | |
|             VarList varList = Command.CreateVarList();
 | |
|             varList.Add(outputVar);
 | |
|             VarRefColumnMap varRefColumnMap = new VarRefColumnMap(outputVar);
 | |
| 
 | |
|             SimpleCollectionColumnMap collectionColumnMap = new SimpleCollectionColumnMap(
 | |
|                 TypeUtils.CreateCollectionType(varRefColumnMap.Type),   // type
 | |
|                 null,                                                   // name
 | |
|                 varRefColumnMap,                                        // element map
 | |
|                 new SimpleColumnMap[0],                                 // keys
 | |
|                 new SimpleColumnMap[0]);                                // foreign keys
 | |
|             return CreatePhysicalProjectOp(varList, collectionColumnMap);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Another overload - with an additional discriminatorValue.
 | |
|         /// Should this be a subtype instead?
 | |
|         /// </summary>
 | |
|         /// <param name="collectionVar">the collectionVar</param>
 | |
|         /// <param name="columnMap">column map for the collection element</param>
 | |
|         /// <param name="flattenedElementVars">elementVars with any nested collections pulled up</param>
 | |
|         /// <param name="keys">keys specific to this collection</param>
 | |
|         /// <param name="sortKeys">sort keys specific to this collecion</param>
 | |
|         /// <param name="discriminatorValue">discriminator value for this collection (under the current nestOp)</param>
 | |
|         /// <returns>a new CollectionInfo instance</returns>
 | |
|         internal static CollectionInfo CreateCollectionInfo(Var collectionVar, ColumnMap columnMap, VarList flattenedElementVars, VarVec keys, List<InternalTrees.SortKey> sortKeys, object discriminatorValue)
 | |
|         {
 | |
|             return new CollectionInfo(collectionVar, columnMap, flattenedElementVars, keys, sortKeys, discriminatorValue);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a singleStreamNestOp
 | |
|         /// </summary>
 | |
|         /// <param name="keys">keys for the nest operation</param>
 | |
|         /// <param name="prefixSortKeys">list of prefix sort keys</param>
 | |
|         /// <param name="postfixSortKeys">list of postfix sort keys</param>
 | |
|         /// <param name="outputVars">List of outputVars</param>
 | |
|         /// <param name="collectionInfoList">CollectionInfo for each collection </param>
 | |
|         /// <param name="discriminatorVar">Var describing the discriminator</param>
 | |
|         /// <returns></returns>
 | |
|         internal SingleStreamNestOp CreateSingleStreamNestOp(VarVec keys,
 | |
|             List<SortKey> prefixSortKeys, List<SortKey> postfixSortKeys,
 | |
|             VarVec outputVars,
 | |
|             List<CollectionInfo> collectionInfoList, Var discriminatorVar)
 | |
|         {
 | |
|             return new SingleStreamNestOp(keys, prefixSortKeys, postfixSortKeys, outputVars, collectionInfoList, discriminatorVar);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a MultiStreamNestOp
 | |
|         /// </summary>
 | |
|         /// <param name="prefixSortKeys">list of prefix sort keys</param>
 | |
|         /// <param name="outputVars">List of outputVars</param>
 | |
|         /// <param name="collectionInfoList">CollectionInfo for each collection element</param>
 | |
|         /// <returns></returns>
 | |
|         internal MultiStreamNestOp CreateMultiStreamNestOp(List<SortKey> prefixSortKeys, VarVec outputVars,
 | |
|             List<CollectionInfo> collectionInfoList)
 | |
|         {
 | |
|             return new MultiStreamNestOp(prefixSortKeys, outputVars, collectionInfoList);
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region NodeInfo
 | |
|         /// <summary>
 | |
|         /// Get auxilliary information for a Node
 | |
|         /// </summary>
 | |
|         /// <param name="n">the node</param>
 | |
|         /// <returns>node info for this node</returns>
 | |
|         internal NodeInfo GetNodeInfo(Node n)
 | |
|         {
 | |
|             return n.GetNodeInfo(this);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Get extended node information for a RelOpNode
 | |
|         /// </summary>
 | |
|         /// <param name="n">the node</param>
 | |
|         /// <returns>extended node info for this node</returns>
 | |
|         internal ExtendedNodeInfo GetExtendedNodeInfo(Node n)
 | |
|         {
 | |
|             return n.GetExtendedNodeInfo(this);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Recompute the nodeinfo for a node, but only if has already been computed
 | |
|         /// </summary>
 | |
|         /// <param name="n">Node in question</param>
 | |
|         internal void RecomputeNodeInfo(Node n)
 | |
|         {
 | |
|             m_nodeInfoVisitor.RecomputeNodeInfo(n);
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region KeyInfo
 | |
|         /// <summary>
 | |
|         /// Pulls up keys if necessary and gets the key information for a Node
 | |
|         /// </summary>
 | |
|         /// <param name="n">node</param>
 | |
|         /// <returns>key information</returns>
 | |
|         internal KeyVec PullupKeys(Node n)
 | |
|         {
 | |
|             return m_keyPullupVisitor.GetKeys(n);
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region Type Comparisons
 | |
|         //
 | |
|         // The functions described in this region are used through out the 
 | |
|         // PlanCompiler to reason about type equality. Make sure that you 
 | |
|         // use these and these alone
 | |
|         //
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Check to see if two types are considered "equal" for the purposes
 | |
|         /// of the plan compiler. 
 | |
|         /// Two types are considered to be equal if their "identities" are equal.
 | |
|         /// </summary>
 | |
|         /// <param name="x"></param>
 | |
|         /// <param name="y"></param>
 | |
|         /// <returns>true, if the types are "equal"</returns>
 | |
|         internal static bool EqualTypes(TypeUsage x, TypeUsage y)
 | |
|         {
 | |
|             return PlanCompiler.TypeUsageEqualityComparer.Instance.Equals(x, y);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Check to see if two types are considered "equal" for the purposes
 | |
|         /// of the plan compiler
 | |
|         /// </summary>
 | |
|         /// <param name="x"></param>
 | |
|         /// <param name="y"></param>
 | |
|         /// <returns>true, if the types are "equal"</returns>
 | |
|         internal static bool EqualTypes(EdmType x, EdmType y)
 | |
|         {
 | |
|             return PlanCompiler.TypeUsageEqualityComparer.Equals(x, y);
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region Builder Methods
 | |
|         /// <summary>
 | |
|         /// Builds out a UNION-ALL ladder from a sequence of node,var pairs.
 | |
|         /// Assumption: Each node produces exactly one Var
 | |
|         /// 
 | |
|         /// If the input sequence has zero elements, we return null
 | |
|         /// If the input sequence has one element, we return that single element
 | |
|         /// Otherwise, we build out a UnionAll ladder from each of the inputs. If the input sequence was {A,B,C,D},
 | |
|         /// we build up a union-all ladder that looks like 
 | |
|         ///     (((A UA B) UA C) UA D)
 | |
|         /// </summary>
 | |
|         /// <param name="inputNodes">list of input nodes - one for each branch</param>
 | |
|         /// <param name="inputVars">list of input vars - N for each branch</param>
 | |
|         /// <param name="resultNode">the resulting union-all subtree</param>
 | |
|         /// <param name="resultVar">the output vars from the union-all subtree</param>
 | |
|         internal void BuildUnionAllLadder(
 | |
|             IList<Node> inputNodes, IList<Var> inputVars,
 | |
|             out Node resultNode, out IList<Var> resultVars)
 | |
|         {
 | |
|             if (inputNodes.Count == 0)
 | |
|             {
 | |
|                 resultNode = null;
 | |
|                 resultVars = null;
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             int varPerNode = inputVars.Count / inputNodes.Count;
 | |
|             Debug.Assert((inputVars.Count % inputNodes.Count == 0) && (varPerNode >= 1), "Inconsistent nodes/vars count:" + inputNodes.Count + "," + inputVars.Count);
 | |
| 
 | |
|             if (inputNodes.Count == 1)
 | |
|             {
 | |
|                 resultNode = inputNodes[0];
 | |
|                 resultVars = inputVars;
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             List<Var> unionAllVars = new List<Var>();
 | |
| 
 | |
|             Node unionAllNode = inputNodes[0];
 | |
|             for (int j = 0; j < varPerNode; j++)
 | |
|             {
 | |
|                 unionAllVars.Add(inputVars[j]);
 | |
|             }
 | |
| 
 | |
|             for (int i = 1; i < inputNodes.Count; i++)
 | |
|             {
 | |
|                 VarMap leftVarMap = this.CreateVarMap();
 | |
|                 VarMap rightVarMap = this.CreateVarMap();
 | |
|                 List<Var> setOpVars = new List<Var>();
 | |
|                 for (int j = 0; j < varPerNode; j++)
 | |
|                 {
 | |
|                     SetOpVar newVar = this.CreateSetOpVar(unionAllVars[j].Type);
 | |
|                     setOpVars.Add(newVar);
 | |
|                     leftVarMap.Add(newVar, unionAllVars[j]);
 | |
|                     rightVarMap.Add(newVar, inputVars[i * varPerNode + j]);
 | |
|                 }
 | |
|                 Op unionAllOp = this.CreateUnionAllOp(leftVarMap, rightVarMap);
 | |
|                 unionAllNode = this.CreateNode(unionAllOp, unionAllNode, inputNodes[i]);
 | |
|                 unionAllVars = setOpVars;
 | |
|             }
 | |
| 
 | |
|             resultNode = unionAllNode;
 | |
|             resultVars = unionAllVars;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// A simplified version of the method above - each branch can produce only one var
 | |
|         /// </summary>
 | |
|         /// <param name="inputNodes"></param>
 | |
|         /// <param name="inputVars"></param>
 | |
|         /// <param name="resultNode"></param>
 | |
|         /// <param name="resultVar"></param>
 | |
|         internal void BuildUnionAllLadder(IList<Node> inputNodes, IList<Var> inputVars,
 | |
|             out Node resultNode, out Var resultVar)
 | |
|         {
 | |
|             Debug.Assert(inputNodes.Count == inputVars.Count, "Count mismatch:" + inputNodes.Count + "," + inputVars.Count);
 | |
|             IList<Var> varList;
 | |
|             BuildUnionAllLadder(inputNodes, inputVars, out resultNode, out varList);
 | |
|             if (varList != null && varList.Count > 0)
 | |
|             {
 | |
|                 resultVar = varList[0];
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 resultVar = null;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Build a projectOp tree over the input. 
 | |
|         /// This function builds a projectOp tree over the input. The Outputs (vars) of the project are the 
 | |
|         /// list of vars from the input (inputVars), plus one computed Var for each of the computed expressions
 | |
|         /// (computedExpressions)
 | |
|         /// </summary>
 | |
|         /// <param name="inputNode">the input relop to the project</param>
 | |
|         /// <param name="inputVars">List of vars from the input that need to be projected</param>
 | |
|         /// <param name="computedExpressions">list (possibly empty) of any computed expressions</param>
 | |
|         /// <returns></returns>
 | |
|         internal Node BuildProject(Node inputNode, IEnumerable<Var> inputVars,
 | |
|             IEnumerable<Node> computedExpressions)
 | |
|         {
 | |
|             Debug.Assert(inputNode.Op.IsRelOp, "Expected a RelOp. Found " + inputNode.Op.OpType);
 | |
| 
 | |
|             VarDefListOp varDefListOp = this.CreateVarDefListOp();
 | |
|             Node varDefListNode = this.CreateNode(varDefListOp);
 | |
|             VarVec projectVars = this.CreateVarVec(inputVars);
 | |
|             foreach (Node expr in computedExpressions)
 | |
|             {
 | |
|                 Var v = this.CreateComputedVar(expr.Op.Type);
 | |
|                 projectVars.Set(v);
 | |
|                 VarDefOp varDefOp = this.CreateVarDefOp(v);
 | |
|                 Node varDefNode = this.CreateNode(varDefOp, expr);
 | |
|                 varDefListNode.Children.Add(varDefNode);
 | |
|             }
 | |
|             Node projectNode = this.CreateNode(
 | |
|                 this.CreateProjectOp(projectVars),
 | |
|                 inputNode,
 | |
|                 varDefListNode);
 | |
|             return projectNode;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// A "simpler" builder method for ProjectOp. The assumption is that the only output is the
 | |
|         /// (var corresponding to) the computedExpression. None of the Vars of the "input" are projected out
 | |
|         /// 
 | |
|         /// The single output Var is returned in the "outputVar" parameter
 | |
|         /// </summary>
 | |
|         /// <param name="input">the input relop</param>
 | |
|         /// <param name="computedExpression">the computed expression</param>
 | |
|         /// <param name="projectVar">(output) the computed var corresponding to the computed expression</param>
 | |
|         /// <returns>the new project subtree node</returns>
 | |
|         internal Node BuildProject(Node input, Node computedExpression, out Var projectVar)
 | |
|         {
 | |
|             Node projectNode = BuildProject(input, new Var[] { }, new Node[] { computedExpression });
 | |
|             projectVar = ((ProjectOp)projectNode.Op).Outputs.First;
 | |
|             return projectNode;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Build the equivalent of an OfTypeExpression over the input (ie) produce the set of values from the
 | |
|         /// input that are of the desired type (exactly of the desired type, if the "includeSubtypes" parameter is false).
 | |
|         /// 
 | |
|         /// Further more, "update" the result element type to be the desired type.
 | |
|         /// 
 | |
|         /// We accomplish this by first building a FilterOp with an IsOf (or an IsOfOnly) predicate for the desired 
 | |
|         /// type. We then build out a ProjectOp over the FilterOp, where we introduce a "Fake" TreatOp over the input
 | |
|         /// element to cast it to the right type. The "Fake" TreatOp is only there for "compile-time" typing reasons,
 | |
|         /// and will be ignored in the rest of the plan compiler
 | |
|         /// </summary>
 | |
|         /// <param name="inputNode">the input collection</param>
 | |
|         /// <param name="inputVar">the single Var produced by the input collection</param>
 | |
|         /// <param name="desiredType">the desired element type </param>
 | |
|         /// <param name="includeSubtypes">do we include subtypes of the desired element type</param>
 | |
|         /// <param name="resultNode">the result subtree</param>
 | |
|         /// <param name="resultVar">the single Var produced by the result subtree</param>
 | |
|         internal void BuildOfTypeTree(Node inputNode, Var inputVar, TypeUsage desiredType, bool includeSubtypes,
 | |
|             out Node resultNode, out Var resultVar)
 | |
|         {
 | |
|             Op isOfOp = includeSubtypes ? this.CreateIsOfOp(desiredType) : this.CreateIsOfOnlyOp(desiredType);
 | |
|             Node predicate = this.CreateNode(isOfOp, this.CreateNode(this.CreateVarRefOp(inputVar)));
 | |
|             Node filterNode = this.CreateNode(this.CreateFilterOp(), inputNode, predicate);
 | |
| 
 | |
|             resultNode = BuildFakeTreatProject(filterNode, inputVar, desiredType, out resultVar);
 | |
|         }
 | |
| 
 | |
|         /// Builds out a ProjectOp over the input that introduces a "Fake" TreatOp over the input Var to cast it to the desired type
 | |
|         /// The "Fake" TreatOp is only there for "compile-time" typing reasons, and will be ignored in the rest of the plan compiler.
 | |
|         /// </summary>
 | |
|         /// <param name="inputNode">the input collection</param>
 | |
|         /// <param name="inputVar">the single Var produced by the input collection</param>
 | |
|         /// <param name="desiredType">the desired element type </param>
 | |
|         /// <param name="resultVar">the single Var produced by the result subtree</param>
 | |
|         /// <returns>the result subtree</returns>
 | |
|         internal Node BuildFakeTreatProject(Node inputNode, Var inputVar, TypeUsage desiredType, out Var resultVar)
 | |
|         {
 | |
|             Node treatNode = this.CreateNode(this.CreateFakeTreatOp(desiredType), 
 | |
|                 this.CreateNode(this.CreateVarRefOp(inputVar)));
 | |
|             Node resultNode = this.BuildProject(inputNode, treatNode, out resultVar);
 | |
|             return resultNode;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Build a comparisonOp over the input arguments. Build SoftCasts over the inputs, if we need
 | |
|         /// to.
 | |
|         /// </summary>
 | |
|         /// <param name="opType">the comparison optype</param>
 | |
|         /// <param name="arg0">Arg 0</param>
 | |
|         /// <param name="arg1">Arg 1</param>
 | |
|         /// <returns>the resulting comparison tree</returns>
 | |
|         internal Node BuildComparison(OpType opType, Node arg0, Node arg1)
 | |
|         {
 | |
|             if (!Command.EqualTypes(arg0.Op.Type, arg1.Op.Type))
 | |
|             {
 | |
|                 TypeUsage commonType = TypeHelpers.GetCommonTypeUsage(arg0.Op.Type, arg1.Op.Type);
 | |
|                 Debug.Assert(commonType != null, "No common type for " + arg0.Op.Type + " and " + arg1.Op.Type);
 | |
|                 if (!EqualTypes(commonType, arg0.Op.Type))
 | |
|                 {
 | |
|                     arg0 = this.CreateNode(this.CreateSoftCastOp(commonType), arg0);
 | |
|                 }
 | |
|                 if (!EqualTypes(commonType, arg1.Op.Type))
 | |
|                 {
 | |
|                     arg1 = this.CreateNode(this.CreateSoftCastOp(commonType), arg1);
 | |
|                 }
 | |
|             }
 | |
|             Node newNode = this.CreateNode(this.CreateComparisonOp(opType), arg0, arg1);
 | |
|             return newNode;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Build up a CollectOp over a relop tree
 | |
|         /// </summary>
 | |
|         /// <param name="relOpNode">the relop tree</param>
 | |
|         /// <param name="relOpVar">the single output var from the relop tree</param>
 | |
|         /// <returns></returns>
 | |
|         internal Node BuildCollect(Node relOpNode, Var relOpVar)
 | |
|         {
 | |
|             Node physicalProjectNode = this.CreateNode(this.CreatePhysicalProjectOp(relOpVar), relOpNode);
 | |
|             TypeUsage collectOpType = TypeHelpers.CreateCollectionTypeUsage(relOpVar.Type);
 | |
|             Node collectNode = this.CreateNode(this.CreateCollectOp(collectOpType), physicalProjectNode);
 | |
|             return collectNode;
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region Rel Properties
 | |
|         /// <summary>
 | |
|         /// Mark this rel-property as "referenced" in the current query, if the target
 | |
|         /// end has multiplicity of one (or zero_or_one)
 | |
|         /// </summary>
 | |
|         /// <param name="relProperty">the rel-property</param>
 | |
|         private void AddRelPropertyReference(RelProperty relProperty)
 | |
|         {
 | |
|             if (relProperty.ToEnd.RelationshipMultiplicity != RelationshipMultiplicity.Many &&
 | |
|                 !m_referencedRelProperties.Contains(relProperty))
 | |
|             {
 | |
|                 m_referencedRelProperties.Add(relProperty);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// The set of referenced rel properties in the current query
 | |
|         /// </summary>
 | |
|         internal HashSet<RelProperty> ReferencedRelProperties
 | |
|         {
 | |
|             get { return m_referencedRelProperties; }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Is this rel-property referenced in the query so far
 | |
|         /// </summary>
 | |
|         /// <param name="relProperty">the rel-property</param>
 | |
|         /// <returns>true, if the rel property was referenced in the query</returns>
 | |
|         internal bool IsRelPropertyReferenced(RelProperty relProperty)
 | |
|         {
 | |
|             bool ret = m_referencedRelProperties.Contains(relProperty);
 | |
|             return ret;
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
|     }
 | |
| 
 | |
| }
 |