//--------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System; using System.Collections.Generic; using System.ComponentModel; using System.Data.Spatial; using System.Diagnostics; using System.Globalization; using System.Data.Metadata.Edm; using System.Data.Common.CommandTrees.Internal; namespace System.Data.Common.CommandTrees { /// /// Describes the different "kinds" (classes) of expressions /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db")] public enum DbExpressionKind { /// /// True for all. /// All = 0, /// /// Logical And. /// And = 1, /// /// True for any. /// Any = 2, /// /// Conditional case statement. /// Case = 3, /// /// Polymorphic type cast. /// Cast = 4, /// /// A constant value. /// Constant = 5, /// /// Cross apply /// CrossApply = 6, /// /// Cross join /// CrossJoin = 7, /// /// Dereference. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Deref")] Deref = 8, /// /// Duplicate removal. /// Distinct = 9, /// /// Division. /// Divide = 10, /// /// Set to singleton conversion. /// Element = 11, /// /// Entity ref value retrieval. /// EntityRef = 12, /// /// Equality /// Equals = 13, /// /// Set subtraction /// Except = 14, /// /// Restriction. /// Filter = 15, /// /// Full outer join /// FullOuterJoin = 16, /// /// Invocation of a stand-alone function /// Function = 17, /// /// Greater than. /// GreaterThan = 18, /// /// Greater than or equal. /// GreaterThanOrEquals = 19, /// /// Grouping. /// GroupBy = 20, /// /// Inner join /// InnerJoin = 21, /// /// Set intersection. /// Intersect = 22, /// /// Empty set determination. /// IsEmpty = 23, /// /// Null determination. /// IsNull = 24, /// /// Type comparison (specified Type or Subtype). /// IsOf = 25, /// /// Type comparison (specified Type only). /// IsOfOnly = 26, /// /// Application of a lambda function /// Lambda = 57, /// /// Left outer join /// LeftOuterJoin = 27, /// /// Less than. /// LessThan = 28, /// /// Less than or equal. /// LessThanOrEquals = 29, /// /// String comparison. /// Like = 30, /// /// Result count restriction (TOP n). /// Limit = 31, #if METHOD_EXPRESSION /// /// Invocation of a static or instance method. /// Method, #endif /// /// Subtraction. /// Minus = 32, /// /// Modulo. /// Modulo = 33, /// /// Multiplication. /// Multiply = 34, /// /// Instance, row, and set construction. /// NewInstance = 35, /// /// Logical Not. /// Not = 36, /// /// Inequality. /// NotEquals = 37, /// /// Null. /// Null = 38, /// /// Set members by type (or subtype). /// OfType = 39, /// /// Set members by (exact) type. /// OfTypeOnly = 40, /// /// Logical Or. /// Or = 41, /// /// Outer apply. /// OuterApply = 42, /// /// A reference to a parameter. /// ParameterReference = 43, /// /// Addition. /// Plus = 44, /// /// Projection. /// Project = 45, /// /// Retrieval of a static or instance property. /// Property = 46, /// /// Reference. /// Ref = 47, /// /// Ref key value retrieval. /// RefKey = 48, /// /// Navigation of a (composition or association) relationship. /// RelationshipNavigation = 49, /// /// Entity or relationship set scan. /// Scan = 50, /// /// Skip elements of an ordered collection. /// Skip = 51, /// /// Sorting. /// Sort = 52, /// /// Type conversion. /// Treat = 53, /// /// Negation. /// UnaryMinus = 54, /// /// Set union (with duplicates). /// UnionAll = 55, /// /// A reference to a variable. /// VariableReference = 56 } /// /// The base type for all expressions /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db")] public abstract class DbExpression { private readonly TypeUsage _type; private readonly DbExpressionKind _kind; internal DbExpression(DbExpressionKind kind, TypeUsage type) { CheckExpressionKind(kind); _kind = kind; Debug.Assert(type != null, string.Format(CultureInfo.InvariantCulture, "{0}.Type is null in DbExpression constructor", this.GetType().Name)); if (!TypeSemantics.IsNullable(type)) { type = type.ShallowCopy(new FacetValues { Nullable = true }); } Debug.Assert(type.IsReadOnly, "Editable type metadata specified for DbExpression.Type"); this._type = type; } /// /// Gets the type metadata for the result type of the expression. /// public TypeUsage ResultType { get { return _type; } } /// /// Gets the kind of the expression, which indicates the operation of this expression. /// public DbExpressionKind ExpressionKind { get { return _kind; } } /// /// The visitor pattern interface method for expression visitors that do not produce a result value. /// /// An instance of DbExpressionVisitor. /// is null public abstract void Accept(DbExpressionVisitor visitor); /// /// The visitor pattern interface method for expression visitors that produce a result value of a specific type. /// /// An instance of a typed DbExpressionVisitor that produces a result value of type TResultType. /// The type of the result produced by /// is null /// An instance of . public abstract TResultType Accept(DbExpressionVisitor visitor); #region Equals / GetHashCode // Dev10#547254: Easy to confuse DbExpressionBuilder.Equal with object.Equals method // The object.Equals method is overriden on DbExpression and marked so that it does // not appear in IntelliSense to avoid confusion with the DbExpressionBuilder.Equal // expression construction method. Overriding Equals also requires that GetHashCode // is overridden, however in both cases we defer to the System.Object implementation. [EditorBrowsable(EditorBrowsableState.Never)] public override bool Equals(object obj) { return base.Equals(obj); } public override int GetHashCode() { return base.GetHashCode(); } #endregion #region Implicit Cast Operators /// /// Creates a that represents the specified binary value, which may be null /// /// The binary value on which the returned expression should be based /// A that represents the specified binary value public static DbExpression FromBinary(byte[] value) { if (null == value) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Binary); } return ExpressionBuilder.DbExpressionBuilder.Constant(value); } public static implicit operator DbExpression(byte[] value) { return DbExpression.FromBinary(value); } /// /// Creates a that represents the specified (nullable) Boolean value /// /// The Boolean value on which the returned expression should be based /// A that represents the specified Boolean value public static DbExpression FromBoolean(bool? value) { if (!value.HasValue) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Boolean); } return (value.Value ? ExpressionBuilder.DbExpressionBuilder.True : ExpressionBuilder.DbExpressionBuilder.False); } public static implicit operator DbExpression(bool? value) { return DbExpression.FromBoolean(value); } /// /// Creates a that represents the specified (nullable) byte value /// /// The byte value on which the returned expression should be based /// A that represents the specified byte value public static DbExpression FromByte(byte? value) { if (!value.HasValue) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Byte); } return ExpressionBuilder.DbExpressionBuilder.Constant(value.Value); } public static implicit operator DbExpression(byte? value) { return DbExpression.FromByte(value); } /// /// Creates a that represents the specified (nullable) value /// /// The DateTime value on which the returned expression should be based /// A that represents the specified DateTime value public static DbExpression FromDateTime(DateTime? value) { if (!value.HasValue) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.DateTime); } return ExpressionBuilder.DbExpressionBuilder.Constant(value.Value); } public static implicit operator DbExpression(DateTime? value) { return DbExpression.FromDateTime(value); } /// /// Creates a that represents the specified (nullable) value /// /// The DateTimeOffset value on which the returned expression should be based /// A that represents the specified DateTimeOffset value public static DbExpression FromDateTimeOffset(DateTimeOffset? value) { if (!value.HasValue) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.DateTimeOffset); } return ExpressionBuilder.DbExpressionBuilder.Constant(value.Value); } public static implicit operator DbExpression(DateTimeOffset? value) { return DbExpression.FromDateTimeOffset(value); } /// /// Creates a that represents the specified (nullable) decimal value /// /// The decimal value on which the returned expression should be based /// A that represents the specified decimal value public static DbExpression FromDecimal(decimal? value) { if (!value.HasValue) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Decimal); } return ExpressionBuilder.DbExpressionBuilder.Constant(value.Value); } public static implicit operator DbExpression(decimal? value) { return DbExpression.FromDecimal(value); } /// /// Creates a that represents the specified (nullable) double value /// /// The double value on which the returned expression should be based /// A that represents the specified double value public static DbExpression FromDouble(double? value) { if (!value.HasValue) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Double); } return ExpressionBuilder.DbExpressionBuilder.Constant(value.Value); } public static implicit operator DbExpression(double? value) { return DbExpression.FromDouble(value); } /// /// Creates a that represents the specified value, which may be null. /// /// The DbGeography value on which the returned expression should be based /// A that represents the specified DbGeography value public static DbExpression FromGeography(DbGeography value) { if (value == null) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Geography); } return ExpressionBuilder.DbExpressionBuilder.Constant(value); } public static implicit operator DbExpression(DbGeography value) { return DbExpression.FromGeography(value); } /// /// Creates a that represents the specified value, which may be null. /// /// The DbGeometry value on which the returned expression should be based /// A that represents the specified DbGeometry value public static DbExpression FromGeometry(DbGeometry value) { if (value == null) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Geometry); } return ExpressionBuilder.DbExpressionBuilder.Constant(value); } public static implicit operator DbExpression(DbGeometry value) { return DbExpression.FromGeometry(value); } /// /// Creates a that represents the specified (nullable) value /// /// The Guid value on which the returned expression should be based /// A that represents the specified Guid value public static DbExpression FromGuid(Guid? value) { if (!value.HasValue) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Guid); } return ExpressionBuilder.DbExpressionBuilder.Constant(value.Value); } public static implicit operator DbExpression(Guid? value) { return DbExpression.FromGuid(value); } /// /// Creates a that represents the specified (nullable) Int16 value /// /// The Int16 value on which the returned expression should be based /// A that represents the specified Int16 value public static DbExpression FromInt16(short? value) { if (!value.HasValue) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Int16); } return ExpressionBuilder.DbExpressionBuilder.Constant(value.Value); } public static implicit operator DbExpression(short? value) { return DbExpression.FromInt16(value); } /// /// Creates a that represents the specified (nullable) Int32 value /// /// The Int32 value on which the returned expression should be based /// A that represents the specified Int32 value public static DbExpression FromInt32(int? value) { if (!value.HasValue) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Int32); } return ExpressionBuilder.DbExpressionBuilder.Constant(value.Value); } public static implicit operator DbExpression(int? value) { return DbExpression.FromInt32(value); } /// /// Creates a that represents the specified (nullable) Int64 value /// /// The Int64 value on which the returned expression should be based /// A that represents the specified Int64 value public static DbExpression FromInt64(long? value) { if (!value.HasValue) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Int64); } return ExpressionBuilder.DbExpressionBuilder.Constant(value.Value); } public static implicit operator DbExpression(long? value) { return DbExpression.FromInt64(value); } //// //public static implicit operator DbExpression(sbyte? value) //{ // return DbExpression.FromSByte(value); //} /// /// Creates a that represents the specified (nullable) Single value /// /// The Single value on which the returned expression should be based /// A that represents the specified Single value public static DbExpression FromSingle(float? value) { if (!value.HasValue) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.Single); } return ExpressionBuilder.DbExpressionBuilder.Constant(value.Value); } public static implicit operator DbExpression(float? value) { return DbExpression.FromSingle(value); } /// /// Creates a that represents the specified string value /// /// The string value on which the returned expression should be based /// A that represents the specified string value public static DbExpression FromString(string value) { if (null == value) { return ExpressionBuilder.DbExpressionBuilder.CreatePrimitiveNullExpression(PrimitiveTypeKind.String); } return ExpressionBuilder.DbExpressionBuilder.Constant(value); } public static implicit operator DbExpression(string value) { return DbExpression.FromString(value); } // #endregion #region Internal API /// /// Produces a text-based tree representation of the DbExpression tree rooted at this expression /// /// A string containing the text-based tree representation [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal string Print() { return new ExpressionPrinter().Print(this); } internal static void CheckExpressionKind(DbExpressionKind kind) { // Add new valid DbExpressionKind values to this method as well as the enum itself. // DbExpressionKind is a contiguous enum from All = 0 through View if ((kind < DbExpressionKind.All) || (DbExpressionKind.Lambda < kind)) { throw EntityUtil.InvalidEnumerationValue(typeof(DbExpressionKind), (int)kind); } } #endregion } /// /// The abstract base type for expressions that accept two expression operands. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db")] public abstract class DbBinaryExpression : DbExpression { private readonly DbExpression _left; private readonly DbExpression _right; internal DbBinaryExpression(DbExpressionKind kind, TypeUsage type, DbExpression left, DbExpression right) : base(kind, type) { Debug.Assert(left != null, "DbBinaryExpression.Left cannot be null"); Debug.Assert(right != null, "DbBinaryExpression.Right cannot be null"); this._left = left; this._right = right; } /// /// Gets the that defines the left argument. /// public DbExpression Left { get { return _left; } } /// /// Gets the that defines the right argument. /// public DbExpression Right { get { return _right; } } } /// /// The abstract base type for expressions that accept a single expression operand /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db")] public abstract class DbUnaryExpression : DbExpression { private readonly DbExpression _argument; internal DbUnaryExpression(DbExpressionKind kind, TypeUsage resultType, DbExpression argument) : base(kind, resultType) { Debug.Assert(argument != null, "DbUnaryExpression.Argument cannot be null"); this._argument = argument; } /// /// Gets the that defines the argument. /// public DbExpression Argument { get { return this._argument; } } } }