You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -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
|
||||
}
|
||||
}
|
@@ -0,0 +1,478 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="BasicValidator.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner simoncav
|
||||
// @backupOwner katicad
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
// Aconrad 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
@@ -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
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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); ;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
@@ -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
Reference in New Issue
Block a user