|
//---------------------------------------------------------------------
// <copyright file="AbstractExpressions.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
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
{
/// <summary>
/// Describes the different "kinds" (classes) of expressions
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db")]
public enum DbExpressionKind
{
/// <summary>
/// True for all.
/// </summary>
All = 0,
/// <summary>
/// Logical And.
/// </summary>
And = 1,
/// <summary>
/// True for any.
/// </summary>
Any = 2,
/// <summary>
/// Conditional case statement.
/// </summary>
Case = 3,
/// <summary>
/// Polymorphic type cast.
/// </summary>
Cast = 4,
/// <summary>
/// A constant value.
/// </summary>
Constant = 5,
/// <summary>
/// Cross apply
/// </summary>
CrossApply = 6,
/// <summary>
/// Cross join
/// </summary>
CrossJoin = 7,
/// <summary>
/// Dereference.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Deref")]
Deref = 8,
/// <summary>
/// Duplicate removal.
/// </summary>
Distinct = 9,
/// <summary>
/// Division.
/// </summary>
Divide = 10,
/// <summary>
/// Set to singleton conversion.
/// </summary>
Element = 11,
/// <summary>
/// Entity ref value retrieval.
/// </summary>
EntityRef = 12,
/// <summary>
/// Equality
/// </summary>
Equals = 13,
/// <summary>
/// Set subtraction
/// </summary>
Except = 14,
/// <summary>
/// Restriction.
/// </summary>
Filter = 15,
/// <summary>
/// Full outer join
/// </summary>
FullOuterJoin = 16,
/// <summary>
/// Invocation of a stand-alone function
/// </summary>
Function = 17,
/// <summary>
/// Greater than.
/// </summary>
GreaterThan = 18,
/// <summary>
/// Greater than or equal.
/// </summary>
GreaterThanOrEquals = 19,
/// <summary>
/// Grouping.
/// </summary>
GroupBy = 20,
/// <summary>
/// Inner join
/// </summary>
InnerJoin = 21,
/// <summary>
/// Set intersection.
/// </summary>
Intersect = 22,
/// <summary>
/// Empty set determination.
/// </summary>
IsEmpty = 23,
/// <summary>
/// Null determination.
/// </summary>
IsNull = 24,
/// <summary>
/// Type comparison (specified Type or Subtype).
/// </summary>
IsOf = 25,
/// <summary>
/// Type comparison (specified Type only).
/// </summary>
IsOfOnly = 26,
/// <summary>
/// Application of a lambda function
/// </summary>
Lambda = 57,
/// <summary>
/// Left outer join
/// </summary>
LeftOuterJoin = 27,
/// <summary>
/// Less than.
/// </summary>
LessThan = 28,
/// <summary>
/// Less than or equal.
/// </summary>
LessThanOrEquals = 29,
/// <summary>
/// String comparison.
/// </summary>
Like = 30,
/// <summary>
/// Result count restriction (TOP n).
/// </summary>
Limit = 31,
#if METHOD_EXPRESSION
/// <summary>
/// Invocation of a static or instance method.
/// </summary>
Method,
#endif
/// <summary>
/// Subtraction.
/// </summary>
Minus = 32,
/// <summary>
/// Modulo.
/// </summary>
Modulo = 33,
/// <summary>
/// Multiplication.
/// </summary>
Multiply = 34,
/// <summary>
/// Instance, row, and set construction.
/// </summary>
NewInstance = 35,
/// <summary>
/// Logical Not.
/// </summary>
Not = 36,
/// <summary>
/// Inequality.
/// </summary>
NotEquals = 37,
/// <summary>
/// Null.
/// </summary>
Null = 38,
/// <summary>
/// Set members by type (or subtype).
/// </summary>
OfType = 39,
/// <summary>
/// Set members by (exact) type.
/// </summary>
OfTypeOnly = 40,
/// <summary>
/// Logical Or.
/// </summary>
Or = 41,
/// <summary>
/// Outer apply.
/// </summary>
OuterApply = 42,
/// <summary>
/// A reference to a parameter.
/// </summary>
ParameterReference = 43,
/// <summary>
/// Addition.
/// </summary>
Plus = 44,
/// <summary>
/// Projection.
/// </summary>
Project = 45,
/// <summary>
/// Retrieval of a static or instance property.
/// </summary>
Property = 46,
/// <summary>
/// Reference.
/// </summary>
Ref = 47,
/// <summary>
/// Ref key value retrieval.
/// </summary>
RefKey = 48,
/// <summary>
/// Navigation of a (composition or association) relationship.
/// </summary>
RelationshipNavigation = 49,
/// <summary>
/// Entity or relationship set scan.
/// </summary>
Scan = 50,
/// <summary>
/// Skip elements of an ordered collection.
/// </summary>
Skip = 51,
/// <summary>
/// Sorting.
/// </summary>
Sort = 52,
/// <summary>
/// Type conversion.
/// </summary>
Treat = 53,
/// <summary>
/// Negation.
/// </summary>
UnaryMinus = 54,
/// <summary>
/// Set union (with duplicates).
/// </summary>
UnionAll = 55,
/// <summary>
/// A reference to a variable.
/// </summary>
VariableReference = 56
}
/// <summary>
/// The base type for all expressions
/// </summary>
[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;
}
/// <summary>
/// Gets the type metadata for the result type of the expression.
/// </summary>
public TypeUsage ResultType { get { return _type; } }
/// <summary>
/// Gets the kind of the expression, which indicates the operation of this expression.
/// </summary>
public DbExpressionKind ExpressionKind { get { return _kind; } }
/// <summary>
/// The visitor pattern interface method for expression visitors that do not produce a result value.
/// </summary>
/// <param name="visitor">An instance of DbExpressionVisitor.</param>
/// <exception cref="ArgumentNullException"><paramref name="visitor"/> is null</exception>
public abstract void Accept(DbExpressionVisitor visitor);
/// <summary>
/// The visitor pattern interface method for expression visitors that produce a result value of a specific type.
/// </summary>
/// <param name="visitor">An instance of a typed DbExpressionVisitor that produces a result value of type TResultType.</param>
/// <typeparam name="TResultType">The type of the result produced by <paramref name="visitor"/></typeparam>
/// <exception cref="ArgumentNullException"><paramref name="visitor"/> is null</exception>
/// <returns>An instance of <typeparamref name="TResultType"/>.</returns>
public abstract TResultType Accept<TResultType>(DbExpressionVisitor<TResultType> 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
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified binary value, which may be <c>null</c>
/// </summary>
/// <param name="value">The binary value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified binary value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified (nullable) Boolean value
/// </summary>
/// <param name="value">The Boolean value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified Boolean value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified (nullable) byte value
/// </summary>
/// <param name="value">The byte value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified byte value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified (nullable) <see cref="DateTime"/> value
/// </summary>
/// <param name="value">The DateTime value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified DateTime value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified (nullable) <see cref="DateTimeOffset"/> value
/// </summary>
/// <param name="value">The DateTimeOffset value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified DateTimeOffset value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified (nullable) decimal value
/// </summary>
/// <param name="value">The decimal value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified decimal value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified (nullable) double value
/// </summary>
/// <param name="value">The double value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified double value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified <see cref="DbGeography"/> value, which may be null.
/// </summary>
/// <param name="value">The DbGeography value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified DbGeography value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified <see cref="DbGeometry"/> value, which may be null.
/// </summary>
/// <param name="value">The DbGeometry value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified DbGeometry value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified (nullable) <see cref="Guid"/> value
/// </summary>
/// <param name="value">The Guid value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified Guid value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified (nullable) Int16 value
/// </summary>
/// <param name="value">The Int16 value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified Int16 value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified (nullable) Int32 value
/// </summary>
/// <param name="value">The Int32 value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified Int32 value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified (nullable) Int64 value
/// </summary>
/// <param name="value">The Int64 value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified Int64 value</returns>
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);
//}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified (nullable) Single value
/// </summary>
/// <param name="value">The Single value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified Single value</returns>
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);
}
/// <summary>
/// Creates a <see cref="DbExpression"/> that represents the specified string value
/// </summary>
/// <param name="value">The string value on which the returned expression should be based</param>
/// <returns>A <see cref="DbExpression"/> that represents the specified string value</returns>
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
/// <summary>
/// Produces a text-based tree representation of the DbExpression tree rooted at this expression
/// </summary>
/// <returns>A string containing the text-based tree representation</returns>
[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
}
/// <summary>
/// The abstract base type for expressions that accept two expression operands.
/// </summary>
[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;
}
/// <summary>
/// Gets the <see cref="DbExpression"/> that defines the left argument.
/// </summary>
public DbExpression Left { get { return _left; } }
/// <summary>
/// Gets the <see cref="DbExpression"/> that defines the right argument.
/// </summary>
public DbExpression Right { get { return _right; } }
}
/// <summary>
/// The abstract base type for expressions that accept a single expression operand
/// </summary>
[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;
}
/// <summary>
/// Gets the <see cref="DbExpression"/> that defines the argument.
/// </summary>
public DbExpression Argument { get { return this._argument; } }
}
}
|