Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Query / InternalTrees / Command.cs / 1305376 / Command.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
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 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)
{
m_parameterMap = new Dictionary();
m_vars = new List();
m_tables = new List();
m_metadataWorkspace = metadataWorkspace;
if(!TryGetPrimitiveType(PrimitiveTypeKind.Boolean, out m_boolType))
{
throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderBooleanType);
}
if (!TryGetPrimitiveType(PrimitiveTypeKind.Int32, out m_intType))
{
throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderIntegerType);
}
if (!TryGetPrimitiveType(PrimitiveTypeKind.String, out m_stringType))
{
throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderStringType);
}
m_trueOp = new ConstantPredicateOp(m_boolType, true);
m_falseOp = new ConstantPredicateOp(m_boolType, false);
m_nodeInfoVisitor = new NodeInfoVisitor(this);
m_keyPullupVisitor = new PlanCompiler.KeyPullup(this);
// FreeLists
m_freeVarVecEnumerators = new Stack();
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/sets the root node of the query
///
internal Node Root { get { return m_root; } set { m_root = value; } }
internal void DisableVarVecEnumCaching() { m_disableVarVecEnumCaching = true; }
///
/// 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 constant that serves as a null sentinel, i.e. it is only ever used
/// to be checked whether it is null
///
///
internal NullSentinelOp CreateNullSentinelOp()
{
return new NullSentinelOp(this.IntegerType, 1);
}
///
/// 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 GroupByIntoOp
///
/// A VarSet that specifies the Key variables produced by the GroupByOp
/// A VarSet that specifies the vars from the input that represent the real grouping input
/// A VarSet that specifies all (Key and Aggregate) variables produced by the GroupByOp
/// A new GroupByOp with the specified key and output VarSets
internal GroupByIntoOp CreateGroupByIntoOp(VarVec gbyKeys, VarVec inputs, VarVec outputs)
{
return new GroupByIntoOp(gbyKeys, inputs, 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
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, but only if has already been computed
///
/// Node in question
internal void RecomputeNodeInfo(Node n)
{
m_nodeInfoVisitor.RecomputeNodeInfo(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);
resultNode = BuildFakeTreatProject(filterNode, inputVar, desiredType, out resultVar);
}
/// Builds out a ProjectOp over the input that introduces a "Fake" TreatOp over the input Var to cast it to the desired type
/// The "Fake" TreatOp is only there for "compile-time" typing reasons, and will be ignored in the rest of the plan compiler.
///
/// the input collection
/// the single Var produced by the input collection
/// the desired element type
/// the single Var produced by the result subtree
/// the result subtree
internal Node BuildFakeTreatProject(Node inputNode, Var inputVar, TypeUsage desiredType, out Var resultVar)
{
Node treatNode = this.CreateNode(this.CreateFakeTreatOp(desiredType),
this.CreateNode(this.CreateVarRefOp(inputVar)));
Node resultNode = this.BuildProject(inputNode, treatNode, out resultVar);
return resultNode;
}
///
/// 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.