Command.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / Query / InternalTrees / Command.cs / 2 / Command.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....], [....]
//--------------------------------------------------------------------- 
 
using System;
using System.Collections.Generic; 
using System.Text;
using System.Diagnostics;
using System.Globalization;
using System.Data.Common; 
using System.Data.Metadata.Edm;
using System.Data.Query.PlanCompiler; 
 
namespace System.Data.Query.InternalTrees
{ 
    /// 
    /// 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 
    /// 
    internal class Command 
    {
        #region private state
        private Dictionary m_parameterMap;
        private List m_vars; 
        private List m_tables;
        private Node m_root; 
        private MetadataWorkspace m_metadataWorkspace; 
        private DataSpace m_dataSpace;
        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 m_freeVarVecEnumerators;
        private Stack m_freeVarVecs;
 

        // set of referenced rel properties in this query 
        private HashSet m_referencedRelProperties; 
        #endregion
 
        #region constructors
        /// 
        /// Creates a new command
        ///  
        internal Command(MetadataWorkspace metadataWorkspace, DataSpace dataSpace)
        { 
            m_parameterMap = new Dictionary(); 
            m_vars = new List();
            m_tables = new List
(); m_metadataWorkspace = metadataWorkspace; m_dataSpace = dataSpace; 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(); m_freeVarVecs = new Stack(); m_referencedRelProperties = new HashSet(); } #endregion #region public methods /// /// Gets the metadata workspace associated with this command /// internal MetadataWorkspace MetadataWorkspace { get { return m_metadataWorkspace; } } /// /// Gets the data space in which metadata used by this command must reside /// internal DataSpace DataSpace { get { return m_dataSpace; } } /// /// Gets/sets the root node of the query /// internal Node Root { get { return m_root; } set { m_root = value; } } internal void DisableVarVecEnumCaching() { m_disableVarVecEnumCaching = true; } /// /// Adds the current set of parameters to the specified list /// /// internal void GetParameters(List destList) { Debug.Assert(destList != null, "Destination list is null"); foreach (ParameterVar paramVar in m_parameterMap.Values) { destList.Add(paramVar); } } /// /// Returns the next value for a UnionAll BranchDiscriminator. /// internal int NextBranchDiscriminatorValue { get { return m_nextBranchDiscriminatorValue++; } } /// /// Returns the next value for a node id, without incrementing it. /// internal int NextNodeId { get { return m_nextNodeId; } } #region Metadata Helpers /// /// Helper routine to get the metadata representation for the bool type /// internal TypeUsage BooleanType { get { return m_boolType; } } /// /// Helper routine to get the metadata representation of the int type /// internal TypeUsage IntegerType { get { return m_intType; } } /// /// Helper routine to get the metadata representation of the string type /// internal TypeUsage StringType { get { return m_stringType; } } /// /// Get the primitive type by primitive type kind /// /// EdmMetadata.PrimitiveTypeKind of the primitive type /// A TypeUsage that represents the specified primitive type /// True if the specified primitive type could be retrieved; otherwise false. 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 /// /// VarVec constructor /// /// A new, empty, VarVec internal VarVec CreateVarVec() { VarVec vec; if (m_freeVarVecs.Count == 0) { vec = new VarVec(this); } else { vec = m_freeVarVecs.Pop(); vec.Clear(); } return vec; } /// /// Create a VarVec with a single Var /// /// /// internal VarVec CreateVarVec(Var v) { VarVec varset = CreateVarVec(); varset.Set(v); return varset; } /// /// Create a VarVec with the set of specified vars /// /// /// internal VarVec CreateVarVec(IEnumerable v) { VarVec vec = CreateVarVec(); vec.InitFrom(v); return vec; } /// /// Create a new VarVec from the input VarVec /// /// /// internal VarVec CreateVarVec(VarVec v) { VarVec vec = CreateVarVec(); vec.InitFrom(v); return vec; } /// /// Release a VarVec to the freelist /// /// internal void ReleaseVarVec(VarVec vec) { m_freeVarVecs.Push(vec); } #endregion #region VarVecEnumerator /// /// Create a new enumerator for a VarVec; use a free one if its /// available; otherwise, create a new one /// /// /// 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; } /// /// Release an enumerator; keep it in a local stack for future use /// /// internal void ReleaseVarVecEnumerator(VarVec.VarVecEnumerator enumerator) { if (!m_disableVarVecEnumCaching) { m_freeVarVecEnumerators.Push(enumerator); } } #endregion #region VarList /// /// Create an ordered list of Vars - initially empty /// /// internal static VarList CreateVarList() { return new VarList(); } /// /// Create an ordered list of Vars /// /// /// internal static VarList CreateVarList(IEnumerable 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; } /// /// Create a table whose element type is "elementType" /// /// type of each element (row) of the table /// a table definition object internal static TableMD CreateTableDefinition(TypeUsage elementType) { return new TableMD(elementType, null); } /// /// Creates a new table definition based on an extent. The element type /// of the extent manifests as the single column of the table /// /// the metadata extent /// A new TableMD instance based on the extent internal static TableMD CreateTableDefinition(EntitySetBase extent) { return new TableMD(TypeUsage.Create(extent.ElementType), extent); } /// /// Create a "flat" table definition object (ie) the table has one column /// for each property of the specified row type /// /// the shape of each row of the table /// the table definition internal TableMD CreateFlatTableDefinition(RowType type) { return CreateFlatTableDefinition(type.Properties, new List(), null); } /// /// 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 /// /// list of columns for the table /// the key columns (if any) /// (OPTIONAL) entityset corresponding to this table /// internal TableMD CreateFlatTableDefinition(IEnumerable properties, IEnumerable keyMembers, EntitySetBase entitySet) { return new TableMD(properties, keyMembers, entitySet); } /// /// Creates a new table instance /// /// table metadata /// A new Table instance with columns as defined in the specified metadata internal Table CreateTableInstance(TableMD tableMetadata) { Table t = new Table(this, tableMetadata, NewTableId()); m_tables.Add(t); return t; } #endregion #region Var Access /// /// All vars in the query /// internal IEnumerable Vars { get { return m_vars; } } /// /// Access an existing variable in the query (by its id) /// /// The ID of the variable to retrieve /// The variable with the specified ID internal Var GetVar(int id) { return m_vars[id]; } /// /// Gets the ParameterVar that corresponds to a given named parameter /// /// The name of the parameter for which to retrieve the ParameterVar /// The ParameterVar that corresponds to the specified parameter internal ParameterVar GetParameter(string paramName) { return m_parameterMap[paramName]; } #endregion #region Var Creation private int NewVarId() { return m_vars.Count; } /// /// Creates a variable for a parameter in the query /// /// The name of the parameter for which to create the var /// The type of the parameter, and therefore the new var /// A new ParameterVar instance with the specified name and type 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; } /// /// Creates a new var for a table column /// /// The table instance that produces the column /// column metadata /// A new ColumnVar instance that references the specified column in the given table 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; } /// /// Creates a computed var (ie) a variable that is computed by an expression /// /// The type of the result produced by the expression that defines the variable /// A new ComputedVar instance with the specified result type internal ComputedVar CreateComputedVar(TypeUsage type) { ComputedVar v = new ComputedVar(NewVarId(), type); m_vars.Add(v); return v; } /// /// Creates a SetOp Var of /// /// Datatype of the Var /// A new SetOp Var with the specified result type 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) // /// /// Creates a Node with zero children /// /// The operator that the Node should reference /// A new Node with zero children that references the specified Op internal Node CreateNode(Op op) { return this.CreateNode(op, new List()); } /// /// Creates a node with a single child Node /// /// The operator that the Node should reference /// The single child Node /// A new Node with the specified child Node, that references the specified Op internal Node CreateNode(Op op, Node arg1) { List l = new List(); l.Add(arg1); return this.CreateNode(op, l); } /// /// Creates a node with two child Nodes /// /// The operator that the Node should reference /// The first child Node /// the second child Node /// A new Node with the specified child Nodes, that references the specified Op internal Node CreateNode(Op op, Node arg1, Node arg2) { List l = new List(); l.Add(arg1); l.Add(arg2); return this.CreateNode(op, l); } /// /// Creates a node with 3 child Nodes /// /// The operator that the Node should reference /// The first child Node /// The second child Node /// The third child Node /// A new Node with the specified child Nodes, that references the specified Op internal Node CreateNode(Op op, Node arg1, Node arg2, Node arg3) { List l = new List(); l.Add(arg1); l.Add(arg2); l.Add(arg3); return this.CreateNode(op, l); } /// /// Create a Node with the specified list of child Nodes /// /// The operator that the Node should reference /// The list of child Nodes /// A new Node with the specified child nodes, that references the specified Op internal Node CreateNode(Op op, IList args) { return new Node(m_nextNodeId++, op, new List(args)); } /// /// Create a Node with the specified list of child Nodes /// /// The operator that the Node should reference /// The list of child Nodes /// A new Node with the specified child nodes, that references the specified Op internal Node CreateNode(Op op, List args) { return new Node(m_nextNodeId++, op, args); } #endregion #region ScalarOps /// /// Creates a new ConstantOp /// /// The type of the constant value /// The constant value (may be null) /// A new ConstantOp with the specified type and value 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); } } /// /// 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 /// /// datatype of the constant /// constant value /// a new "internal" constant op that represents the constant internal InternalConstantOp CreateInternalConstantOp(TypeUsage type, object value) { return new InternalConstantOp(type, value); } /// /// An "internal" null constant /// /// datatype of the null constant /// a new "internal" null constant op internal NullOp CreateNullOp(TypeUsage type) { return new NullOp(type); } /// /// Create a constant predicateOp /// /// value of the constant predicate /// internal ConstantPredicateOp CreateConstantPredicateOp(bool value) { return value ? m_trueOp : m_falseOp; } /// /// Create a constant predicate with value=true /// /// internal ConstantPredicateOp CreateTrueOp() { return m_trueOp; } /// /// Create a constant predicateOp with the value false /// /// internal ConstantPredicateOp CreateFalseOp() { return m_falseOp; } /// /// Creates a new FunctionOp /// /// EdmFunction metadata that represents the function that is invoked by the Op /// A new FunctionOp that references the specified function metadata internal FunctionOp CreateFunctionOp(EdmFunction function) { return new FunctionOp(function); } /// /// Creates a new TreatOp /// /// Type metadata that specifies the type that the child of the treat node should be treated as /// A new TreatOp that references the specified type metadata internal TreatOp CreateTreatOp(TypeUsage type) { return new TreatOp(type, false); } /// /// Create a "dummy" treatOp (i.e.) we can actually ignore the treatOp. /// /// /// internal TreatOp CreateFakeTreatOp(TypeUsage type) { return new TreatOp(type, true); } /// /// Creates a new IsOfOp, which tests if the argument is of the specified type or a promotable type /// /// Type metadata that specifies the type with which the type of the argument should be compared /// A new IsOfOp that references the specified type metadata internal IsOfOp CreateIsOfOp(TypeUsage isOfType) { return new IsOfOp(isOfType, false/*only*/, m_boolType); } /// /// Creates a new IsOfOp, which tests if the argument is of the specified type (and only the specified type) /// /// Type metadata that specifies the type with which the type of the argument should be compared /// A new IsOfOp that references the specified type metadata internal IsOfOp CreateIsOfOnlyOp(TypeUsage isOfType) { return new IsOfOp(isOfType, true /* "only" */, m_boolType); } /// /// Creates a new CastOp /// /// Type metadata that represents the type to which the argument should be cast /// A new CastOp that references the specified type metadata internal CastOp CreateCastOp(TypeUsage type) { return new CastOp(type); } /// /// 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 /// /// Type metadata that represents the type to which the argument should be cast /// A new CastOp that references the specified type metadata internal SoftCastOp CreateSoftCastOp(TypeUsage type) { return new SoftCastOp(type); } /// /// Creates a new ComparisonOp of the specified type /// /// An OpType that specifies one of the valid comparison OpTypes: EQ, GT, GE, NE, LT, LE /// A new ComparisonOp of the specified comparison OpType internal ComparisonOp CreateComparisonOp(OpType opType) { return new ComparisonOp(opType, this.BooleanType); } /// /// Creates a new LikeOp /// /// The new LikeOp internal LikeOp CreateLikeOp() { return new LikeOp(this.BooleanType); } /// /// Creates a new ConditionalOp of the specified type /// /// An OpType that specifies one of the valid condition operations: And, Or, Not, IsNull /// A new ConditionalOp with the specified conditional OpType internal ConditionalOp CreateConditionalOp(OpType opType) { return new ConditionalOp(opType, this.BooleanType); } /// /// Creates a new CaseOp /// /// The result type of the CaseOp /// A new CaseOp with the specified result type internal CaseOp CreateCaseOp(TypeUsage type) { return new CaseOp(type); } /// /// Creates a new AggregateOp /// /// EdmFunction metadata that specifies the aggregate function /// Indicates whether or not the aggregate is a distinct aggregate /// A new AggregateOp with the specified function metadata and distinct property internal AggregateOp CreateAggregateOp(EdmFunction aggFunc, bool distinctAgg) { return new AggregateOp(aggFunc, distinctAgg); } /// /// Creates a named type constructor /// /// Type metadata that specifies the type of the instance to construct /// A new NewInstanceOp with the specified result type internal NewInstanceOp CreateNewInstanceOp(TypeUsage type) { return new NewInstanceOp(type); } /// /// Build out a new NewEntityOp /// /// the entity type /// the list of relationship properties /// the entity set (if any) /// internal NewEntityOp CreateNewEntityOp(TypeUsage type, List relProperties, EntitySetBase entitySet) { return new NewEntityOp(type, relProperties, entitySet); } internal NewEntityOp CreateNewEntityOp(TypeUsage type, List relProperties) { return CreateNewEntityOp(type, relProperties, null); } /// /// Create a discriminated named type constructor /// /// Type metadata that specifies the type of the instance to construct /// Mapping information including discriminator values /// the entityset that this instance belongs to /// list of rel properties that have corresponding values /// A new DiscriminatedNewInstanceOp with the specified result type and discrimination behavior internal DiscriminatedNewEntityOp CreateDiscriminatedNewEntityOp(TypeUsage type, ExplicitDiscriminatorMap discriminatorMap, EntitySetBase entitySet, List relProperties) { return new DiscriminatedNewEntityOp(type, discriminatorMap, entitySet, relProperties); } /// /// Creates a multiset constructor /// /// Type metadata that specifies the type of the multiset to construct /// A new NewMultiSetOp with the specified result type internal NewMultisetOp CreateNewMultisetOp(TypeUsage type) { return new NewMultisetOp(type); } /// /// Creates a record constructor /// /// Type metadata that specifies that record type to construct /// A new NewRecordOp with the specified result type internal NewRecordOp CreateNewRecordOp(TypeUsage type) { return new NewRecordOp(type); } /// /// Creates a record constructor /// /// Type metadata that specifies that record type to construct /// A new NewRecordOp with the specified result type internal NewRecordOp CreateNewRecordOp(RowType type) { return new NewRecordOp(TypeUsage.Create(type)); } /// /// 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. /// /// /// /// internal NewRecordOp CreateNewRecordOp(TypeUsage type, List fields) { return new NewRecordOp(type, fields); } /// /// Creates a new VarRefOp /// /// The variable to reference /// A new VarRefOp that references the specified variable internal VarRefOp CreateVarRefOp(Var v) { return new VarRefOp(v); } /// /// Creates a new ArithmeticOp of the specified type /// /// An OpType that specifies one of the valid arithmetic operations: Plus, Minus, Multiply, Divide, Modulo, UnaryMinus /// Type metadata that specifies the result type of the arithmetic operation /// A new ArithmeticOp of the specified arithmetic OpType internal ArithmeticOp CreateArithmeticOp(OpType opType, TypeUsage type) { return new ArithmeticOp(opType, type); } /// /// Creates a new PropertyOp /// /// EdmProperty metadata that specifies the property /// A new PropertyOp that references the specified property metadata 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); } /// /// Create a "relationship" propertyOp /// /// the relationship property /// a RelPropertyOp internal RelPropertyOp CreateRelPropertyOp(RelProperty prop) { AddRelPropertyReference(prop); return new RelPropertyOp(prop.ToEnd.TypeUsage, prop); } /// /// Creates a new RefOp /// /// The EntitySet to which the ref refers /// The result type of the RefOp /// A new RefOp that references the specified EntitySet and has the specified result type internal RefOp CreateRefOp(EntitySet entitySet, TypeUsage type) { return new RefOp(entitySet, type); } /// /// Creates a new ExistsOp /// /// A new ExistsOp internal ExistsOp CreateExistsOp() { return new ExistsOp(this.BooleanType); } /// /// Creates a new ElementOp /// /// Type metadata that specifies the result (element) type /// A new ElementOp with the specified result type internal ElementOp CreateElementOp(TypeUsage type) { return new ElementOp(type); } /// /// Creates a new GetEntityRefOp: a ref-extractor (from an entity instance) Op /// /// Type metadata that specifies the result type /// A new GetEntityKeyOp with the specified result type internal GetEntityRefOp CreateGetEntityRefOp(TypeUsage type) { return new GetEntityRefOp(type); } /// /// Creates a new GetRefKeyOp: a key-extractor (from a ref instance) Op /// /// Type metadata that specifies the result type /// A new GetRefKeyOp with the specified result type internal GetRefKeyOp CreateGetRefKeyOp(TypeUsage type) { return new GetRefKeyOp(type); } /// /// Creates a new CollectOp /// /// Type metadata that specifies the result type of the Nest operation /// A new NestOp with the specified result type internal CollectOp CreateCollectOp(TypeUsage type) { return new CollectOp(type); } /// /// Create a DerefOp /// /// Entity type of the target entity /// a DerefOp internal DerefOp CreateDerefOp(TypeUsage type) { return new DerefOp(type); } /// /// Create a new NavigateOp node /// /// the output type of the navigateOp /// the relationship property /// the navigateOp internal NavigateOp CreateNavigateOp(TypeUsage type, RelProperty relProperty) { // keep track of rel-properties AddRelPropertyReference(relProperty); return new NavigateOp(type, relProperty); } #endregion #region AncillaryOps /// /// Creates a VarDefListOp /// /// A new VarDefListOp internal VarDefListOp CreateVarDefListOp() { return VarDefListOp.Instance; } /// /// Creates a VarDefOp (for a computed var) /// /// The computed var /// A new VarDefOp that references the computed var internal VarDefOp CreateVarDefOp(Var v) { return new VarDefOp(v); } /// /// 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 /// /// /// new Var produced /// 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; } /// /// Creates a VarDefListOp with a single child - a VarDefOp created as in the function /// above. /// /// /// the computed Var produced /// 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 /// /// Creates a new ScanTableOp /// /// A Table metadata instance that specifies the table that should be scanned /// A new ScanTableOp that references a new Table instance based on the specified table metadata internal ScanTableOp CreateScanTableOp(TableMD tableMetadata) { Table table = this.CreateTableInstance(tableMetadata); return CreateScanTableOp(table); } /// /// A variant of the above /// /// The table instance /// a new ScanTableOp internal ScanTableOp CreateScanTableOp(Table table) { return new ScanTableOp(table); } /// /// Creates an instance of a ScanViewOp /// /// the table instance /// a new ScanViewOp internal ScanViewOp CreateScanViewOp(Table table) { return new ScanViewOp(table); } /// /// Creates an instance of a ScanViewOp /// /// the table metadata /// a new ScanViewOp internal ScanViewOp CreateScanViewOp(TableMD tableMetadata) { Table table = this.CreateTableInstance(tableMetadata); return this.CreateScanViewOp(table); } /// /// Creates a new UnnestOp, which creates a streaming result from a scalar (non-RelOp) value /// /// The Var that indicates the value to unnest /// A new UnnestOp that targets the specified Var internal UnnestOp CreateUnnestOp(Var v) { Table t = this.CreateTableInstance(Command.CreateTableDefinition(TypeHelpers.GetEdmType(v.Type).TypeUsage)); return CreateUnnestOp(v, t); } /// /// Creates a new UnnestOp - a variant of the above with the Table supplied /// /// the unnest Var /// the table instance /// a new UnnestOp internal UnnestOp CreateUnnestOp(Var v, Table t) { return new UnnestOp(v, t); } /// /// Creates a new FilterOp /// /// A new FilterOp internal FilterOp CreateFilterOp() { return FilterOp.Instance; } /// /// Creates a new ProjectOp /// /// A VarSet that specifies the Vars produced by the projection /// A new ProjectOp with the specified output VarSet internal ProjectOp CreateProjectOp(VarVec vars) { return new ProjectOp(vars); } /// /// A variant of the above where the ProjectOp produces exactly one var /// /// /// internal ProjectOp CreateProjectOp(Var v) { VarVec varSet = this.CreateVarVec(); varSet.Set(v); return new ProjectOp(varSet); } #region JoinOps /// /// Creates a new InnerJoinOp /// /// A new InnerJoinOp internal InnerJoinOp CreateInnerJoinOp() { return InnerJoinOp.Instance; } /// /// Creates a new LeftOuterJoinOp /// /// A new LeftOuterJoinOp internal LeftOuterJoinOp CreateLeftOuterJoinOp() { return LeftOuterJoinOp.Instance; } /// /// Creates a new FullOuterJoinOp /// /// A new FullOuterJoinOp internal FullOuterJoinOp CreateFullOuterJoinOp() { return FullOuterJoinOp.Instance; } /// /// Creates a new CrossJoinOp /// /// A new CrossJoinOp internal CrossJoinOp CreateCrossJoinOp() { return CrossJoinOp.Instance; } #endregion #region ApplyOps /// /// Creates a new CrossApplyOp /// /// A new CrossApplyOp internal CrossApplyOp CreateCrossApplyOp() { return CrossApplyOp.Instance; } /// /// Creates a new OuterApplyOp /// /// A new OuterApplyOp internal OuterApplyOp CreateOuterApplyOp() { return OuterApplyOp.Instance; } #endregion #region SortKeys /// /// Creates a new SortKey with the specified var, order and collation /// /// The variable to sort on /// The sort order (true for ascending, false for descending) /// The sort collation /// A new SortKey with the specified var, order and collation internal static SortKey CreateSortKey(Var v, bool asc, string collation) { return new SortKey(v, asc, collation); } /// /// Creates a new SortKey with the specified var and order /// /// The variable to sort on /// The sort order (true for ascending, false for descending) /// A new SortKey with the specified var and order internal static SortKey CreateSortKey(Var v, bool asc) { return new SortKey(v, asc, ""); } /// /// Creates a new SortKey with the specified var /// /// The variable to sort on /// A new SortKey with the specified var internal static SortKey CreateSortKey(Var v) { return new SortKey(v, true, ""); } #endregion /// /// Creates a new SortOp /// /// The list of SortKeys that define the sort var, order and collation for each sort key /// A new SortOp with the specified sort keys internal SortOp CreateSortOp(List sortKeys) { return new SortOp(sortKeys); } /// /// Creates a new ConstrainedSortOp /// /// The list of SortKeys that define the sort var, order and collation for each sort key /// A new ConstrainedSortOp with the specified sort keys and a default WithTies value of false internal ConstrainedSortOp CreateConstrainedSortOp(List sortKeys) { return new ConstrainedSortOp(sortKeys, false); } /// /// Creates a new ConstrainedSortOp /// /// The list of SortKeys that define the sort var, order and collation for each sort key /// The value to use for the WithTies property of the new ConstrainedSortOp /// A new ConstrainedSortOp with the specified sort keys and WithTies value internal ConstrainedSortOp CreateConstrainedSortOp(List sortKeys, bool withTies) { return new ConstrainedSortOp(sortKeys, withTies); } /// /// Creates a new GroupByOp /// /// A VarSet that specifies the Key variables produced by the GroupByOp /// A VarSet that specifies all (Key and Aggregate) variables produced by the GroupByOp /// A new GroupByOp with the specified key and output VarSets internal GroupByOp CreateGroupByOp(VarVec gbyKeys, VarVec outputs) { return new GroupByOp(gbyKeys, outputs); } /// /// Creates a new DistinctOp /// list of key vars /// /// A new DistinctOp internal DistinctOp CreateDistinctOp(VarVec keyVars) { return new DistinctOp(keyVars); } /// /// An overload of the above - where the distinct has exactly one key /// /// /// internal DistinctOp CreateDistinctOp(Var keyVar) { return new DistinctOp(this.CreateVarVec(keyVar)); } /// /// Creates a new UnionAllOp /// /// Mappings from the Output Vars to the Vars produced by the left argument /// Mappings from the Output Vars to the Vars produced by the right argument /// A UnionAllOp that references the specified left and right Vars internal UnionAllOp CreateUnionAllOp(VarMap leftMap, VarMap rightMap) { return CreateUnionAllOp(leftMap, rightMap, null); } /// /// Creates a new UnionAllOp, with a branch descriminator. /// /// Mappings from the Output Vars to the Vars produced by the left argument /// Mappings from the Output Vars to the Vars produced by the right argument /// Var that contains the branch discrimination value (may be null until key pullup occurs) /// A UnionAllOp that references the specified left and right Vars 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); } /// /// Creates a new IntersectOp /// /// Mappings from the Output Vars to the Vars produced by the left argument /// Mappings from the Output Vars to the Vars produced by the right argument /// An IntersectOp that references the specified left and right Vars 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); } /// /// Creates a new ExceptOp /// /// Mappings from the Output Vars to the Vars produced by the left argument /// Mappings from the Output Vars to the Vars produced by the right argument /// An ExceptOp that references the specified left and right Vars 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); } /// /// Create a single-row-op (the relop analog of Element) /// /// internal SingleRowOp CreateSingleRowOp() { return SingleRowOp.Instance; } /// /// Create a SingleRowTableOp - a table with exactly one row (and no columns) /// /// internal SingleRowTableOp CreateSingleRowTableOp() { return SingleRowTableOp.Instance; } #endregion #region PhysicalOps /// /// Create a PhysicalProjectOp - with a columnMap describing the output /// /// list of output vars /// columnmap describing the output element /// internal PhysicalProjectOp CreatePhysicalProjectOp(VarList outputVars, SimpleCollectionColumnMap columnMap) { return new PhysicalProjectOp(outputVars, columnMap); } /// /// Create a physicalProjectOp - with a single column output /// /// the output element /// 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 new SortKeyInfo[0]); // sort keys return CreatePhysicalProjectOp(varList, collectionColumnMap); } /// /// Another overload - with an additional discriminatorValue. /// Should this be a subtype instead? /// /// the collectionVar /// column map for the collection element /// elementVars with any nested collections pulled up /// keys specific to this collection /// sort keys specific to this collecion /// discriminator value for this collection (under the current nestOp) /// a new CollectionInfo instance internal static CollectionInfo CreateCollectionInfo(Var collectionVar, ColumnMap columnMap, VarList flattenedElementVars, VarVec keys, List sortKeys, object discriminatorValue) { return new CollectionInfo(collectionVar, columnMap, flattenedElementVars, keys, sortKeys, discriminatorValue); } /// /// Create a singleStreamNestOp /// /// keys for the nest operation /// list of prefix sort keys /// list of postfix sort keys /// List of outputVars /// CollectionInfo for each collection /// Var describing the discriminator /// internal SingleStreamNestOp CreateSingleStreamNestOp(VarVec keys, List prefixSortKeys, List postfixSortKeys, VarVec outputVars, List collectionInfoList, Var discriminatorVar) { return new SingleStreamNestOp(keys, prefixSortKeys, postfixSortKeys, outputVars, collectionInfoList, discriminatorVar); } /// /// Create a MultiStreamNestOp /// /// list of prefix sort keys /// List of outputVars /// CollectionInfo for each collection element /// internal MultiStreamNestOp CreateMultiStreamNestOp(List prefixSortKeys, VarVec outputVars, List collectionInfoList) { return new MultiStreamNestOp(prefixSortKeys, outputVars, collectionInfoList); } #endregion #region NodeInfo /// /// Get auxilliary information for a Node /// /// the node /// node info for this node internal NodeInfo GetNodeInfo(Node n) { return n.GetNodeInfo(this); } /// /// Get extended node information for a RelOpNode /// /// the node /// extended node info for this node internal ExtendedNodeInfo GetExtendedNodeInfo(Node n) { return n.GetExtendedNodeInfo(this); } /// /// Recompute the nodeinfo for a node /// /// Node in question /// internal NodeInfo RecomputeNodeInfo(Node n) { return m_nodeInfoVisitor.ComputeNodeInfo(n); } #endregion #region KeyInfo /// /// Pulls up keys if necessary and gets the key information for a Node /// /// node /// key information 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 // /// /// 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. /// /// /// /// true, if the types are "equal" internal static bool EqualTypes(TypeUsage x, TypeUsage y) { return PlanCompiler.TypeUsageEqualityComparer.Instance.Equals(x, y); } /// /// Check to see if two types are considered "equal" for the purposes /// of the plan compiler /// /// /// /// true, if the types are "equal" internal static bool EqualTypes(EdmType x, EdmType y) { return PlanCompiler.TypeUsageEqualityComparer.Equals(x, y); } #endregion #region Builder Methods /// /// 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) /// /// list of input nodes - one for each branch /// list of input vars - N for each branch /// the resulting union-all subtree /// the output vars from the union-all subtree internal void BuildUnionAllLadder( IList inputNodes, IList inputVars, out Node resultNode, out IList 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 unionAllVars = new List(); 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 setOpVars = new List(); 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; } /// /// A simplified version of the method above - each branch can produce only one var /// /// /// /// /// internal void BuildUnionAllLadder(IList inputNodes, IList inputVars, out Node resultNode, out Var resultVar) { Debug.Assert(inputNodes.Count == inputVars.Count, "Count mismatch:" + inputNodes.Count + "," + inputVars.Count); IList varList; BuildUnionAllLadder(inputNodes, inputVars, out resultNode, out varList); if (varList != null && varList.Count > 0) { resultVar = varList[0]; } else { resultVar = null; } } /// /// 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) /// /// the input relop to the project /// List of vars from the input that need to be projected /// list (possibly empty) of any computed expressions /// internal Node BuildProject(Node inputNode, IEnumerable inputVars, IEnumerable 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; } /// /// 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 /// /// the input relop /// the computed expression /// (output) the computed var corresponding to the computed expression /// the new project subtree node 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; } /// /// 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 /// /// the input collection /// the single Var produced by the input collection /// the desired element type /// do we include subtypes of the desired element type /// the result subtree /// the single Var produced by the result subtree 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); Node treatNode = this.CreateNode(this.CreateFakeTreatOp(desiredType), this.CreateNode(this.CreateVarRefOp(inputVar))); resultNode = this.BuildProject(filterNode, treatNode, out resultVar); } /// /// Build a comparisonOp over the input arguments. Build SoftCasts over the inputs, if we need /// to. /// /// the comparison optype /// Arg 0 /// Arg 1 /// the resulting comparison tree 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; } /// /// Build up a CollectOp over a relop tree /// /// the relop tree /// the single output var from the relop tree /// 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 /// /// Mark this rel-property as "referenced" in the current query, if the target /// end has multiplicity of one (or zero_or_one) /// /// the rel-property private void AddRelPropertyReference(RelProperty relProperty) { if (relProperty.ToEnd.RelationshipMultiplicity != RelationshipMultiplicity.Many && !m_referencedRelProperties.Contains(relProperty)) { m_referencedRelProperties.Add(relProperty); } } /// /// The set of referenced rel properties in the current query /// internal HashSet ReferencedRelProperties { get { return m_referencedRelProperties; } } /// /// Is this rel-property referenced in the query so far /// /// the rel-property /// true, if the rel property was referenced in the query internal bool IsRelPropertyReferenced(RelProperty relProperty) { bool ret = m_referencedRelProperties.Contains(relProperty); return ret; } #endregion #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....], [....] //--------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Globalization; using System.Data.Common; using System.Data.Metadata.Edm; using System.Data.Query.PlanCompiler; namespace System.Data.Query.InternalTrees { /// /// 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 /// internal class Command { #region private state private Dictionary m_parameterMap; private List m_vars; private List
m_tables; private Node m_root; private MetadataWorkspace m_metadataWorkspace; private DataSpace m_dataSpace; 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 m_freeVarVecEnumerators; private Stack m_freeVarVecs; // set of referenced rel properties in this query private HashSet m_referencedRelProperties; #endregion #region constructors /// /// Creates a new command /// internal Command(MetadataWorkspace metadataWorkspace, DataSpace dataSpace) { m_parameterMap = new Dictionary(); m_vars = new List(); m_tables = new List
(); m_metadataWorkspace = metadataWorkspace; m_dataSpace = dataSpace; 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(); m_freeVarVecs = new Stack(); m_referencedRelProperties = new HashSet(); } #endregion #region public methods /// /// Gets the metadata workspace associated with this command /// internal MetadataWorkspace MetadataWorkspace { get { return m_metadataWorkspace; } } /// /// Gets the data space in which metadata used by this command must reside /// internal DataSpace DataSpace { get { return m_dataSpace; } } /// /// Gets/sets the root node of the query /// internal Node Root { get { return m_root; } set { m_root = value; } } internal void DisableVarVecEnumCaching() { m_disableVarVecEnumCaching = true; } /// /// Adds the current set of parameters to the specified list /// /// internal void GetParameters(List destList) { Debug.Assert(destList != null, "Destination list is null"); foreach (ParameterVar paramVar in m_parameterMap.Values) { destList.Add(paramVar); } } /// /// Returns the next value for a UnionAll BranchDiscriminator. /// internal int NextBranchDiscriminatorValue { get { return m_nextBranchDiscriminatorValue++; } } /// /// Returns the next value for a node id, without incrementing it. /// internal int NextNodeId { get { return m_nextNodeId; } } #region Metadata Helpers /// /// Helper routine to get the metadata representation for the bool type /// internal TypeUsage BooleanType { get { return m_boolType; } } /// /// Helper routine to get the metadata representation of the int type /// internal TypeUsage IntegerType { get { return m_intType; } } /// /// Helper routine to get the metadata representation of the string type /// internal TypeUsage StringType { get { return m_stringType; } } /// /// Get the primitive type by primitive type kind /// /// EdmMetadata.PrimitiveTypeKind of the primitive type /// A TypeUsage that represents the specified primitive type /// True if the specified primitive type could be retrieved; otherwise false. 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 /// /// VarVec constructor /// /// A new, empty, VarVec internal VarVec CreateVarVec() { VarVec vec; if (m_freeVarVecs.Count == 0) { vec = new VarVec(this); } else { vec = m_freeVarVecs.Pop(); vec.Clear(); } return vec; } /// /// Create a VarVec with a single Var /// /// /// internal VarVec CreateVarVec(Var v) { VarVec varset = CreateVarVec(); varset.Set(v); return varset; } /// /// Create a VarVec with the set of specified vars /// /// /// internal VarVec CreateVarVec(IEnumerable v) { VarVec vec = CreateVarVec(); vec.InitFrom(v); return vec; } /// /// Create a new VarVec from the input VarVec /// /// /// internal VarVec CreateVarVec(VarVec v) { VarVec vec = CreateVarVec(); vec.InitFrom(v); return vec; } /// /// Release a VarVec to the freelist /// /// internal void ReleaseVarVec(VarVec vec) { m_freeVarVecs.Push(vec); } #endregion #region VarVecEnumerator /// /// Create a new enumerator for a VarVec; use a free one if its /// available; otherwise, create a new one /// /// /// 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; } /// /// Release an enumerator; keep it in a local stack for future use /// /// internal void ReleaseVarVecEnumerator(VarVec.VarVecEnumerator enumerator) { if (!m_disableVarVecEnumCaching) { m_freeVarVecEnumerators.Push(enumerator); } } #endregion #region VarList /// /// Create an ordered list of Vars - initially empty /// /// internal static VarList CreateVarList() { return new VarList(); } /// /// Create an ordered list of Vars /// /// /// internal static VarList CreateVarList(IEnumerable 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; } /// /// Create a table whose element type is "elementType" /// /// type of each element (row) of the table /// a table definition object internal static TableMD CreateTableDefinition(TypeUsage elementType) { return new TableMD(elementType, null); } /// /// Creates a new table definition based on an extent. The element type /// of the extent manifests as the single column of the table /// /// the metadata extent /// A new TableMD instance based on the extent internal static TableMD CreateTableDefinition(EntitySetBase extent) { return new TableMD(TypeUsage.Create(extent.ElementType), extent); } /// /// Create a "flat" table definition object (ie) the table has one column /// for each property of the specified row type /// /// the shape of each row of the table /// the table definition internal TableMD CreateFlatTableDefinition(RowType type) { return CreateFlatTableDefinition(type.Properties, new List(), null); } /// /// 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 /// /// list of columns for the table /// the key columns (if any) /// (OPTIONAL) entityset corresponding to this table /// internal TableMD CreateFlatTableDefinition(IEnumerable properties, IEnumerable keyMembers, EntitySetBase entitySet) { return new TableMD(properties, keyMembers, entitySet); } /// /// Creates a new table instance /// /// table metadata /// A new Table instance with columns as defined in the specified metadata internal Table CreateTableInstance(TableMD tableMetadata) { Table t = new Table(this, tableMetadata, NewTableId()); m_tables.Add(t); return t; } #endregion #region Var Access /// /// All vars in the query /// internal IEnumerable Vars { get { return m_vars; } } /// /// Access an existing variable in the query (by its id) /// /// The ID of the variable to retrieve /// The variable with the specified ID internal Var GetVar(int id) { return m_vars[id]; } /// /// Gets the ParameterVar that corresponds to a given named parameter /// /// The name of the parameter for which to retrieve the ParameterVar /// The ParameterVar that corresponds to the specified parameter internal ParameterVar GetParameter(string paramName) { return m_parameterMap[paramName]; } #endregion #region Var Creation private int NewVarId() { return m_vars.Count; } /// /// Creates a variable for a parameter in the query /// /// The name of the parameter for which to create the var /// The type of the parameter, and therefore the new var /// A new ParameterVar instance with the specified name and type 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; } /// /// Creates a new var for a table column /// /// The table instance that produces the column /// column metadata /// A new ColumnVar instance that references the specified column in the given table 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; } /// /// Creates a computed var (ie) a variable that is computed by an expression /// /// The type of the result produced by the expression that defines the variable /// A new ComputedVar instance with the specified result type internal ComputedVar CreateComputedVar(TypeUsage type) { ComputedVar v = new ComputedVar(NewVarId(), type); m_vars.Add(v); return v; } /// /// Creates a SetOp Var of /// /// Datatype of the Var /// A new SetOp Var with the specified result type 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) // /// /// Creates a Node with zero children /// /// The operator that the Node should reference /// A new Node with zero children that references the specified Op internal Node CreateNode(Op op) { return this.CreateNode(op, new List()); } /// /// Creates a node with a single child Node /// /// The operator that the Node should reference /// The single child Node /// A new Node with the specified child Node, that references the specified Op internal Node CreateNode(Op op, Node arg1) { List l = new List(); l.Add(arg1); return this.CreateNode(op, l); } /// /// Creates a node with two child Nodes /// /// The operator that the Node should reference /// The first child Node /// the second child Node /// A new Node with the specified child Nodes, that references the specified Op internal Node CreateNode(Op op, Node arg1, Node arg2) { List l = new List(); l.Add(arg1); l.Add(arg2); return this.CreateNode(op, l); } /// /// Creates a node with 3 child Nodes /// /// The operator that the Node should reference /// The first child Node /// The second child Node /// The third child Node /// A new Node with the specified child Nodes, that references the specified Op internal Node CreateNode(Op op, Node arg1, Node arg2, Node arg3) { List l = new List(); l.Add(arg1); l.Add(arg2); l.Add(arg3); return this.CreateNode(op, l); } /// /// Create a Node with the specified list of child Nodes /// /// The operator that the Node should reference /// The list of child Nodes /// A new Node with the specified child nodes, that references the specified Op internal Node CreateNode(Op op, IList args) { return new Node(m_nextNodeId++, op, new List(args)); } /// /// Create a Node with the specified list of child Nodes /// /// The operator that the Node should reference /// The list of child Nodes /// A new Node with the specified child nodes, that references the specified Op internal Node CreateNode(Op op, List args) { return new Node(m_nextNodeId++, op, args); } #endregion #region ScalarOps /// /// Creates a new ConstantOp /// /// The type of the constant value /// The constant value (may be null) /// A new ConstantOp with the specified type and value 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); } } /// /// 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 /// /// datatype of the constant /// constant value /// a new "internal" constant op that represents the constant internal InternalConstantOp CreateInternalConstantOp(TypeUsage type, object value) { return new InternalConstantOp(type, value); } /// /// An "internal" null constant /// /// datatype of the null constant /// a new "internal" null constant op internal NullOp CreateNullOp(TypeUsage type) { return new NullOp(type); } /// /// Create a constant predicateOp /// /// value of the constant predicate /// internal ConstantPredicateOp CreateConstantPredicateOp(bool value) { return value ? m_trueOp : m_falseOp; } /// /// Create a constant predicate with value=true /// /// internal ConstantPredicateOp CreateTrueOp() { return m_trueOp; } /// /// Create a constant predicateOp with the value false /// /// internal ConstantPredicateOp CreateFalseOp() { return m_falseOp; } /// /// Creates a new FunctionOp /// /// EdmFunction metadata that represents the function that is invoked by the Op /// A new FunctionOp that references the specified function metadata internal FunctionOp CreateFunctionOp(EdmFunction function) { return new FunctionOp(function); } /// /// Creates a new TreatOp /// /// Type metadata that specifies the type that the child of the treat node should be treated as /// A new TreatOp that references the specified type metadata internal TreatOp CreateTreatOp(TypeUsage type) { return new TreatOp(type, false); } /// /// Create a "dummy" treatOp (i.e.) we can actually ignore the treatOp. /// /// /// internal TreatOp CreateFakeTreatOp(TypeUsage type) { return new TreatOp(type, true); } /// /// Creates a new IsOfOp, which tests if the argument is of the specified type or a promotable type /// /// Type metadata that specifies the type with which the type of the argument should be compared /// A new IsOfOp that references the specified type metadata internal IsOfOp CreateIsOfOp(TypeUsage isOfType) { return new IsOfOp(isOfType, false/*only*/, m_boolType); } /// /// Creates a new IsOfOp, which tests if the argument is of the specified type (and only the specified type) /// /// Type metadata that specifies the type with which the type of the argument should be compared /// A new IsOfOp that references the specified type metadata internal IsOfOp CreateIsOfOnlyOp(TypeUsage isOfType) { return new IsOfOp(isOfType, true /* "only" */, m_boolType); } /// /// Creates a new CastOp /// /// Type metadata that represents the type to which the argument should be cast /// A new CastOp that references the specified type metadata internal CastOp CreateCastOp(TypeUsage type) { return new CastOp(type); } /// /// 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 /// /// Type metadata that represents the type to which the argument should be cast /// A new CastOp that references the specified type metadata internal SoftCastOp CreateSoftCastOp(TypeUsage type) { return new SoftCastOp(type); } /// /// Creates a new ComparisonOp of the specified type /// /// An OpType that specifies one of the valid comparison OpTypes: EQ, GT, GE, NE, LT, LE /// A new ComparisonOp of the specified comparison OpType internal ComparisonOp CreateComparisonOp(OpType opType) { return new ComparisonOp(opType, this.BooleanType); } /// /// Creates a new LikeOp /// /// The new LikeOp internal LikeOp CreateLikeOp() { return new LikeOp(this.BooleanType); } /// /// Creates a new ConditionalOp of the specified type /// /// An OpType that specifies one of the valid condition operations: And, Or, Not, IsNull /// A new ConditionalOp with the specified conditional OpType internal ConditionalOp CreateConditionalOp(OpType opType) { return new ConditionalOp(opType, this.BooleanType); } /// /// Creates a new CaseOp /// /// The result type of the CaseOp /// A new CaseOp with the specified result type internal CaseOp CreateCaseOp(TypeUsage type) { return new CaseOp(type); } /// /// Creates a new AggregateOp /// /// EdmFunction metadata that specifies the aggregate function /// Indicates whether or not the aggregate is a distinct aggregate /// A new AggregateOp with the specified function metadata and distinct property internal AggregateOp CreateAggregateOp(EdmFunction aggFunc, bool distinctAgg) { return new AggregateOp(aggFunc, distinctAgg); } /// /// Creates a named type constructor /// /// Type metadata that specifies the type of the instance to construct /// A new NewInstanceOp with the specified result type internal NewInstanceOp CreateNewInstanceOp(TypeUsage type) { return new NewInstanceOp(type); } /// /// Build out a new NewEntityOp /// /// the entity type /// the list of relationship properties /// the entity set (if any) /// internal NewEntityOp CreateNewEntityOp(TypeUsage type, List relProperties, EntitySetBase entitySet) { return new NewEntityOp(type, relProperties, entitySet); } internal NewEntityOp CreateNewEntityOp(TypeUsage type, List relProperties) { return CreateNewEntityOp(type, relProperties, null); } /// /// Create a discriminated named type constructor /// /// Type metadata that specifies the type of the instance to construct /// Mapping information including discriminator values /// the entityset that this instance belongs to /// list of rel properties that have corresponding values /// A new DiscriminatedNewInstanceOp with the specified result type and discrimination behavior internal DiscriminatedNewEntityOp CreateDiscriminatedNewEntityOp(TypeUsage type, ExplicitDiscriminatorMap discriminatorMap, EntitySetBase entitySet, List relProperties) { return new DiscriminatedNewEntityOp(type, discriminatorMap, entitySet, relProperties); } /// /// Creates a multiset constructor /// /// Type metadata that specifies the type of the multiset to construct /// A new NewMultiSetOp with the specified result type internal NewMultisetOp CreateNewMultisetOp(TypeUsage type) { return new NewMultisetOp(type); } /// /// Creates a record constructor /// /// Type metadata that specifies that record type to construct /// A new NewRecordOp with the specified result type internal NewRecordOp CreateNewRecordOp(TypeUsage type) { return new NewRecordOp(type); } /// /// Creates a record constructor /// /// Type metadata that specifies that record type to construct /// A new NewRecordOp with the specified result type internal NewRecordOp CreateNewRecordOp(RowType type) { return new NewRecordOp(TypeUsage.Create(type)); } /// /// 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. /// /// /// /// internal NewRecordOp CreateNewRecordOp(TypeUsage type, List fields) { return new NewRecordOp(type, fields); } /// /// Creates a new VarRefOp /// /// The variable to reference /// A new VarRefOp that references the specified variable internal VarRefOp CreateVarRefOp(Var v) { return new VarRefOp(v); } /// /// Creates a new ArithmeticOp of the specified type /// /// An OpType that specifies one of the valid arithmetic operations: Plus, Minus, Multiply, Divide, Modulo, UnaryMinus /// Type metadata that specifies the result type of the arithmetic operation /// A new ArithmeticOp of the specified arithmetic OpType internal ArithmeticOp CreateArithmeticOp(OpType opType, TypeUsage type) { return new ArithmeticOp(opType, type); } /// /// Creates a new PropertyOp /// /// EdmProperty metadata that specifies the property /// A new PropertyOp that references the specified property metadata 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); } /// /// Create a "relationship" propertyOp /// /// the relationship property /// a RelPropertyOp internal RelPropertyOp CreateRelPropertyOp(RelProperty prop) { AddRelPropertyReference(prop); return new RelPropertyOp(prop.ToEnd.TypeUsage, prop); } /// /// Creates a new RefOp /// /// The EntitySet to which the ref refers /// The result type of the RefOp /// A new RefOp that references the specified EntitySet and has the specified result type internal RefOp CreateRefOp(EntitySet entitySet, TypeUsage type) { return new RefOp(entitySet, type); } /// /// Creates a new ExistsOp /// /// A new ExistsOp internal ExistsOp CreateExistsOp() { return new ExistsOp(this.BooleanType); } /// /// Creates a new ElementOp /// /// Type metadata that specifies the result (element) type /// A new ElementOp with the specified result type internal ElementOp CreateElementOp(TypeUsage type) { return new ElementOp(type); } /// /// Creates a new GetEntityRefOp: a ref-extractor (from an entity instance) Op /// /// Type metadata that specifies the result type /// A new GetEntityKeyOp with the specified result type internal GetEntityRefOp CreateGetEntityRefOp(TypeUsage type) { return new GetEntityRefOp(type); } /// /// Creates a new GetRefKeyOp: a key-extractor (from a ref instance) Op /// /// Type metadata that specifies the result type /// A new GetRefKeyOp with the specified result type internal GetRefKeyOp CreateGetRefKeyOp(TypeUsage type) { return new GetRefKeyOp(type); } /// /// Creates a new CollectOp /// /// Type metadata that specifies the result type of the Nest operation /// A new NestOp with the specified result type internal CollectOp CreateCollectOp(TypeUsage type) { return new CollectOp(type); } /// /// Create a DerefOp /// /// Entity type of the target entity /// a DerefOp internal DerefOp CreateDerefOp(TypeUsage type) { return new DerefOp(type); } /// /// Create a new NavigateOp node /// /// the output type of the navigateOp /// the relationship property /// the navigateOp internal NavigateOp CreateNavigateOp(TypeUsage type, RelProperty relProperty) { // keep track of rel-properties AddRelPropertyReference(relProperty); return new NavigateOp(type, relProperty); } #endregion #region AncillaryOps /// /// Creates a VarDefListOp /// /// A new VarDefListOp internal VarDefListOp CreateVarDefListOp() { return VarDefListOp.Instance; } /// /// Creates a VarDefOp (for a computed var) /// /// The computed var /// A new VarDefOp that references the computed var internal VarDefOp CreateVarDefOp(Var v) { return new VarDefOp(v); } /// /// 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 /// /// /// new Var produced /// 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; } /// /// Creates a VarDefListOp with a single child - a VarDefOp created as in the function /// above. /// /// /// the computed Var produced /// 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 /// /// Creates a new ScanTableOp /// /// A Table metadata instance that specifies the table that should be scanned /// A new ScanTableOp that references a new Table instance based on the specified table metadata internal ScanTableOp CreateScanTableOp(TableMD tableMetadata) { Table table = this.CreateTableInstance(tableMetadata); return CreateScanTableOp(table); } /// /// A variant of the above /// /// The table instance /// a new ScanTableOp internal ScanTableOp CreateScanTableOp(Table table) { return new ScanTableOp(table); } /// /// Creates an instance of a ScanViewOp /// /// the table instance /// a new ScanViewOp internal ScanViewOp CreateScanViewOp(Table table) { return new ScanViewOp(table); } /// /// Creates an instance of a ScanViewOp /// /// the table metadata /// a new ScanViewOp internal ScanViewOp CreateScanViewOp(TableMD tableMetadata) { Table table = this.CreateTableInstance(tableMetadata); return this.CreateScanViewOp(table); } /// /// Creates a new UnnestOp, which creates a streaming result from a scalar (non-RelOp) value /// /// The Var that indicates the value to unnest /// A new UnnestOp that targets the specified Var internal UnnestOp CreateUnnestOp(Var v) { Table t = this.CreateTableInstance(Command.CreateTableDefinition(TypeHelpers.GetEdmType(v.Type).TypeUsage)); return CreateUnnestOp(v, t); } /// /// Creates a new UnnestOp - a variant of the above with the Table supplied /// /// the unnest Var /// the table instance /// a new UnnestOp internal UnnestOp CreateUnnestOp(Var v, Table t) { return new UnnestOp(v, t); } /// /// Creates a new FilterOp /// /// A new FilterOp internal FilterOp CreateFilterOp() { return FilterOp.Instance; } /// /// Creates a new ProjectOp /// /// A VarSet that specifies the Vars produced by the projection /// A new ProjectOp with the specified output VarSet internal ProjectOp CreateProjectOp(VarVec vars) { return new ProjectOp(vars); } /// /// A variant of the above where the ProjectOp produces exactly one var /// /// /// internal ProjectOp CreateProjectOp(Var v) { VarVec varSet = this.CreateVarVec(); varSet.Set(v); return new ProjectOp(varSet); } #region JoinOps /// /// Creates a new InnerJoinOp /// /// A new InnerJoinOp internal InnerJoinOp CreateInnerJoinOp() { return InnerJoinOp.Instance; } /// /// Creates a new LeftOuterJoinOp /// /// A new LeftOuterJoinOp internal LeftOuterJoinOp CreateLeftOuterJoinOp() { return LeftOuterJoinOp.Instance; } /// /// Creates a new FullOuterJoinOp /// /// A new FullOuterJoinOp internal FullOuterJoinOp CreateFullOuterJoinOp() { return FullOuterJoinOp.Instance; } /// /// Creates a new CrossJoinOp /// /// A new CrossJoinOp internal CrossJoinOp CreateCrossJoinOp() { return CrossJoinOp.Instance; } #endregion #region ApplyOps /// /// Creates a new CrossApplyOp /// /// A new CrossApplyOp internal CrossApplyOp CreateCrossApplyOp() { return CrossApplyOp.Instance; } /// /// Creates a new OuterApplyOp /// /// A new OuterApplyOp internal OuterApplyOp CreateOuterApplyOp() { return OuterApplyOp.Instance; } #endregion #region SortKeys /// /// Creates a new SortKey with the specified var, order and collation /// /// The variable to sort on /// The sort order (true for ascending, false for descending) /// The sort collation /// A new SortKey with the specified var, order and collation internal static SortKey CreateSortKey(Var v, bool asc, string collation) { return new SortKey(v, asc, collation); } /// /// Creates a new SortKey with the specified var and order /// /// The variable to sort on /// The sort order (true for ascending, false for descending) /// A new SortKey with the specified var and order internal static SortKey CreateSortKey(Var v, bool asc) { return new SortKey(v, asc, ""); } /// /// Creates a new SortKey with the specified var /// /// The variable to sort on /// A new SortKey with the specified var internal static SortKey CreateSortKey(Var v) { return new SortKey(v, true, ""); } #endregion /// /// Creates a new SortOp /// /// The list of SortKeys that define the sort var, order and collation for each sort key /// A new SortOp with the specified sort keys internal SortOp CreateSortOp(List sortKeys) { return new SortOp(sortKeys); } /// /// Creates a new ConstrainedSortOp /// /// The list of SortKeys that define the sort var, order and collation for each sort key /// A new ConstrainedSortOp with the specified sort keys and a default WithTies value of false internal ConstrainedSortOp CreateConstrainedSortOp(List sortKeys) { return new ConstrainedSortOp(sortKeys, false); } /// /// Creates a new ConstrainedSortOp /// /// The list of SortKeys that define the sort var, order and collation for each sort key /// The value to use for the WithTies property of the new ConstrainedSortOp /// A new ConstrainedSortOp with the specified sort keys and WithTies value internal ConstrainedSortOp CreateConstrainedSortOp(List sortKeys, bool withTies) { return new ConstrainedSortOp(sortKeys, withTies); } /// /// Creates a new GroupByOp /// /// A VarSet that specifies the Key variables produced by the GroupByOp /// A VarSet that specifies all (Key and Aggregate) variables produced by the GroupByOp /// A new GroupByOp with the specified key and output VarSets internal GroupByOp CreateGroupByOp(VarVec gbyKeys, VarVec outputs) { return new GroupByOp(gbyKeys, outputs); } /// /// Creates a new DistinctOp /// list of key vars /// /// A new DistinctOp internal DistinctOp CreateDistinctOp(VarVec keyVars) { return new DistinctOp(keyVars); } /// /// An overload of the above - where the distinct has exactly one key /// /// /// internal DistinctOp CreateDistinctOp(Var keyVar) { return new DistinctOp(this.CreateVarVec(keyVar)); } /// /// Creates a new UnionAllOp /// /// Mappings from the Output Vars to the Vars produced by the left argument /// Mappings from the Output Vars to the Vars produced by the right argument /// A UnionAllOp that references the specified left and right Vars internal UnionAllOp CreateUnionAllOp(VarMap leftMap, VarMap rightMap) { return CreateUnionAllOp(leftMap, rightMap, null); } /// /// Creates a new UnionAllOp, with a branch descriminator. /// /// Mappings from the Output Vars to the Vars produced by the left argument /// Mappings from the Output Vars to the Vars produced by the right argument /// Var that contains the branch discrimination value (may be null until key pullup occurs) /// A UnionAllOp that references the specified left and right Vars 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); } /// /// Creates a new IntersectOp /// /// Mappings from the Output Vars to the Vars produced by the left argument /// Mappings from the Output Vars to the Vars produced by the right argument /// An IntersectOp that references the specified left and right Vars 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); } /// /// Creates a new ExceptOp /// /// Mappings from the Output Vars to the Vars produced by the left argument /// Mappings from the Output Vars to the Vars produced by the right argument /// An ExceptOp that references the specified left and right Vars 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); } /// /// Create a single-row-op (the relop analog of Element) /// /// internal SingleRowOp CreateSingleRowOp() { return SingleRowOp.Instance; } /// /// Create a SingleRowTableOp - a table with exactly one row (and no columns) /// /// internal SingleRowTableOp CreateSingleRowTableOp() { return SingleRowTableOp.Instance; } #endregion #region PhysicalOps /// /// Create a PhysicalProjectOp - with a columnMap describing the output /// /// list of output vars /// columnmap describing the output element /// internal PhysicalProjectOp CreatePhysicalProjectOp(VarList outputVars, SimpleCollectionColumnMap columnMap) { return new PhysicalProjectOp(outputVars, columnMap); } /// /// Create a physicalProjectOp - with a single column output /// /// the output element /// 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 new SortKeyInfo[0]); // sort keys return CreatePhysicalProjectOp(varList, collectionColumnMap); } /// /// Another overload - with an additional discriminatorValue. /// Should this be a subtype instead? /// /// the collectionVar /// column map for the collection element /// elementVars with any nested collections pulled up /// keys specific to this collection /// sort keys specific to this collecion /// discriminator value for this collection (under the current nestOp) /// a new CollectionInfo instance internal static CollectionInfo CreateCollectionInfo(Var collectionVar, ColumnMap columnMap, VarList flattenedElementVars, VarVec keys, List sortKeys, object discriminatorValue) { return new CollectionInfo(collectionVar, columnMap, flattenedElementVars, keys, sortKeys, discriminatorValue); } /// /// Create a singleStreamNestOp /// /// keys for the nest operation /// list of prefix sort keys /// list of postfix sort keys /// List of outputVars /// CollectionInfo for each collection /// Var describing the discriminator /// internal SingleStreamNestOp CreateSingleStreamNestOp(VarVec keys, List prefixSortKeys, List postfixSortKeys, VarVec outputVars, List collectionInfoList, Var discriminatorVar) { return new SingleStreamNestOp(keys, prefixSortKeys, postfixSortKeys, outputVars, collectionInfoList, discriminatorVar); } /// /// Create a MultiStreamNestOp /// /// list of prefix sort keys /// List of outputVars /// CollectionInfo for each collection element /// internal MultiStreamNestOp CreateMultiStreamNestOp(List prefixSortKeys, VarVec outputVars, List collectionInfoList) { return new MultiStreamNestOp(prefixSortKeys, outputVars, collectionInfoList); } #endregion #region NodeInfo /// /// Get auxilliary information for a Node /// /// the node /// node info for this node internal NodeInfo GetNodeInfo(Node n) { return n.GetNodeInfo(this); } /// /// Get extended node information for a RelOpNode /// /// the node /// extended node info for this node internal ExtendedNodeInfo GetExtendedNodeInfo(Node n) { return n.GetExtendedNodeInfo(this); } /// /// Recompute the nodeinfo for a node /// /// Node in question /// internal NodeInfo RecomputeNodeInfo(Node n) { return m_nodeInfoVisitor.ComputeNodeInfo(n); } #endregion #region KeyInfo /// /// Pulls up keys if necessary and gets the key information for a Node /// /// node /// key information 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 // /// /// 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. /// /// /// /// true, if the types are "equal" internal static bool EqualTypes(TypeUsage x, TypeUsage y) { return PlanCompiler.TypeUsageEqualityComparer.Instance.Equals(x, y); } /// /// Check to see if two types are considered "equal" for the purposes /// of the plan compiler /// /// /// /// true, if the types are "equal" internal static bool EqualTypes(EdmType x, EdmType y) { return PlanCompiler.TypeUsageEqualityComparer.Equals(x, y); } #endregion #region Builder Methods /// /// 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) /// /// list of input nodes - one for each branch /// list of input vars - N for each branch /// the resulting union-all subtree /// the output vars from the union-all subtree internal void BuildUnionAllLadder( IList inputNodes, IList inputVars, out Node resultNode, out IList 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 unionAllVars = new List(); 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 setOpVars = new List(); 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; } /// /// A simplified version of the method above - each branch can produce only one var /// /// /// /// /// internal void BuildUnionAllLadder(IList inputNodes, IList inputVars, out Node resultNode, out Var resultVar) { Debug.Assert(inputNodes.Count == inputVars.Count, "Count mismatch:" + inputNodes.Count + "," + inputVars.Count); IList varList; BuildUnionAllLadder(inputNodes, inputVars, out resultNode, out varList); if (varList != null && varList.Count > 0) { resultVar = varList[0]; } else { resultVar = null; } } /// /// 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) /// /// the input relop to the project /// List of vars from the input that need to be projected /// list (possibly empty) of any computed expressions /// internal Node BuildProject(Node inputNode, IEnumerable inputVars, IEnumerable 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; } /// /// 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 /// /// the input relop /// the computed expression /// (output) the computed var corresponding to the computed expression /// the new project subtree node 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; } /// /// 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 /// /// the input collection /// the single Var produced by the input collection /// the desired element type /// do we include subtypes of the desired element type /// the result subtree /// the single Var produced by the result subtree 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); Node treatNode = this.CreateNode(this.CreateFakeTreatOp(desiredType), this.CreateNode(this.CreateVarRefOp(inputVar))); resultNode = this.BuildProject(filterNode, treatNode, out resultVar); } /// /// Build a comparisonOp over the input arguments. Build SoftCasts over the inputs, if we need /// to. /// /// the comparison optype /// Arg 0 /// Arg 1 /// the resulting comparison tree 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; } /// /// Build up a CollectOp over a relop tree /// /// the relop tree /// the single output var from the relop tree /// 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 /// /// Mark this rel-property as "referenced" in the current query, if the target /// end has multiplicity of one (or zero_or_one) /// /// the rel-property private void AddRelPropertyReference(RelProperty relProperty) { if (relProperty.ToEnd.RelationshipMultiplicity != RelationshipMultiplicity.Many && !m_referencedRelProperties.Contains(relProperty)) { m_referencedRelProperties.Add(relProperty); } } /// /// The set of referenced rel properties in the current query /// internal HashSet ReferencedRelProperties { get { return m_referencedRelProperties; } } /// /// Is this rel-property referenced in the query so far /// /// the rel-property /// true, if the rel property was referenced in the query internal bool IsRelPropertyReferenced(RelProperty relProperty) { bool ret = m_referencedRelProperties.Contains(relProperty); return ret; } #endregion #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK