Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@@ -0,0 +1,100 @@
//---------------------------------------------------------------------
// <copyright file="AnciliaryOps.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// A definition of a variable
/// </summary>
internal sealed class VarDefOp : AncillaryOp
{
#region private state
private Var m_var;
#endregion
#region constructors
internal VarDefOp(Var v) : this()
{
m_var = v;
}
private VarDefOp() : base(OpType.VarDef) { }
#endregion
#region public methods
internal static readonly VarDefOp Pattern = new VarDefOp();
/// <summary>
/// 1 child - the defining expression
/// </summary>
internal override int Arity { get { return 1; } }
/// <summary>
/// The Var being defined
/// </summary>
internal Var Var { get { return m_var; } }
/// <summary>
/// Visitor pattern method
/// </summary>
/// <param name="v">The BasicOpVisitor that is visiting this Op</param>
/// <param name="n">The Node that references this Op</param>
[DebuggerNonUserCode]
internal override void Accept(BasicOpVisitor v, Node n) { v.Visit(this, n); }
/// <summary>
/// Visitor pattern method for visitors with a return value
/// </summary>
/// <param name="v">The visitor</param>
/// <param name="n">The node in question</param>
/// <returns>An instance of TResultType</returns>
[DebuggerNonUserCode]
internal override TResultType Accept<TResultType>(BasicOpVisitorOfT<TResultType> v, Node n) { return v.Visit(this, n); }
#endregion
}
/// <summary>
/// Helps define a list of VarDefOp
/// </summary>
internal sealed class VarDefListOp : AncillaryOp
{
#region constructors
private VarDefListOp() : base(OpType.VarDefList) { }
#endregion
#region public methods
/// <summary>
/// singleton instance
/// </summary>
internal static readonly VarDefListOp Instance = new VarDefListOp();
internal static readonly VarDefListOp Pattern = Instance;
/// <summary>
/// Visitor pattern method
/// </summary>
/// <param name="v">The BasicOpVisitor that is visiting this Op</param>
/// <param name="n">The Node that references this Op</param>
[DebuggerNonUserCode]
internal override void Accept(BasicOpVisitor v, Node n) { v.Visit(this, n); }
/// <summary>
/// Visitor pattern method for visitors with a return value
/// </summary>
/// <param name="v">The visitor</param>
/// <param name="n">The node in question</param>
/// <returns>An instance of TResultType</returns>
[DebuggerNonUserCode]
internal override TResultType Accept<TResultType>(BasicOpVisitorOfT<TResultType> v, Node n) { return v.Visit(this, n); }
#endregion
}
}

View File

@@ -0,0 +1,478 @@
//---------------------------------------------------------------------
// <copyright file="BasicValidator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics;
using System.Data;
using System.Data.Common;
using System.Data.Metadata.Edm;
namespace System.Data.Query.InternalTrees
{
#if DEBUG
/// <summary>
/// The BasicValidator validates the shape of the IQT. It ensures that the
/// various Ops in the tree have the right kinds and number of arguments.
/// </summary>
internal class BasicValidator : BasicOpVisitor
{
#region constructors
protected BasicValidator(Command command)
{
m_command = command;
}
#endregion
#region private surface
protected void Validate(Node node)
{
VisitNode(node);
}
#region AssertHelpers
protected static void Assert(bool condition, string format, int arg0)
{
if (!condition)
{
Debug.Assert(false, String.Format(CultureInfo.InvariantCulture, format, arg0));
}
}
protected static void Assert(bool condition, string format, OpType op)
{
if (!condition)
{
Debug.Assert(false, String.Format(CultureInfo.InvariantCulture, format, Dump.AutoString.ToString(op)));
}
}
protected static void Assert(bool condition, string format, OpType op, object arg1)
{
if (!condition)
{
Debug.Assert(false, String.Format(CultureInfo.InvariantCulture, format, Dump.AutoString.ToString(op), arg1));
}
}
protected static void Assert(bool condition, string format, OpType op, object arg1, object arg2)
{
if (!condition)
{
Debug.Assert(false, String.Format(CultureInfo.InvariantCulture, format, Dump.AutoString.ToString(op), arg1, arg2));
}
}
protected static void Assert(bool condition, string format, params object[] args)
{
if (!condition)
{
Debug.Assert(false, String.Format(CultureInfo.InvariantCulture, format, args));
}
}
protected static void AssertArity(Node n, int arity)
{
Assert(arity == n.Children.Count, "Op Arity mismatch for Op {0}: Expected {1} arguments; found {2} arguments", n.Op.OpType, arity, n.Children.Count);
}
protected static void AssertArity(Node n)
{
if (n.Op.Arity != Op.ArityVarying)
{
AssertArity(n, n.Op.Arity);
}
}
protected static void AssertBoolean(TypeUsage type)
{
Assert(TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Boolean), "Type Mismatch: Expected Boolean; found {0} instead", TypeHelpers.GetFullName(type));
}
protected static void AssertCollectionType(TypeUsage type)
{
Assert(TypeSemantics.IsCollectionType(type), "Type Mismatch: Expected Collection type: Found {0}", TypeHelpers.GetFullName(type));
}
protected static void AssertEqualTypes(TypeUsage type1, TypeUsage type2)
{
Assert(Command.EqualTypes(type1, type2),
"Type mismatch: " + type1.Identity + ", " + type2.Identity);
}
protected static void AssertEqualTypes(TypeUsage type1, EdmType type2)
{
AssertEqualTypes(type1, TypeUsage.Create(type2));
}
protected static void AssertBooleanOp(Op op)
{
AssertBoolean(op.Type);
}
protected static void AssertRelOp(Op op)
{
Assert(op.IsRelOp, "OpType Mismatch: Expected RelOp; found {0}", op.OpType);
}
protected static void AssertRelOpOrPhysicalOp(Op op)
{
Assert(op.IsRelOp || op.IsPhysicalOp, "OpType Mismatch: Expected RelOp or PhysicalOp; found {0}", op.OpType);
}
protected static void AssertScalarOp(Op op)
{
Assert(op.IsScalarOp, "OpType Mismatch: Expected ScalarOp; found {0}", op.OpType);
}
protected static void AssertOpType(Op op, OpType opType)
{
Assert(op.OpType == opType, "OpType Mismatch: Expected {0}; found {1}", op.OpType, Dump.AutoString.ToString(opType));
}
protected static void AssertUnexpectedOp(Op op)
{
Assert(false, "Unexpected OpType {0}", op.OpType);
}
#endregion
#region Visitors
protected override void VisitDefault(Node n)
{
Assert(n.Id >= 0, "Bad node id {0}", n.Id);
VisitChildren(n);
AssertArity(n);
}
#region ScalarOps
protected override void VisitScalarOpDefault(ScalarOp op, Node n)
{
VisitDefault(n);
Assert(op.Type != null, "ScalarOp {0} with no datatype!", op.OpType);
if (op.OpType != OpType.Element &&
op.OpType != OpType.Exists &&
op.OpType != OpType.Collect)
{
foreach (Node chi in n.Children)
{
AssertScalarOp(chi.Op);
}
}
}
public override void Visit(AggregateOp op, Node n)
{
VisitScalarOpDefault(op, n);
}
public override void Visit(CaseOp op, Node n)
{
VisitScalarOpDefault(op, n);
Assert((n.Children.Count >= 3 && n.Children.Count % 2 == 1),
"CaseOp: Expected odd number of arguments, and at least 3; found {0}", n.Children.Count);
// Validate that each when statement is of type Boolean
for (int i = 0; i < n.Children.Count - 1; i += 2)
{
Assert(TypeSemantics.IsBooleanType(n.Children[i].Op.Type), "Encountered a when node with a non-boolean return type");
}
// Ensure that the then clauses, the else clause and the result type are all the same
for (int i = 1; i < n.Children.Count-1; i += 2)
{
AssertEqualTypes(n.Op.Type, n.Children[i].Op.Type);
}
AssertEqualTypes(n.Op.Type, n.Children[n.Children.Count - 1].Op.Type);
}
public override void Visit(ComparisonOp op, Node n)
{
VisitScalarOpDefault(op, n);
AssertBooleanOp(op);
AssertEqualTypes(n.Child0.Op.Type, n.Child1.Op.Type);
}
public override void Visit(ConditionalOp op, Node n)
{
VisitScalarOpDefault(op, n);
switch(op.OpType)
{
case OpType.And:
case OpType.Or:
AssertArity(n, 2);
AssertBooleanOp(n.Child0.Op);
AssertBooleanOp(n.Child1.Op);
break;
case OpType.Not:
AssertArity(n, 1);
AssertBooleanOp(n.Child0.Op);
break;
case OpType.IsNull:
AssertArity(n, 1);
break;
default:
AssertUnexpectedOp(op);
break;
}
AssertBooleanOp(op);
}
public override void Visit(ArithmeticOp op, Node n)
{
VisitScalarOpDefault(op, n);
switch (op.OpType)
{
case OpType.Plus:
case OpType.Minus:
case OpType.Multiply:
case OpType.Divide:
case OpType.Modulo:
AssertEqualTypes(n.Child0.Op.Type, n.Child1.Op.Type);
AssertEqualTypes(n.Op.Type, n.Child0.Op.Type);
AssertArity(n, 2);
break;
case OpType.UnaryMinus:
AssertArity(n, 1);
break;
default:
AssertUnexpectedOp(op);
break;
}
}
public override void Visit(ElementOp op, Node n)
{
VisitScalarOpDefault(op, n);
AssertRelOp(n.Child0.Op);
}
public override void Visit(CollectOp op, Node n)
{
VisitScalarOpDefault(op, n);
AssertOpType(n.Child0.Op, OpType.PhysicalProject);
AssertCollectionType(op.Type);
}
public override void Visit(DerefOp op, Node n)
{
VisitScalarOpDefault(op, n);
Assert(TypeSemantics.IsEntityType(op.Type), "Expected an entity type. Found " + op.Type);
Assert(TypeSemantics.IsReferenceType(n.Child0.Op.Type), "Expected a ref type. Found " + n.Child0.Op.Type);
RefType r = n.Child0.Op.Type.EdmType as RefType;
Assert(r.ElementType.EdmEquals(op.Type.EdmType), "Inconsistent types");
}
public override void Visit(ExistsOp op, Node n)
{
VisitScalarOpDefault(op, n);
AssertRelOp(n.Child0.Op);
AssertBooleanOp(op);
}
public override void Visit(PropertyOp op, Node n)
{
VisitScalarOpDefault(op, n);
AssertEqualTypes(n.Child0.Op.Type, op.PropertyInfo.DeclaringType);
}
public override void Visit(RelPropertyOp op, Node n)
{
VisitScalarOpDefault(op, n);
Assert(m_command.IsRelPropertyReferenced(op.PropertyInfo), "no such rel property:", op.PropertyInfo);
Assert(TypeSemantics.IsEntityType(n.Child0.Op.Type), "argument to RelPropertyOp must be an entity type. Found: ", n.Child0.Op.Type);
}
public override void Visit(FunctionOp op, Node n)
{
VisitScalarOpDefault(op, n);
Assert(op.Function.Parameters.Count == n.Children.Count, "FunctionOp: Argument count ({0}) does not match parameter count ({1})", n.Children.Count, op.Function.Parameters.Count);
for (int idx = 0; idx < n.Children.Count; idx++)
{
AssertEqualTypes(n.Children[idx].Op.Type, op.Function.Parameters[idx].TypeUsage);
}
}
public override void Visit(SoftCastOp op, Node n)
{
VisitScalarOpDefault(op, n);
// [....] 9/21/06 - temporarily removing check here
// because the assert wrongly fails in some cases where the types are promotable,
// but the facets are not. Put this back when that issue is solved.
// Assert(TypeSemantics.IsEquivalentOrPromotableTo(n.Child0.Op.Type, op.Type), "Illegal SoftCastOp: Cannot promote input type {0} to target type {1}", n.Child0.Op.Type.Identity, op.Type.Identity);
}
public override void Visit(NavigateOp op, Node n)
{
VisitScalarOpDefault(op, n);
}
#endregion
#region AncillaryOps
protected override void VisitAncillaryOpDefault(AncillaryOp op, Node n)
{
VisitDefault(n);
}
public override void Visit(VarDefOp op, Node n)
{
VisitAncillaryOpDefault(op, n);
AssertScalarOp(n.Child0.Op);
VarDefOp varDefOp = (VarDefOp)op;
AssertEqualTypes(varDefOp.Var.Type, n.Child0.Op.Type);
}
public override void Visit(VarDefListOp op, Node n)
{
VisitDefault(n);
foreach (Node chi in n.Children)
{
AssertOpType(chi.Op, OpType.VarDef);
}
}
#endregion
#region RelOps
protected override void VisitRelOpDefault(RelOp op, Node n)
{
VisitDefault(n);
}
protected override void VisitJoinOp(JoinBaseOp op, Node n)
{
VisitRelOpDefault(op, n);
if (op.OpType == OpType.CrossJoin)
{
Assert(n.Children.Count >= 2, "CrossJoinOp needs at least 2 arguments; found only {0}", n.Children.Count);
return;
}
AssertRelOpOrPhysicalOp(n.Child0.Op);
AssertRelOpOrPhysicalOp(n.Child1.Op);
AssertScalarOp(n.Child2.Op);
AssertBooleanOp(n.Child2.Op);
}
protected override void VisitApplyOp(ApplyBaseOp op, Node n)
{
VisitRelOpDefault(op, n);
AssertRelOpOrPhysicalOp(n.Child0.Op);
AssertRelOpOrPhysicalOp(n.Child1.Op);
}
protected override void VisitSetOp(SetOp op, Node n)
{
VisitRelOpDefault(op, n);
AssertRelOpOrPhysicalOp(n.Child0.Op);
AssertRelOpOrPhysicalOp(n.Child1.Op);
//
// Ensure that the corresponding setOp Vars are all of the same
// type
//
foreach (VarMap varMap in op.VarMap)
{
foreach (KeyValuePair<Var, Var> kv in varMap)
{
AssertEqualTypes(kv.Key.Type, kv.Value.Type);
}
}
}
protected override void VisitSortOp(SortBaseOp op, Node n)
{
VisitRelOpDefault(op, n);
AssertRelOpOrPhysicalOp(n.Child0.Op);
}
public override void Visit(ConstrainedSortOp op, Node n)
{
base.Visit(op, n);
AssertScalarOp(n.Child1.Op);
Assert(TypeSemantics.IsIntegerNumericType(n.Child1.Op.Type), "ConstrainedSortOp Skip Count Node must have an integer result type");
AssertScalarOp(n.Child2.Op);
Assert(TypeSemantics.IsIntegerNumericType(n.Child2.Op.Type), "ConstrainedSortOp Limit Node must have an integer result type");
}
public override void Visit(ScanTableOp op, Node n)
{
VisitRelOpDefault(op, n);
}
public override void Visit(ScanViewOp op, Node n)
{
VisitRelOpDefault(op, n);
AssertRelOp(n.Child0.Op);
}
public override void Visit(FilterOp op, Node n)
{
VisitRelOpDefault(op, n);
AssertRelOpOrPhysicalOp(n.Child0.Op);
AssertScalarOp(n.Child1.Op);
AssertBooleanOp(n.Child1.Op);
}
public override void Visit(ProjectOp op, Node n)
{
VisitRelOpDefault(op, n);
AssertRelOpOrPhysicalOp(n.Child0.Op);
AssertOpType(n.Child1.Op, OpType.VarDefList);
}
public override void Visit(UnnestOp op, Node n)
{
VisitRelOpDefault(op, n);
AssertOpType(n.Child0.Op, OpType.VarDef);
}
protected override void VisitGroupByOp(GroupByBaseOp op, Node n)
{
VisitRelOpDefault(op, n);
AssertRelOpOrPhysicalOp(n.Child0.Op);
for (int i = 1; i < n.Children.Count; i++)
{
AssertOpType(n.Children[i].Op, OpType.VarDefList);
}
}
public override void Visit(GroupByIntoOp op, Node n)
{
VisitGroupByOp(op, n);
Assert(n.Child3.Children.Count > 0, "GroupByInto with no group aggregate vars");
}
public override void Visit(DistinctOp op, Node n)
{
VisitRelOpDefault(op, n);
AssertRelOp(n.Child0.Op);
}
public override void Visit(SingleRowTableOp op, Node n)
{
VisitRelOpDefault(op, n);
}
public override void Visit(SingleRowOp op, Node n)
{
VisitRelOpDefault(op, n);
AssertRelOpOrPhysicalOp(n.Child0.Op);
}
#endregion
#region PhysicalOps
protected override void VisitPhysicalOpDefault(PhysicalOp op, Node n)
{
VisitDefault(n);
}
public override void Visit(PhysicalProjectOp op, Node n)
{
VisitPhysicalOpDefault(op, n);
Assert(n.Children.Count >= 1, "PhysicalProjectOp needs at least 1 arg: found {0}", n.Children.Count);
foreach (Node chi in n.Children)
{
AssertRelOpOrPhysicalOp(chi.Op);
}
}
public override void Visit(SingleStreamNestOp op, Node n)
{
VisitPhysicalOpDefault(op, n);
AssertRelOp(n.Child0.Op);
}
public override void Visit(MultiStreamNestOp op, Node n)
{
VisitPhysicalOpDefault(op, n);
Assert(n.Children.Count > 1, "MultiStreamNestOp needs at least 2 arguments: found {0}", n.Children.Count);
foreach (Node chi in n.Children)
{
AssertRelOpOrPhysicalOp(chi.Op);
}
}
#endregion
#endregion
#endregion
#region private state
private Command m_command;
#endregion
}
#endif // DEBUG
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,304 @@
//---------------------------------------------------------------------
// <copyright file="ColumnMapCopier.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics;
using System.Data.Query.InternalTrees;
using System.Data.Query.PlanCompiler;
using System.Linq;
using System.Data.Mapping;
using System.Data.Metadata.Edm;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// The ColumnMapCopier clones an entire ColumnMap hierarchy; this is different
/// than the ColumnMapTranslator, which only copies things that need to be copied.
///
/// Note that this is a stateless visitor; it uses the visitor's argument for its
/// state management.
///
/// The Visitor's argument is a VarMap; anytime a Var is found in the ColumnMap
/// hierarchy, it is replaced with the replacement from the VarMap.
///
/// Note also that previous implementations of this class attempted to avoid re-
/// processing ColumnMaps by caching the results for each input and returning it.
/// I wasn't convinced that we were buying much with all that caching, since the
/// only ColumnMaps that should be repeated in the hierarchy are simple ones; there
/// is about as much object creation either way. The only reason I see that we
/// want to cache these is if we really cared to have only one VarRefColumnMap
/// instance for a given Var and be able to use reference equality instead of
/// comparing the Vars themselves. I don't believe we're making that guarantee
/// anywhere else, so I've removed that for now because I don't want the added
/// complexity that the caching adds. If performance analysis indicates there is
/// a problem, we can considier addding the cache back in.
/// </summary>
internal class ColumnMapCopier : ColumnMapVisitorWithResults<ColumnMap, VarMap>
{
#region Constructors
/// <summary>
/// Singleton instance for the "public" methods to use;
/// </summary>
static private ColumnMapCopier Instance = new ColumnMapCopier();
/// <summary>
/// Constructor; no one should use this.
/// </summary>
private ColumnMapCopier()
{
}
#endregion
#region "Public" surface area
/// <summary>
/// Return a copy of the column map, replacing all vars with the replacements
/// found in the replacementVarMap
/// </summary>
/// <param name="columnMap"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
internal static ColumnMap Copy(ColumnMap columnMap, VarMap replacementVarMap)
{
return columnMap.Accept(Instance, replacementVarMap);
}
#endregion
#region Visitor Helpers
/// <summary>
/// Returns the var to use in the copy, either the original or the
/// replacement. Note that we will follow the chain of replacements, in
/// case the replacement was also replaced.
/// </summary>
/// <param name="originalVar"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
private static Var GetReplacementVar(Var originalVar, VarMap replacementVarMap)
{
// SQLBUDT #478509: Follow the chain of mapped vars, don't
// just stop at the first one
Var replacementVar = originalVar;
while (replacementVarMap.TryGetValue(replacementVar, out originalVar))
{
if (originalVar == replacementVar)
{
break;
}
replacementVar = originalVar;
}
return replacementVar;
}
#endregion
#region Visitor Methods
#region List handling
/// <summary>
/// Copies the List of ColumnMaps or SimpleColumnMaps
/// </summary>
/// <typeparam name="TListType"></typeparam>
/// <param name="tList"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
internal TListType[] VisitList<TListType>(TListType[] tList, VarMap replacementVarMap)
where TListType : ColumnMap
{
TListType[] newTList = new TListType[tList.Length];
for(int i = 0; i < tList.Length; ++i) {
newTList[i] = (TListType)tList[i].Accept(this, replacementVarMap);
}
return newTList;
}
#endregion
#region EntityIdentity handling
/// <summary>
/// Copies the DiscriminatedEntityIdentity
/// </summary>
/// <param name="entityIdentity"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
protected override EntityIdentity VisitEntityIdentity(DiscriminatedEntityIdentity entityIdentity, VarMap replacementVarMap)
{
SimpleColumnMap newEntitySetCol = (SimpleColumnMap)entityIdentity.EntitySetColumnMap.Accept(this, replacementVarMap);
SimpleColumnMap[] newKeys = VisitList(entityIdentity.Keys, replacementVarMap);
return new DiscriminatedEntityIdentity(newEntitySetCol, entityIdentity.EntitySetMap, newKeys);
}
/// <summary>
/// Copies the SimpleEntityIdentity
/// </summary>
/// <param name="entityIdentity"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
protected override EntityIdentity VisitEntityIdentity(SimpleEntityIdentity entityIdentity, VarMap replacementVarMap)
{
SimpleColumnMap[] newKeys = VisitList(entityIdentity.Keys, replacementVarMap);
return new SimpleEntityIdentity(entityIdentity.EntitySet, newKeys);
}
#endregion
/// <summary>
/// ComplexTypeColumnMap
/// </summary>
/// <param name="columnMap"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
internal override ColumnMap Visit(ComplexTypeColumnMap columnMap, VarMap replacementVarMap)
{
SimpleColumnMap newNullability = columnMap.NullSentinel;
if (null != newNullability)
{
newNullability = (SimpleColumnMap)newNullability.Accept(this, replacementVarMap);
}
ColumnMap[] fieldList = VisitList(columnMap.Properties, replacementVarMap);
return new ComplexTypeColumnMap(columnMap.Type, columnMap.Name, fieldList, newNullability);
}
/// <summary>
/// DiscriminatedCollectionColumnMap
/// </summary>
/// <param name="columnMap"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
internal override ColumnMap Visit(DiscriminatedCollectionColumnMap columnMap, VarMap replacementVarMap)
{
ColumnMap newElementColumnMap = columnMap.Element.Accept(this, replacementVarMap);
SimpleColumnMap newDiscriminator = (SimpleColumnMap)columnMap.Discriminator.Accept(this, replacementVarMap);
SimpleColumnMap[] newKeys = VisitList(columnMap.Keys, replacementVarMap);
SimpleColumnMap[] newForeignKeys = VisitList(columnMap.ForeignKeys, replacementVarMap);
return new DiscriminatedCollectionColumnMap(columnMap.Type, columnMap.Name, newElementColumnMap, newKeys, newForeignKeys, newDiscriminator, columnMap.DiscriminatorValue);
}
/// <summary>
/// EntityColumnMap
/// </summary>
/// <param name="columnMap"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
internal override ColumnMap Visit(EntityColumnMap columnMap, VarMap replacementVarMap)
{
EntityIdentity newEntityIdentity = VisitEntityIdentity(columnMap.EntityIdentity, replacementVarMap);
ColumnMap[] fieldList = VisitList(columnMap.Properties, replacementVarMap);
return new EntityColumnMap(columnMap.Type, columnMap.Name, fieldList, newEntityIdentity);
}
/// <summary>
/// SimplePolymorphicColumnMap
/// </summary>
/// <param name="columnMap"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
internal override ColumnMap Visit(SimplePolymorphicColumnMap columnMap, VarMap replacementVarMap)
{
SimpleColumnMap newDiscriminator = (SimpleColumnMap)columnMap.TypeDiscriminator.Accept(this, replacementVarMap);
Dictionary<object, TypedColumnMap> newTypeChoices = new Dictionary<object, TypedColumnMap>(columnMap.TypeChoices.Comparer);
foreach (KeyValuePair<object, TypedColumnMap> kv in columnMap.TypeChoices)
{
TypedColumnMap newMap = (TypedColumnMap)kv.Value.Accept(this, replacementVarMap);
newTypeChoices[kv.Key] = newMap;
}
ColumnMap[] newBaseFieldList = VisitList(columnMap.Properties, replacementVarMap);
return new SimplePolymorphicColumnMap(columnMap.Type, columnMap.Name, newBaseFieldList, newDiscriminator, newTypeChoices);
}
/// <summary>
/// MultipleDiscriminatorPolymorphicColumnMap
/// </summary>
internal override ColumnMap Visit(MultipleDiscriminatorPolymorphicColumnMap columnMap, VarMap replacementVarMap)
{
// At this time, we shouldn't ever see this type here; it's for SPROCS which don't use
// the plan compiler.
System.Data.Query.PlanCompiler.PlanCompiler.Assert(false, "unexpected MultipleDiscriminatorPolymorphicColumnMap in ColumnMapCopier");
return null;
}
/// <summary>
/// RecordColumnMap
/// </summary>
/// <param name="columnMap"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
internal override ColumnMap Visit(RecordColumnMap columnMap, VarMap replacementVarMap)
{
SimpleColumnMap newNullability = columnMap.NullSentinel;
if (null != newNullability)
{
newNullability = (SimpleColumnMap)newNullability.Accept(this, replacementVarMap);
}
ColumnMap[] fieldList = VisitList(columnMap.Properties, replacementVarMap);
return new RecordColumnMap(columnMap.Type, columnMap.Name, fieldList, newNullability);
}
/// <summary>
/// RefColumnMap
/// </summary>
/// <param name="columnMap"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
internal override ColumnMap Visit(RefColumnMap columnMap, VarMap replacementVarMap)
{
EntityIdentity newEntityIdentity = VisitEntityIdentity(columnMap.EntityIdentity, replacementVarMap);
return new RefColumnMap(columnMap.Type, columnMap.Name, newEntityIdentity);
}
/// <summary>
/// ScalarColumnMap
/// </summary>
/// <param name="columnMap"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
internal override ColumnMap Visit(ScalarColumnMap columnMap, VarMap replacementVarMap)
{
return new ScalarColumnMap(columnMap.Type, columnMap.Name, columnMap.CommandId, columnMap.ColumnPos);
}
/// <summary>
/// SimpleCollectionColumnMap
/// </summary>
/// <param name="columnMap"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
internal override ColumnMap Visit(SimpleCollectionColumnMap columnMap, VarMap replacementVarMap)
{
ColumnMap newElementColumnMap = columnMap.Element.Accept(this, replacementVarMap);
SimpleColumnMap[] newKeys = VisitList(columnMap.Keys, replacementVarMap);
SimpleColumnMap[] newForeignKeys = VisitList(columnMap.ForeignKeys, replacementVarMap);
return new SimpleCollectionColumnMap(columnMap.Type, columnMap.Name, newElementColumnMap, newKeys, newForeignKeys);
}
/// <summary>
/// VarRefColumnMap
/// </summary>
/// <param name="columnMap"></param>
/// <param name="replacementVarMap"></param>
/// <returns></returns>
internal override ColumnMap Visit(VarRefColumnMap columnMap, VarMap replacementVarMap)
{
Var replacementVar = GetReplacementVar(columnMap.Var, replacementVarMap);
return new VarRefColumnMap(columnMap.Type, columnMap.Name, replacementVar);
}
#endregion
}
}

View File

@@ -0,0 +1,394 @@
//------------------------------------------------------------------------------
// <copyright file="ColumnMapFactory.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// @owner [....]
// @backupOwner [....]
//------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Common.Utils;
using System.Data.Entity;
using System.Data.Mapping;
using System.Data.Metadata.Edm;
using System.Data.Objects.ELinq;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// Factory methods for prescriptive column map patterns (includes default
/// column maps for -- soon to be -- public materializer services and function
/// mappings).
/// </summary>
internal static class ColumnMapFactory
{
/// <summary>
/// Creates a column map for the given reader and function mapping.
/// </summary>
internal static CollectionColumnMap CreateFunctionImportStructuralTypeColumnMap(DbDataReader storeDataReader, FunctionImportMappingNonComposable mapping, int resultSetIndex, EntitySet entitySet, StructuralType baseStructuralType)
{
FunctionImportStructuralTypeMappingKB resultMapping = mapping.GetResultMapping(resultSetIndex);
Debug.Assert(resultMapping != null);
if (resultMapping.NormalizedEntityTypeMappings.Count == 0) // no explicit mapping; use default non-polymorphic reader
{
// if there is no mapping, create default mapping to root entity type or complex type
Debug.Assert(!baseStructuralType.Abstract, "mapping loader must verify abstract types have explicit mapping");
return CreateColumnMapFromReaderAndType(storeDataReader, baseStructuralType, entitySet, resultMapping.ReturnTypeColumnsRenameMapping);
}
// the section below deals with the polymorphic entity type mapping for return type
EntityType baseEntityType = baseStructuralType as EntityType;
Debug.Assert(null != baseEntityType, "We should have entity type here");
// Generate column maps for all discriminators
ScalarColumnMap[] discriminatorColumns = CreateDiscriminatorColumnMaps(storeDataReader, mapping, resultSetIndex);
// Generate default maps for all mapped entity types
var mappedEntityTypes = new HashSet<EntityType>(resultMapping.MappedEntityTypes);
mappedEntityTypes.Add(baseEntityType); // make sure the base type is represented
Dictionary<EntityType, TypedColumnMap> typeChoices = new Dictionary<EntityType, TypedColumnMap>(mappedEntityTypes.Count);
ColumnMap[] baseTypeColumnMaps = null;
foreach (EntityType entityType in mappedEntityTypes)
{
ColumnMap[] propertyColumnMaps = GetColumnMapsForType(storeDataReader, entityType, resultMapping.ReturnTypeColumnsRenameMapping);
EntityColumnMap entityColumnMap = CreateEntityTypeElementColumnMap(storeDataReader, entityType, entitySet, propertyColumnMaps, resultMapping.ReturnTypeColumnsRenameMapping);
if (!entityType.Abstract)
{
typeChoices.Add(entityType, entityColumnMap);
}
if (entityType == baseStructuralType)
{
baseTypeColumnMaps = propertyColumnMaps;
}
}
// NOTE: We don't have a null sentinel here, because the stored proc won't
// return one anyway; we'll just presume the data's always there.
MultipleDiscriminatorPolymorphicColumnMap polymorphicMap = new MultipleDiscriminatorPolymorphicColumnMap(TypeUsage.Create(baseStructuralType), baseStructuralType.Name, baseTypeColumnMaps, discriminatorColumns, typeChoices, (object[] discriminatorValues) => mapping.Discriminate(discriminatorValues, resultSetIndex));
CollectionColumnMap collection = new SimpleCollectionColumnMap(baseStructuralType.GetCollectionType().TypeUsage, baseStructuralType.Name, polymorphicMap, null, null);
return collection;
}
/// <summary>
/// Build the collectionColumnMap from a store datareader, a type and an entitySet.
/// </summary>
/// <param name="storeDataReader"></param>
/// <param name="edmType"></param>
/// <param name="entitySet"></param>
/// <returns></returns>
internal static CollectionColumnMap CreateColumnMapFromReaderAndType(DbDataReader storeDataReader, EdmType edmType, EntitySet entitySet, Dictionary<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping> renameList)
{
Debug.Assert(Helper.IsEntityType(edmType) || null == entitySet, "The specified non-null EntitySet is incompatible with the EDM type specified.");
// Next, build the ColumnMap directly from the edmType and entitySet provided.
ColumnMap[] propertyColumnMaps = GetColumnMapsForType(storeDataReader, edmType, renameList);
ColumnMap elementColumnMap = null;
// NOTE: We don't have a null sentinel here, because the stored proc won't
// return one anyway; we'll just presume the data's always there.
if (Helper.IsRowType(edmType))
{
elementColumnMap = new RecordColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, null);
}
else if (Helper.IsComplexType(edmType))
{
elementColumnMap = new ComplexTypeColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, null);
}
else if (Helper.IsScalarType(edmType))
{
if (storeDataReader.FieldCount != 1)
{
throw EntityUtil.CommandExecutionDataReaderFieldCountForScalarType();
}
elementColumnMap = new ScalarColumnMap(TypeUsage.Create(edmType), edmType.Name, 0, 0);
}
else if (Helper.IsEntityType(edmType))
{
elementColumnMap = CreateEntityTypeElementColumnMap(storeDataReader, edmType, entitySet, propertyColumnMaps, null/*renameList*/);
}
else
{
Debug.Assert(false, "unexpected edmType?");
}
CollectionColumnMap collection = new SimpleCollectionColumnMap(edmType.GetCollectionType().TypeUsage, edmType.Name, elementColumnMap, null, null);
return collection;
}
/// <summary>
/// Requires: a public type with a public, default constructor. Returns a column map initializing the type
/// and all properties of the type with a public setter taking a primitive type and having a corresponding
/// column in the reader.
/// </summary>
internal static CollectionColumnMap CreateColumnMapFromReaderAndClrType(DbDataReader reader, Type type, MetadataWorkspace workspace)
{
Debug.Assert(null != reader);
Debug.Assert(null != type);
Debug.Assert(null != workspace);
// we require a default constructor
ConstructorInfo constructor = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
null, Type.EmptyTypes, null);
if (type.IsAbstract || (null == constructor && !type.IsValueType))
{
throw EntityUtil.InvalidOperation(
Strings.ObjectContext_InvalidTypeForStoreQuery(type));
}
// build a LINQ expression used by result assembly to create results
var memberInfo = new List<Tuple<MemberAssignment, int, EdmProperty>>();
foreach (PropertyInfo prop in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
// for enums unwrap the type if nullable
var propertyUnderlyingType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
Type propType = propertyUnderlyingType.IsEnum ? propertyUnderlyingType.GetEnumUnderlyingType() : prop.PropertyType;
EdmType modelType;
int ordinal;
if (TryGetColumnOrdinalFromReader(reader, prop.Name, out ordinal) &&
MetadataHelper.TryDetermineCSpaceModelType(propType, workspace, out modelType) &&
(Helper.IsScalarType(modelType)) &&
prop.CanWrite && prop.GetIndexParameters().Length == 0 && null != prop.GetSetMethod(/* nonPublic */true))
{
memberInfo.Add(Tuple.Create(
Expression.Bind(prop, Expression.Parameter(prop.PropertyType, "placeholder")),
ordinal,
new EdmProperty(prop.Name, TypeUsage.Create(modelType))));
}
}
// initialize members in the order in which they appear in the reader
MemberInfo[] members = new MemberInfo[memberInfo.Count];
MemberBinding[] memberBindings = new MemberBinding[memberInfo.Count];
ColumnMap[] propertyMaps = new ColumnMap[memberInfo.Count];
EdmProperty[] modelProperties = new EdmProperty[memberInfo.Count];
int i = 0;
foreach (var memberGroup in memberInfo.GroupBy(tuple => tuple.Item2).OrderBy(tuple => tuple.Key))
{
// make sure that a single column isn't contributing to multiple properties
if (memberGroup.Count() != 1)
{
throw EntityUtil.InvalidOperation(Strings.ObjectContext_TwoPropertiesMappedToSameColumn(
reader.GetName(memberGroup.Key),
String.Join(", ", memberGroup.Select(tuple => tuple.Item3.Name).ToArray())));
}
var member = memberGroup.Single();
MemberAssignment assignment = member.Item1;
int ordinal = member.Item2;
EdmProperty modelProp = member.Item3;
members[i] = assignment.Member;
memberBindings[i] = assignment;
propertyMaps[i] = new ScalarColumnMap(modelProp.TypeUsage, modelProp.Name, 0, ordinal);
modelProperties[i] = modelProp;
i++;
}
NewExpression newExpr = null == constructor ? Expression.New(type) : Expression.New(constructor);
MemberInitExpression init = Expression.MemberInit(newExpr, memberBindings);
InitializerMetadata initMetadata = InitializerMetadata.CreateProjectionInitializer(
(EdmItemCollection)workspace.GetItemCollection(DataSpace.CSpace), init, members);
// column map (a collection of rows with InitializerMetadata markup)
RowType rowType = new RowType(modelProperties, initMetadata);
RecordColumnMap rowMap = new RecordColumnMap(TypeUsage.Create(rowType),
"DefaultTypeProjection", propertyMaps, null);
CollectionColumnMap collectionMap = new SimpleCollectionColumnMap(rowType.GetCollectionType().TypeUsage,
rowType.Name, rowMap, null, null);
return collectionMap;
}
/// <summary>
/// Build the entityColumnMap from a store datareader, a type and an entitySet and
/// a list ofproperties.
/// </summary>
/// <param name="storeDataReader"></param>
/// <param name="edmType"></param>
/// <param name="entitySet"></param>
/// <param name="propertyColumnMaps"></param>
/// <returns></returns>
private static EntityColumnMap CreateEntityTypeElementColumnMap(
DbDataReader storeDataReader, EdmType edmType, EntitySet entitySet,
ColumnMap[] propertyColumnMaps, Dictionary<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping> renameList)
{
EntityType entityType = (EntityType)edmType;
// The tricky part here is
// that the KeyColumns list must point at the same ColumnMap(s) that
// the properties list points to, so we build a quick array of
// ColumnMap(s) that are indexed by their ordinal; then we can walk
// the list of keyMembers, and find the ordinal in the reader, and
// pick the same ColumnMap for it.
// Build the ordinal -> ColumnMap index
ColumnMap[] ordinalToColumnMap = new ColumnMap[storeDataReader.FieldCount];
foreach (ColumnMap propertyColumnMap in propertyColumnMaps)
{
int ordinal = ((ScalarColumnMap)propertyColumnMap).ColumnPos;
ordinalToColumnMap[ordinal] = propertyColumnMap;
}
// Now build the list of KeyColumns;
IList<EdmMember> keyMembers = entityType.KeyMembers;
SimpleColumnMap[] keyColumns = new SimpleColumnMap[keyMembers.Count];
int keyMemberIndex = 0;
foreach (EdmMember keyMember in keyMembers)
{
int keyOrdinal = GetMemberOrdinalFromReader(storeDataReader, keyMember, edmType, renameList);
Debug.Assert(keyOrdinal >= 0, "keyMember for entity is not found by name in the data reader?");
ColumnMap keyColumnMap = ordinalToColumnMap[keyOrdinal];
Debug.Assert(null != keyColumnMap, "keyMember for entity isn't in properties collection for the entity?");
keyColumns[keyMemberIndex] = (SimpleColumnMap)keyColumnMap;
keyMemberIndex++;
}
SimpleEntityIdentity entityIdentity = new SimpleEntityIdentity(entitySet, keyColumns);
EntityColumnMap result = new EntityColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, entityIdentity);
return result;
}
/// <summary>
/// For a given edmType, build an array of scalarColumnMaps that map to the columns
/// in the store datareader provided. Note that we're hooking things up by name, not
/// by ordinal position.
/// </summary>
/// <param name="storeDataReader"></param>
/// <param name="edmType"></param>
/// <returns></returns>
private static ColumnMap[] GetColumnMapsForType(DbDataReader storeDataReader, EdmType edmType, Dictionary<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping> renameList)
{
// First get the list of properties; NOTE: we need to hook up the column by name,
// not by position.
IBaseList<EdmMember> members = TypeHelpers.GetAllStructuralMembers(edmType);
ColumnMap[] propertyColumnMaps = new ColumnMap[members.Count];
int index = 0;
foreach (EdmMember member in members)
{
if (!Helper.IsScalarType(member.TypeUsage.EdmType))
{
throw EntityUtil.InvalidOperation(Strings.ADP_InvalidDataReaderUnableToMaterializeNonScalarType(member.Name, member.TypeUsage.EdmType.FullName));
}
int ordinal = GetMemberOrdinalFromReader(storeDataReader, member, edmType, renameList);
propertyColumnMaps[index] = new ScalarColumnMap(member.TypeUsage, member.Name, 0, ordinal);
index++;
}
return propertyColumnMaps;
}
private static ScalarColumnMap[] CreateDiscriminatorColumnMaps(DbDataReader storeDataReader, FunctionImportMappingNonComposable mapping, int resultIndex)
{
// choose an arbitrary type for discriminator columns -- the type is not
// actually statically known
EdmType discriminatorType =
MetadataItem.EdmProviderManifest.GetPrimitiveType(PrimitiveTypeKind.String);
TypeUsage discriminatorTypeUsage =
TypeUsage.Create(discriminatorType);
IList<string> discriminatorColumnNames = mapping.GetDiscriminatorColumns(resultIndex);
ScalarColumnMap[] discriminatorColumns = new ScalarColumnMap[discriminatorColumnNames.Count];
for (int i = 0; i < discriminatorColumns.Length; i++)
{
string columnName = discriminatorColumnNames[i];
ScalarColumnMap columnMap = new ScalarColumnMap(discriminatorTypeUsage, columnName, 0,
GetDiscriminatorOrdinalFromReader(storeDataReader, columnName, mapping.FunctionImport));
discriminatorColumns[i] = columnMap;
}
return discriminatorColumns;
}
/// <summary>
/// Given a store datareader and a member of an edmType, find the column ordinal
/// in the datareader with the name of the member.
/// </summary>
/// <param name="storeDataReader"></param>
/// <param name="member"></param>
/// <returns></returns>
private static int GetMemberOrdinalFromReader(DbDataReader storeDataReader, EdmMember member, EdmType currentType, Dictionary<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping> renameList)
{
int result;
string memberName = GetRenameForMember(member, currentType, renameList);
if (!TryGetColumnOrdinalFromReader(storeDataReader, memberName, out result))
{
throw EntityUtil.CommandExecutionDataReaderMissingColumnForType(member, currentType);
}
return result;
}
private static string GetRenameForMember(EdmMember member, EdmType currentType, Dictionary<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping> renameList)
{
// if list is null,
// or no rename mapping at all,
// or partial rename and the member is not specified by the renaming
// then we return the original member.Name
// otherwise we return the mapped one
return renameList == null || renameList.Count == 0 || !renameList.Any(m => m.Key == member.Name) ? member.Name : renameList[member.Name].GetRename(currentType);
}
/// <summary>
/// Given a store datareader, a column name, find the column ordinal
/// in the datareader with the name of the column.
///
/// We only have the functionImport provided to include it in the exception
/// message.
/// </summary>
/// <param name="storeDataReader"></param>
/// <param name="columnName"></param>
/// <param name="functionImport"></param>
/// <returns></returns>
private static int GetDiscriminatorOrdinalFromReader(DbDataReader storeDataReader, string columnName, EdmFunction functionImport)
{
int result;
if (!TryGetColumnOrdinalFromReader(storeDataReader, columnName, out result))
{
throw EntityUtil.CommandExecutionDataReaderMissinDiscriminatorColumn(columnName, functionImport);
}
return result;
}
/// <summary>
/// Given a store datareader and a column name, try to find the column ordinal
/// in the datareader with the name of the column.
/// </summary>
/// <param name="storeDataReader"></param>
/// <param name="columnName"></param>
/// <param name="ordinal"></param>
/// <returns>true if found, false otherwise.</returns>
private static bool TryGetColumnOrdinalFromReader(DbDataReader storeDataReader, string columnName, out int ordinal)
{
if (0 == storeDataReader.FieldCount)
{
// If there are no fields, there can't be a match (this check avoids
// an InvalidOperationException on the call to GetOrdinal)
ordinal = default(int);
return false;
}
// Wrap ordinal lookup for the member so that we can throw a nice exception.
try
{
ordinal = storeDataReader.GetOrdinal(columnName);
return true;
}
catch (IndexOutOfRangeException)
{
// No column matching the column name found
ordinal = default(int);
return false;
}
}
}
}

View File

@@ -0,0 +1,258 @@
//---------------------------------------------------------------------
// <copyright file="ColumnMapVisitorWithResults.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
namespace System.Data.Query.InternalTrees
{
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.Common.CommandTrees;
using System.Data.Metadata.Edm;
using System.Data.Query.PlanCompiler;
using System.Diagnostics;
using System.IO;
using System.Threading;
/// <summary>
/// Basic Visitor Design Pattern support for ColumnMap hierarchy;
///
/// This visitor class will walk the entire hierarchy, but does not
/// return results; it's useful for operations such as printing and
/// searching.
/// </summary>
/// <typeparam name="TArgType"></typeparam>
internal abstract class ColumnMapVisitor<TArgType>
{
#region visitor helpers
/// <summary>
/// Common List(ColumnMap) code
/// </summary>
/// <param name="columnMaps"></param>
/// <param name="arg"></param>
protected void VisitList<TListType>(TListType[] columnMaps, TArgType arg)
where TListType : ColumnMap
{
foreach (TListType columnMap in columnMaps)
{
columnMap.Accept(this, arg);
}
}
#endregion
#region EntityIdentity handling
protected void VisitEntityIdentity(EntityIdentity entityIdentity, TArgType arg)
{
DiscriminatedEntityIdentity dei = entityIdentity as DiscriminatedEntityIdentity;
if (null != dei)
{
VisitEntityIdentity(dei, arg);
}
else
{
VisitEntityIdentity((SimpleEntityIdentity)entityIdentity, arg);
}
}
protected virtual void VisitEntityIdentity(DiscriminatedEntityIdentity entityIdentity, TArgType arg)
{
entityIdentity.EntitySetColumnMap.Accept(this, arg);
foreach (SimpleColumnMap columnMap in entityIdentity.Keys)
{
columnMap.Accept(this, arg);
}
}
protected virtual void VisitEntityIdentity(SimpleEntityIdentity entityIdentity, TArgType arg)
{
foreach (SimpleColumnMap columnMap in entityIdentity.Keys)
{
columnMap.Accept(this, arg);
}
}
#endregion
#region Visitor methods
internal virtual void Visit(ComplexTypeColumnMap columnMap, TArgType arg)
{
ColumnMap nullSentinel = columnMap.NullSentinel;
if (null != nullSentinel)
{
nullSentinel.Accept(this, arg);
}
foreach (ColumnMap p in columnMap.Properties)
{
p.Accept(this, arg);
}
}
internal virtual void Visit(DiscriminatedCollectionColumnMap columnMap, TArgType arg)
{
columnMap.Discriminator.Accept(this, arg);
foreach (SimpleColumnMap fk in columnMap.ForeignKeys)
{
fk.Accept(this, arg);
}
foreach (SimpleColumnMap k in columnMap.Keys)
{
k.Accept(this, arg);
}
columnMap.Element.Accept(this, arg);
}
internal virtual void Visit(EntityColumnMap columnMap, TArgType arg)
{
VisitEntityIdentity(columnMap.EntityIdentity, arg);
foreach (ColumnMap p in columnMap.Properties)
{
p.Accept(this, arg);
}
}
internal virtual void Visit(SimplePolymorphicColumnMap columnMap, TArgType arg)
{
columnMap.TypeDiscriminator.Accept(this, arg);
foreach (ColumnMap cm in columnMap.TypeChoices.Values)
{
cm.Accept(this, arg);
}
foreach (ColumnMap p in columnMap.Properties)
{
p.Accept(this, arg);
}
}
internal virtual void Visit(MultipleDiscriminatorPolymorphicColumnMap columnMap, TArgType arg)
{
foreach (var typeDiscriminator in columnMap.TypeDiscriminators)
{
typeDiscriminator.Accept(this, arg);
}
foreach (var typeColumnMap in columnMap.TypeChoices.Values)
{
typeColumnMap.Accept(this, arg);
}
foreach (var property in columnMap.Properties)
{
property.Accept(this, arg);
}
}
internal virtual void Visit(RecordColumnMap columnMap, TArgType arg)
{
ColumnMap nullSentinel = columnMap.NullSentinel;
if (null != nullSentinel)
{
nullSentinel.Accept(this, arg);
}
foreach (ColumnMap p in columnMap.Properties)
{
p.Accept(this, arg);
}
}
internal virtual void Visit(RefColumnMap columnMap, TArgType arg)
{
VisitEntityIdentity(columnMap.EntityIdentity, arg);
}
internal virtual void Visit(ScalarColumnMap columnMap, TArgType arg)
{
}
internal virtual void Visit(SimpleCollectionColumnMap columnMap, TArgType arg)
{
foreach (SimpleColumnMap fk in columnMap.ForeignKeys)
{
fk.Accept(this, arg);
}
foreach (SimpleColumnMap k in columnMap.Keys)
{
k.Accept(this, arg);
}
columnMap.Element.Accept(this, arg);
}
internal virtual void Visit(VarRefColumnMap columnMap, TArgType arg)
{
}
#endregion
}
/// <summary>
/// Basic Visitor Design Pattern support for ColumnMap hierarchy;
///
/// This visitor class allows you to return results; it's useful for operations
/// that copy or manipulate the hierarchy.
/// </summary>
/// <typeparam name="TArgType"></typeparam>
/// <typeparam name="TResultType"></typeparam>
internal abstract class ColumnMapVisitorWithResults<TResultType, TArgType>
{
#region EntityIdentity handling
protected EntityIdentity VisitEntityIdentity(EntityIdentity entityIdentity, TArgType arg)
{
DiscriminatedEntityIdentity dei = entityIdentity as DiscriminatedEntityIdentity;
if (null != dei)
{
return VisitEntityIdentity(dei, arg);
}
else
{
return VisitEntityIdentity((SimpleEntityIdentity)entityIdentity, arg);
}
}
protected virtual EntityIdentity VisitEntityIdentity(DiscriminatedEntityIdentity entityIdentity, TArgType arg)
{
return entityIdentity;
}
protected virtual EntityIdentity VisitEntityIdentity(SimpleEntityIdentity entityIdentity, TArgType arg)
{
return entityIdentity;
}
#endregion
#region Visitor methods
internal abstract TResultType Visit(ComplexTypeColumnMap columnMap, TArgType arg);
internal abstract TResultType Visit(DiscriminatedCollectionColumnMap columnMap, TArgType arg);
internal abstract TResultType Visit(EntityColumnMap columnMap, TArgType arg);
internal abstract TResultType Visit(SimplePolymorphicColumnMap columnMap, TArgType arg);
internal abstract TResultType Visit(RecordColumnMap columnMap, TArgType arg);
internal abstract TResultType Visit(RefColumnMap columnMap, TArgType arg);
internal abstract TResultType Visit(ScalarColumnMap columnMap, TArgType arg);
internal abstract TResultType Visit(SimpleCollectionColumnMap columnMap, TArgType arg);
internal abstract TResultType Visit(VarRefColumnMap columnMap, TArgType arg);
internal abstract TResultType Visit(MultipleDiscriminatorPolymorphicColumnMap columnMap, TArgType arg);
#endregion
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
//---------------------------------------------------------------------
// <copyright file="ExplicitDiscriminatorMap.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Data.Metadata.Edm;
using System.Collections.Generic;
using System.Linq;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// Describes user-defined discriminator metadata (e.g. for a basic TPH mapping). Encapsulates
/// relevant data from System.Data.Mapping.ViewGenerabetion.DiscriminatorMap (that is to say,
/// data relevant to the PlanCompiler). This separate class accomplishes two things:
///
/// 1. Maintain separation of ViewGen and PlanCompiler
/// 2. Avoid holding references to CQT expressions in ITree ops (which the ViewGen.DiscriminatorMap
/// holds a few CQT references)
/// </summary>
internal class ExplicitDiscriminatorMap
{
private readonly System.Collections.ObjectModel.ReadOnlyCollection<KeyValuePair<object, EntityType>> m_typeMap;
private readonly EdmMember m_discriminatorProperty;
private readonly System.Collections.ObjectModel.ReadOnlyCollection<EdmProperty> m_properties;
internal ExplicitDiscriminatorMap(System.Data.Mapping.ViewGeneration.DiscriminatorMap template)
{
m_typeMap = template.TypeMap;
m_discriminatorProperty = template.Discriminator.Property;
m_properties = template.PropertyMap.Select(propertyValuePair => propertyValuePair.Key)
.ToList().AsReadOnly();
}
/// <summary>
/// Maps from discriminator value to type.
/// </summary>
internal System.Collections.ObjectModel.ReadOnlyCollection<KeyValuePair<object, EntityType>> TypeMap
{
get { return m_typeMap; }
}
/// <summary>
/// Gets property containing discriminator value.
/// </summary>
internal EdmMember DiscriminatorProperty
{
get { return m_discriminatorProperty; }
}
/// <summary>
/// All properties for the type hierarchy.
/// </summary>
internal System.Collections.ObjectModel.ReadOnlyCollection<EdmProperty> Properties
{
get { return m_properties; }
}
/// <summary>
/// Returns the type id for the given entity type, or null if non exists.
/// </summary>
internal object GetTypeId(EntityType entityType)
{
object result = null;
foreach (var discriminatorTypePair in this.TypeMap)
{
if (discriminatorTypePair.Value.EdmEquals(entityType))
{
result = discriminatorTypePair.Key;
break;
}
}
return result;
}
}
}

View File

@@ -0,0 +1,271 @@
//---------------------------------------------------------------------
// <copyright file="Metadata.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Metadata.Edm;
using System.Globalization;
using System.Diagnostics;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// Describes metadata about a table
/// </summary>
internal class TableMD
{
private List<ColumnMD> m_columns;
private List<ColumnMD> m_keys;
private EntitySetBase m_extent; // null for transient tables
private bool m_flattened;
/// <summary>
/// private initializer
/// </summary>
/// <param name="extent">the entity set corresponding to this table (if any)</param>
private TableMD(EntitySetBase extent)
{
m_columns = new List<ColumnMD>();
m_keys = new List<ColumnMD>();
m_extent = extent;
}
/// <summary>
/// Create a typed-table definition corresponding to an entityset (if specified)
///
/// The table has exactly one column - the type of the column is specified by
/// the "type" parameter. This table is considered to be un-"flattened"
/// </summary>
/// <param name="type">type of each element (row) of the table</param>
/// <param name="extent">entityset corresponding to the table (if any)</param>
internal TableMD(TypeUsage type, EntitySetBase extent)
: this(extent)
{
m_columns.Add(new ColumnMD(this, "element", type));
m_flattened = !PlanCompiler.TypeUtils.IsStructuredType(type);
}
/// <summary>
/// Creates a "flattened" table definition.
///
/// The table has one column for each specified property in the "properties" parameter.
/// The name and datatype of each table column are taken from the corresponding property.
///
/// The keys of the table (if any) are those specified in the "keyProperties" parameter
///
/// The table may correspond to an entity set (if the entityset parameter was non-null)
/// </summary>
/// <param name="properties">prperties corresponding to columns of the table</param>
/// <param name="keyProperties"></param>
/// <param name="extent">entityset corresponding to the table (if any)</param>
internal TableMD(IEnumerable<EdmProperty> properties, IEnumerable<EdmMember> keyProperties,
EntitySetBase extent)
: this(extent)
{
Dictionary<string, ColumnMD> columnMap = new Dictionary<string, ColumnMD>();
m_flattened = true;
foreach (EdmProperty p in properties)
{
ColumnMD newColumn = new ColumnMD(this, p);
m_columns.Add(newColumn);
columnMap[p.Name] = newColumn;
}
foreach (EdmMember p in keyProperties)
{
ColumnMD keyColumn;
if (!columnMap.TryGetValue(p.Name, out keyColumn))
{
Debug.Assert(false, "keyMember not in columns?");
}
else
{
m_keys.Add(keyColumn);
}
}
}
/// <summary>
/// The extent metadata (if any)
/// </summary>
internal EntitySetBase Extent { get { return m_extent; } }
/// <summary>
/// List of columns of this table
/// </summary>
internal List<ColumnMD> Columns { get { return m_columns; } }
/// <summary>
/// Keys for this table
/// </summary>
internal List<ColumnMD> Keys { get { return m_keys; } }
/// <summary>
/// Is this table a "flat" table?
/// </summary>
internal bool Flattened { get { return m_flattened; } }
/// <summary>
/// String form - for debugging
/// </summary>
/// <returns></returns>
public override string ToString()
{
return (m_extent != null ? m_extent.Name : "Transient");
}
}
/// <summary>
/// Describes information about each column
/// </summary>
internal class ColumnMD
{
private string m_name;
private TypeUsage m_type;
private EdmMember m_property;
/// <summary>
/// Default constructor
/// </summary>
/// <param name="table">Table containing this column</param>
/// <param name="name">Column name</param>
/// <param name="type">Datatype of the column</param>
internal ColumnMD(TableMD table, string name, TypeUsage type)
{
m_name = name;
m_type = type;
}
/// <summary>
/// More useful default constructor
/// </summary>
/// <param name="table">table containing this column</param>
/// <param name="property">property describing this column</param>
internal ColumnMD(TableMD table, EdmMember property)
: this(table, property.Name, property.TypeUsage)
{
m_property = property;
}
/// <summary>
/// Column Name
/// </summary>
internal string Name { get { return m_name; } }
/// <summary>
/// Datatype of the column
/// </summary>
internal TypeUsage Type { get { return m_type; } }
/// <summary>
/// Is this column nullable ?
/// </summary>
internal bool IsNullable
{
get
{
return (m_property == null) || TypeSemantics.IsNullable(m_property);
}
}
/// <summary>
/// debugging help
/// </summary>
/// <returns></returns>
public override string ToString()
{
return m_name;
}
}
/// <summary>
/// Represents one instance of a table. Contains the table metadata
/// </summary>
internal class Table
{
private TableMD m_tableMetadata;
private VarList m_columns;
private VarVec m_referencedColumns;
private VarVec m_keys;
private VarVec m_nonnullableColumns;
private int m_tableId;
internal Table(Command command, TableMD tableMetadata, int tableId)
{
m_tableMetadata = tableMetadata;
m_columns = Command.CreateVarList();
m_keys = command.CreateVarVec();
m_nonnullableColumns = command.CreateVarVec();
m_tableId = tableId;
Dictionary<string, ColumnVar> columnVarMap = new Dictionary<string, ColumnVar>();
foreach (ColumnMD c in tableMetadata.Columns)
{
ColumnVar v = command.CreateColumnVar(this, c);
columnVarMap[c.Name] = v;
if (!c.IsNullable)
{
m_nonnullableColumns.Set(v);
}
}
foreach (ColumnMD c in tableMetadata.Keys)
{
ColumnVar v = columnVarMap[c.Name];
m_keys.Set(v);
}
m_referencedColumns = command.CreateVarVec(m_columns);
}
/// <summary>
/// Metadata for the table instance
/// </summary>
internal TableMD TableMetadata { get { return m_tableMetadata; } }
/// <summary>
/// List of column references
/// </summary>
internal VarList Columns { get { return m_columns; } }
/// <summary>
/// Get the list of all referenced columns.
/// </summary>
internal VarVec ReferencedColumns
{
get { return m_referencedColumns; }
}
/// <summary>
///
/// </summary>
internal VarVec NonNullableColumns { get { return m_nonnullableColumns; } }
/// <summary>
/// List of keys
/// </summary>
internal VarVec Keys { get { return m_keys; } }
/// <summary>
/// (internal) id for this table instance
/// </summary>
internal int TableId { get { return m_tableId; } }
/// <summary>
/// String form - for debugging
/// </summary>
/// <returns></returns>
public override string ToString()
{
return String.Format(CultureInfo.InvariantCulture, "{0}::{1}", m_tableMetadata.ToString(), this.TableId); ;
}
}
}

View File

@@ -0,0 +1,53 @@
//---------------------------------------------------------------------
// <copyright file="NodeCounter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics;
using System.Data.Common;
using md=System.Data.Metadata.Edm;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// Counts the number of nodes in a tree
/// </summary>
internal class NodeCounter : BasicOpVisitorOfT<int>
{
/// <summary>
/// Public entry point - Calculates the nubmer of nodes in the given subTree
/// </summary>
/// <param name="subTree"></param>
/// <returns></returns>
internal static int Count(Node subTree)
{
NodeCounter counter = new NodeCounter();
return counter.VisitNode(subTree);
}
/// <summary>
/// Common processing for all node types
/// Count = 1 (self) + count of children
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
protected override int VisitDefault(Node n)
{
int count = 1;
foreach (Node child in n.Children)
{
count += VisitNode(child);
}
return count;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,190 @@
//---------------------------------------------------------------------
// <copyright file="Nodes.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Data.Metadata.Edm;
using System.Globalization;
using System.Diagnostics;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// A Node describes a node in a query tree. Each node has an operator, and
/// a list of zero or more children of that operator.
/// </summary>
internal class Node
{
#region private state
private int m_id;
private List<Node> m_children;
private Op m_op;
private NodeInfo m_nodeInfo;
#endregion
#region constructors
/// <summary>
/// Basic constructor.
///
/// NEVER call this routine directly - you should always use the Command.CreateNode
/// factory methods.
/// </summary>
/// <param name="nodeId">id for the node</param>
/// <param name="op">The operator</param>
/// <param name="children">List of child nodes</param>
internal Node(int nodeId, Op op, List<Node> children)
{
m_id = nodeId;
m_op = op;
m_children = children;
}
/// <summary>
/// This routine is only used for building up rule patterns.
/// NEVER use this routine for building up nodes in a user command tree.
/// </summary>
/// <param name="op"></param>
/// <param name="children"></param>
internal Node(Op op, params Node[] children)
: this(-1, op, new List<Node>(children))
{
}
#endregion
#region public properties and methods
#if DEBUG
internal int Id { get { return m_id; } }
#endif
/// <summary>
/// Get the list of children
/// </summary>
internal List<Node> Children { get { return m_children; } }
/// <summary>
/// Gets or sets the node's operator
/// </summary>
internal Op Op { get { return m_op; } set { m_op = value; } }
/// <summary>
/// Simpler (?) getter/setter routines
/// </summary>
internal Node Child0 { get { return m_children[0]; } set { m_children[0] = value; } }
/// <summary>
/// Do I have a zeroth child?
/// </summary>
internal bool HasChild0 { get { return m_children.Count > 0; } }
/// <summary>
/// Get/set first child
/// </summary>
internal Node Child1 { get { return m_children[1]; } set { m_children[1] = value; } }
/// <summary>
/// Do I have a child1?
/// </summary>
internal bool HasChild1 { get { return m_children.Count > 1; } }
/// <summary>
/// get/set second child
/// </summary>
internal Node Child2 { get { return m_children[2]; } set { m_children[2] = value; } }
/// <summary>
/// get/set second child
/// </summary>
internal Node Child3 { get { return m_children[3]; } /* commented out because of fxcop - there are no upstream callers -- set { m_children[3] = value; }*/ }
/// <summary>
/// Do I have a child2 (third child really)
/// </summary>
internal bool HasChild2 { get { return m_children.Count > 2; } }
/// <summary>
/// Do I have a child3 (fourth child really)
/// </summary>
internal bool HasChild3 { get { return m_children.Count > 3; } }
#region equivalence functions
/// <summary>
/// Is this subtree equivalent to another subtree
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
internal bool IsEquivalent(Node other)
{
if (this.Children.Count != other.Children.Count)
{
return false;
}
bool? opEquivalent = this.Op.IsEquivalent(other.Op);
if (opEquivalent != true)
{
return false;
}
for (int i = 0; i < this.Children.Count; i++)
{
if (!this.Children[i].IsEquivalent(other.Children[i]))
{
return false;
}
}
return true;
}
#endregion
#region NodeInfo methods and properties
/// <summary>
/// Has the node info been initialized, i.e. previously computed
/// </summary>
internal bool IsNodeInfoInitialized { get { return (m_nodeInfo != null); } }
/// <summary>
/// Get the nodeInfo for a node. Initializes it, if it has not yet been initialized
/// </summary>
/// <param name="command">Current command object</param>
/// <returns>NodeInfo for this node</returns>
internal NodeInfo GetNodeInfo(Command command)
{
if (m_nodeInfo == null)
{
InitializeNodeInfo(command);
}
return m_nodeInfo;
}
/// <summary>
/// Gets the "extended" nodeinfo for a node; if it has not yet been initialized, then it will be
/// </summary>
/// <param name="command">current command object</param>
/// <returns>extended nodeinfo for this node</returns>
internal ExtendedNodeInfo GetExtendedNodeInfo(Command command)
{
if (m_nodeInfo == null)
{
InitializeNodeInfo(command);
}
ExtendedNodeInfo extendedNodeInfo = m_nodeInfo as ExtendedNodeInfo;
Debug.Assert(extendedNodeInfo != null);
return extendedNodeInfo;
}
private void InitializeNodeInfo(Command command)
{
if (this.Op.IsRelOp || this.Op.IsPhysicalOp)
{
m_nodeInfo = new ExtendedNodeInfo(command);
}
else
{
m_nodeInfo = new NodeInfo(command);
}
command.RecomputeNodeInfo(this);
}
#endregion
#endregion
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,341 @@
//---------------------------------------------------------------------
// <copyright file="PhysicalOps.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Globalization;
using System.Data.Query.PlanCompiler;
using md = System.Data.Metadata.Edm;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// A PhysicalProjectOp is a physical Op capping the entire command tree (and the
/// subtrees of CollectOps).
/// </summary>
internal class PhysicalProjectOp : PhysicalOp
{
#region public methods
/// <summary>
/// Instance for pattern matching in rules
/// </summary>
internal static readonly PhysicalProjectOp Pattern = new PhysicalProjectOp();
/// <summary>
/// Get the column map that describes how the result should be reshaped
/// </summary>
internal SimpleCollectionColumnMap ColumnMap
{
get { return m_columnMap; }
}
/// <summary>
/// Get the (ordered) list of output vars that this node produces
/// </summary>
internal VarList Outputs
{
get { return m_outputVars; }
}
/// <summary>
/// Visitor pattern method
/// </summary>
/// <param name="v">The BasicOpVisitor that is visiting this Op</param>
/// <param name="n">The Node that references this Op</param>
[DebuggerNonUserCode]
internal override void Accept(BasicOpVisitor v, Node n) { v.Visit(this, n); }
/// <summary>
/// Visitor pattern method for visitors with a return value
/// </summary>
/// <param name="v">The visitor</param>
/// <param name="n">The node in question</param>
/// <returns>An instance of TResultType</returns>
[DebuggerNonUserCode]
internal override TResultType Accept<TResultType>(BasicOpVisitorOfT<TResultType> v, Node n) { return v.Visit(this, n); }
#endregion
#region private constructors
/// <summary>
/// basic constructor
/// </summary>
/// <param name="outputVars">List of outputs from this Op</param>
/// <param name="columnMap">column map that describes the result to be shaped</param>
internal PhysicalProjectOp(VarList outputVars, SimpleCollectionColumnMap columnMap)
: this()
{
Debug.Assert(null != columnMap, "null columnMap?");
m_outputVars = outputVars;
m_columnMap = columnMap;
}
private PhysicalProjectOp()
: base(OpType.PhysicalProject)
{
}
#endregion
#region private state
private SimpleCollectionColumnMap m_columnMap;
private VarList m_outputVars;
#endregion
}
/// <summary>
/// Represents information about one collection being managed by the NestOps.
/// The CollectionVar is a Var that represents the entire collection.
/// </summary>
internal class CollectionInfo
{
#region public methods
/// <summary>
/// The collection-var
/// </summary>
internal Var CollectionVar
{
get { return m_collectionVar; }
}
/// <summary>
/// the column map for the collection element
/// </summary>
internal ColumnMap ColumnMap
{
get { return m_columnMap; }
}
/// <summary>
/// list of vars describing the collection element; flattened to remove
/// nested collections
/// </summary>
internal VarList FlattenedElementVars
{
get { return m_flattenedElementVars; }
}
/// <summary>
/// list of keys specific to this collection
/// </summary>
internal VarVec Keys
{
get { return m_keys; }
}
/// <summary>
/// list of sort keys specific to this collection
/// </summary>
internal List<InternalTrees.SortKey> SortKeys
{
get { return m_sortKeys; }
}
/// <summary>
/// Discriminator Value for this collection (for a given NestOp).
/// Should we break this out into a subtype of CollectionInfo
/// </summary>
internal object DiscriminatorValue
{
get { return m_discriminatorValue; }
}
#endregion
#region constructors
internal CollectionInfo(Var collectionVar, ColumnMap columnMap, VarList flattenedElementVars, VarVec keys, List<InternalTrees.SortKey> sortKeys, object discriminatorValue)
{
m_collectionVar = collectionVar;
m_columnMap = columnMap;
m_flattenedElementVars = flattenedElementVars;
m_keys = keys;
m_sortKeys = sortKeys;
m_discriminatorValue = discriminatorValue;
}
#endregion
#region private state
private Var m_collectionVar; // the collection Var
private ColumnMap m_columnMap; // column map for the collection element
private VarList m_flattenedElementVars; // elementVars, removing collections;
private VarVec m_keys; //list of keys specific to this collection
private List<InternalTrees.SortKey> m_sortKeys; //list of sort keys specific to this collection
private object m_discriminatorValue;
#endregion
}
/// <summary>
/// Base class for Nest operations
/// </summary>
internal abstract class NestBaseOp : PhysicalOp
{
#region publics
/// <summary>
/// (Ordered) list of prefix sort keys (defines ordering of results)
/// </summary>
internal List<SortKey> PrefixSortKeys
{
get { return m_prefixSortKeys; }
}
/// <summary>
/// Outputs of the NestOp. Includes the Keys obviously, and one Var for each of
/// the collections produced. In addition, this may also include non-key vars
/// from the outer row
/// </summary>
internal VarVec Outputs
{
get { return m_outputs; }
}
/// <summary>
/// Information about each collection managed by the NestOp
/// </summary>
internal List<CollectionInfo> CollectionInfo
{
get { return m_collectionInfoList; }
}
#endregion
#region constructors
internal NestBaseOp(OpType opType, List<SortKey> prefixSortKeys,
VarVec outputVars,
List<CollectionInfo> collectionInfoList)
: base(opType)
{
m_outputs = outputVars;
m_collectionInfoList = collectionInfoList;
m_prefixSortKeys = prefixSortKeys;
}
#endregion
#region private state
private List<SortKey> m_prefixSortKeys; // list of sort key prefixes
private VarVec m_outputs; // list of all output vars
private List<CollectionInfo> m_collectionInfoList;
#endregion
}
/// <summary>
/// Single-stream nest aggregation Op.
/// (Somewhat similar to a group-by op - should we merge these?)
/// </summary>
internal class SingleStreamNestOp : NestBaseOp
{
#region publics
/// <summary>
/// 1 child - the input
/// </summary>
internal override int Arity { get { return 1; } }
/// <summary>
/// The discriminator Var (when there are multiple collections)
/// </summary>
internal Var Discriminator
{
get { return m_discriminator; }
}
/// <summary>
/// List of postfix sort keys (mostly to deal with multi-level nested collections)
/// </summary>
internal List<SortKey> PostfixSortKeys
{
get { return m_postfixSortKeys; }
}
/// <summary>
/// Set of keys for this nest operation
/// </summary>
internal VarVec Keys
{
get { return m_keys; }
}
/// <summary>
/// Visitor pattern method
/// </summary>
/// <param name="v">The BasicOpVisitor that is visiting this Op</param>
/// <param name="n">The Node that references this Op</param>
[DebuggerNonUserCode]
internal override void Accept(BasicOpVisitor v, Node n)
{
v.Visit(this, n);
}
/// <summary>
/// Visitor pattern method for visitors with a return value
/// </summary>
/// <param name="v">The visitor</param>
/// <param name="n">The node in question</param>
/// <returns>An instance of TResultType</returns>
[DebuggerNonUserCode]
internal override TResultType Accept<TResultType>(BasicOpVisitorOfT<TResultType> v, Node n)
{
return v.Visit(this, n);
}
#endregion
#region constructors
internal SingleStreamNestOp(VarVec keys,
List<SortKey> prefixSortKeys, List<SortKey> postfixSortKeys,
VarVec outputVars, List<CollectionInfo> collectionInfoList,
Var discriminatorVar)
: base(OpType.SingleStreamNest, prefixSortKeys, outputVars, collectionInfoList)
{
m_keys = keys;
m_postfixSortKeys = postfixSortKeys;
m_discriminator = discriminatorVar;
}
#endregion
#region private state
private VarVec m_keys; // keys for this operation
private Var m_discriminator; // Var describing the discriminator
List<SortKey> m_postfixSortKeys; // list of postfix sort keys
#endregion
}
/// <summary>
/// Represents a multi-stream nest operation. The first input represents the
/// container row, while all the other inputs represent collections
/// </summary>
internal class MultiStreamNestOp : NestBaseOp
{
#region publics
/// <summary>
/// Visitor pattern method
/// </summary>
/// <param name="v">The BasicOpVisitor that is visiting this Op</param>
/// <param name="n">The Node that references this Op</param>
[DebuggerNonUserCode]
internal override void Accept(BasicOpVisitor v, Node n) { v.Visit(this, n); }
/// <summary>
/// Visitor pattern method for visitors with a return value
/// </summary>
/// <param name="v">The visitor</param>
/// <param name="n">The node in question</param>
/// <returns>An instance of TResultType</returns>
[DebuggerNonUserCode]
internal override TResultType Accept<TResultType>(BasicOpVisitorOfT<TResultType> v, Node n) { return v.Visit(this, n); }
#endregion
#region constructors
internal MultiStreamNestOp(List<SortKey> prefixSortKeys, VarVec outputVars,
List<CollectionInfo> collectionInfoList)
: base(OpType.MultiStreamNest, prefixSortKeys, outputVars, collectionInfoList)
{
}
#endregion
#region private state
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,232 @@
//---------------------------------------------------------------------
// <copyright file="RelPropertyHelper.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics;
using System.Data.Common;
using System.Data.Metadata.Edm;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// A "Rel" property is best thought of as a collocated reference (aka foreign key).
/// Any entity may have zero or more rel-properties carried along with it (purely
/// as a means to optimize for common relationship traversal scenarios)
///
/// Although the definition is lax here, we only deal with RelProperties that
/// are one-ended (ie) the target multiplicity is at most One.
///
/// Consider for example, an Order entity with a (N:1) Order-Customer relationship. The Customer ref
/// will be treated as a rel property for the Order entity.
/// Similarly, the OrderLine entity may have an Order ref rel property (assuming that there was
/// a N:1 relationship between OrderLine and Order)
/// </summary>
internal sealed class RelProperty
{
#region private state
private readonly RelationshipType m_relationshipType;
private readonly RelationshipEndMember m_fromEnd;
private readonly RelationshipEndMember m_toEnd;
#endregion
#region constructors
internal RelProperty(RelationshipType relationshipType, RelationshipEndMember fromEnd, RelationshipEndMember toEnd)
{
m_relationshipType = relationshipType;
m_fromEnd = fromEnd;
m_toEnd = toEnd;
}
#endregion
#region public APIs
/// <summary>
/// The relationship
/// </summary>
public RelationshipType Relationship { get { return m_relationshipType; } }
/// <summary>
/// The source end of the relationship
/// </summary>
public RelationshipEndMember FromEnd { get { return m_fromEnd; } }
/// <summary>
/// the target end of the relationship
/// </summary>
public RelationshipEndMember ToEnd { get { return m_toEnd; } }
/// <summary>
/// Our definition of equality
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
RelProperty other = obj as RelProperty;
return (other != null &&
this.Relationship.EdmEquals(other.Relationship) &&
this.FromEnd.EdmEquals(other.FromEnd) &&
this.ToEnd.EdmEquals(other.ToEnd));
}
/// <summary>
/// our hash code
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return this.ToEnd.Identity.GetHashCode();
}
/// <summary>
/// String form
/// </summary>
/// <returns></returns>
[DebuggerNonUserCode]
public override string ToString()
{
return m_relationshipType.ToString() + ":" +
m_fromEnd.ToString() + ":" +
m_toEnd.ToString();
}
#endregion
}
/// <summary>
/// A helper class for all rel-properties
/// </summary>
internal sealed class RelPropertyHelper
{
#region private state
private Dictionary<EntityTypeBase, List<RelProperty>> _relPropertyMap;
private HashSet<RelProperty> _interestingRelProperties;
#endregion
#region private methods
/// <summary>
/// Add the rel property induced by the specified relationship, (if the target
/// end has a multiplicity of one)
/// We only keep track of rel-properties that are "interesting"
/// </summary>
/// <param name="associationType">the association relationship</param>
/// <param name="fromEnd">source end of the relationship traversal</param>
/// <param name="toEnd">target end of the traversal</param>
private void AddRelProperty(AssociationType associationType,
AssociationEndMember fromEnd, AssociationEndMember toEnd)
{
if (toEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many)
{
return;
}
RelProperty prop = new RelProperty(associationType, fromEnd, toEnd);
if (_interestingRelProperties == null ||
!_interestingRelProperties.Contains(prop))
{
return;
}
EntityTypeBase entityType = (EntityTypeBase)((RefType)fromEnd.TypeUsage.EdmType).ElementType;
List<RelProperty> propList;
if (!_relPropertyMap.TryGetValue(entityType, out propList))
{
propList = new List<RelProperty>();
_relPropertyMap[entityType] = propList;
}
propList.Add(prop);
}
/// <summary>
/// Add any rel properties that are induced by the supplied relationship
/// </summary>
/// <param name="relationshipType">the relationship</param>
private void ProcessRelationship(RelationshipType relationshipType)
{
AssociationType associationType = relationshipType as AssociationType;
if (associationType == null)
{
return;
}
// Handle only binary associations
if (associationType.AssociationEndMembers.Count != 2)
{
return;
}
AssociationEndMember end0 = associationType.AssociationEndMembers[0];
AssociationEndMember end1 = associationType.AssociationEndMembers[1];
AddRelProperty(associationType, end0, end1);
AddRelProperty(associationType, end1, end0);
}
#endregion
#region constructors
internal RelPropertyHelper(MetadataWorkspace ws, HashSet<RelProperty> interestingRelProperties)
{
_relPropertyMap = new Dictionary<EntityTypeBase, List<RelProperty>>();
_interestingRelProperties = interestingRelProperties;
foreach (RelationshipType relationshipType in ws.GetItems<RelationshipType>(DataSpace.CSpace))
{
ProcessRelationship(relationshipType);
}
}
#endregion
#region public APIs
/// <summary>
/// Get the rel properties declared by this type (and *not* by any of its subtypes)
/// </summary>
/// <param name="entityType">the entity type</param>
/// <returns>set of rel properties declared for this type</returns>
internal IEnumerable<RelProperty> GetDeclaredOnlyRelProperties(EntityTypeBase entityType)
{
List<RelProperty> relProperties;
if (_relPropertyMap.TryGetValue(entityType, out relProperties))
{
foreach (RelProperty p in relProperties)
{
yield return p;
}
}
yield break;
}
/// <summary>
/// Get the rel-properties of this entity and its supertypes (starting from the root)
/// </summary>
/// <param name="entityType">the entity type</param>
/// <returns>set of rel-properties for this entity type (and its supertypes)</returns>
internal IEnumerable<RelProperty> GetRelProperties(EntityTypeBase entityType)
{
if (entityType.BaseType != null)
{
foreach (RelProperty p in GetRelProperties(entityType.BaseType as EntityTypeBase))
{
yield return p;
}
}
foreach (RelProperty p in GetDeclaredOnlyRelProperties(entityType))
{
yield return p;
}
}
#endregion
}
}

View File

@@ -0,0 +1,183 @@
//---------------------------------------------------------------------
// <copyright file="Rule.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// A Rule - more specifically, a transformation rule - describes an action that is to
/// be taken when a specific kind of subtree is found in the tree
/// </summary>
internal abstract class Rule
{
/// <summary>
/// The "callback" function for each rule.
/// Every callback function must return true if the subtree has
/// been modified (or a new subtree has been returned); and must return false
/// otherwise. If the root of the subtree has not changed, but some internal details
/// of the subtree have changed, it is the responsibility of the rule to update any
/// local bookkeeping information.
/// </summary>
/// <param name="context">The rule processing context</param>
/// <param name="subTree">the subtree to operate on</param>
/// <param name="newSubTree">possibly transformed subtree</param>
/// <returns>transformation status - true, if there was some change; false otherwise</returns>
internal delegate bool ProcessNodeDelegate(RuleProcessingContext context, Node subTree, out Node newSubTree);
#region private state
private ProcessNodeDelegate m_nodeDelegate;
private OpType m_opType;
#endregion
#region Constructors
/// <summary>
/// Basic constructor
/// </summary>
/// <param name="opType">The OpType we're interested in processing</param>
/// <param name="nodeProcessDelegate">The callback to invoke</param>
protected Rule(OpType opType, ProcessNodeDelegate nodeProcessDelegate)
{
Debug.Assert(nodeProcessDelegate != null, "null process delegate");
Debug.Assert(opType != OpType.NotValid, "bad OpType");
Debug.Assert(opType != OpType.Leaf, "bad OpType - Leaf");
m_opType = opType;
m_nodeDelegate = nodeProcessDelegate;
}
#endregion
#region protected methods
#endregion
#region public methods
/// <summary>
/// Does the rule match the current node?
/// </summary>
/// <param name="node">the node in question</param>
/// <returns>true, if a match was found</returns>
internal abstract bool Match(Node node);
/// <summary>
/// We need to invoke the specified callback on the subtree in question - but only
/// if the match succeeds
/// </summary>
/// <param name="ruleProcessingContext">Current rule processing context</param>
/// <param name="node">The node (subtree) to process</param>
/// <param name="newNode">the (possibly) modified subtree</param>
/// <returns>true, if the subtree was modified</returns>
internal bool Apply(RuleProcessingContext ruleProcessingContext, Node node, out Node newNode)
{
// invoke the real callback
return m_nodeDelegate(ruleProcessingContext, node, out newNode);
}
/// <summary>
/// The OpType we're interested in transforming
/// </summary>
internal OpType RuleOpType
{
get { return m_opType; }
}
#if DEBUG
/// <summary>
/// The method name for the rule
/// </summary>
internal string MethodName
{
get { return m_nodeDelegate.Method.Name; }
}
#endif
#endregion
}
/// <summary>
/// A SimpleRule is a rule that specifies a specific OpType to look for, and an
/// appropriate action to take when such an Op is identified
/// </summary>
internal sealed class SimpleRule : Rule
{
#region private state
#endregion
#region constructors
/// <summary>
/// Basic constructor.
/// </summary>
/// <param name="opType">The OpType we're interested in</param>
/// <param name="processDelegate">The callback to invoke when we see such an Op</param>
internal SimpleRule(OpType opType, ProcessNodeDelegate processDelegate)
: base(opType, processDelegate)
{
}
#endregion
#region overriden methods
internal override bool Match(Node node)
{
return node.Op.OpType == this.RuleOpType;
}
#endregion
}
/// <summary>
/// A PatternMatchRule allows for a pattern to be specified to identify interesting
/// subtrees, rather than just an OpType
/// </summary>
internal sealed class PatternMatchRule: Rule
{
#region private state
private Node m_pattern;
#endregion
#region constructors
/// <summary>
/// Basic constructor
/// </summary>
/// <param name="pattern">The pattern to look for</param>
/// <param name="processDelegate">The callback to invoke when such a pattern is identified</param>
internal PatternMatchRule(Node pattern, ProcessNodeDelegate processDelegate)
: base(pattern.Op.OpType, processDelegate)
{
Debug.Assert(pattern != null, "null pattern");
Debug.Assert(pattern.Op != null, "null pattern Op");
m_pattern = pattern;
}
#endregion
#region private methods
private bool Match(Node pattern, Node original)
{
if (pattern.Op.OpType == OpType.Leaf)
return true;
if (pattern.Op.OpType != original.Op.OpType)
return false;
if (pattern.Children.Count != original.Children.Count)
return false;
for (int i = 0; i < pattern.Children.Count; i++)
if (!Match(pattern.Children[i], original.Children[i]))
return false;
return true;
}
#endregion
#region overridden methods
internal override bool Match(Node node)
{
return Match(m_pattern, node);
}
#endregion
}
}

View File

@@ -0,0 +1,40 @@
//---------------------------------------------------------------------
// <copyright file="RulePatternOps.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Data.Metadata.Edm;
using System.Globalization;
namespace System.Data.Query.InternalTrees
{
/// <summary>
/// LeafOp - matches any subtree
/// </summary>
internal sealed class LeafOp : RulePatternOp
{
/// <summary>
/// The singleton instance of this class
/// </summary>
internal static readonly LeafOp Instance = new LeafOp();
internal static readonly LeafOp Pattern = Instance;
/// <summary>
/// 0 children
/// </summary>
internal override int Arity { get { return 0; } }
#region constructors
/// <summary>
/// Niladic constructor
/// </summary>
private LeafOp() : base(OpType.Leaf) { }
#endregion
}
}

Some files were not shown because too many files have changed in this diff Show More