File: System\Data\Mapping\ViewGeneration\Structures\Constant.cs
Project: ndp\fx\src\DataEntity\System.Data.Entity.csproj (System.Data.Entity)
//---------------------------------------------------------------------
// <copyright file="Constant.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
 
namespace System.Data.Mapping.ViewGeneration.Structures
{
    using System.Collections.Generic;
    using System.Data.Common.CommandTrees;
    using System.Data.Common.CommandTrees.ExpressionBuilder;
    using System.Data.Common.Utils;
    using System.Data.Mapping.ViewGeneration.CqlGeneration;
    using System.Data.Metadata.Edm;
    using System.Diagnostics;
    using System.Text;
 
    /// <summary>
    /// This class denotes a constant that can be stored in multiconstants or projected in fields.
    /// </summary>
    internal abstract class Constant : InternalBase
    {
        #region Fields
        internal static readonly IEqualityComparer<Constant> EqualityComparer = new CellConstantComparer();
        internal static readonly Constant Null = NullConstant.Instance;
        internal static readonly Constant NotNull = new NegatedConstant( new Constant[] { NullConstant.Instance });
        internal static readonly Constant Undefined = UndefinedConstant.Instance;
        /// <summary>
        /// Represents scalar constants within a finite set that are not specified explicitly in the domain.
        /// Currently only used as a Sentinel node to prevent expression optimization
        /// </summary>
        internal static readonly Constant AllOtherConstants = AllOtherConstantsConstant.Instance;
        #endregion
 
        #region Methods
        internal abstract bool IsNull();
 
        internal abstract bool IsNotNull();
 
        internal abstract bool IsUndefined();
 
        /// <summary>
        /// Returns true if this constant contains not null. 
        /// Implemented in <see cref="NegatedConstant"/> class, all other implementations return false.
        /// </summary>
        internal abstract bool HasNotNull();
 
        /// <summary>
        /// Generates eSQL for the constant expression.
        /// </summary>
        /// <param name="outputMember">The member to which this constant is directed</param>
        internal abstract StringBuilder AsEsql(StringBuilder builder, MemberPath outputMember, string blockAlias);
 
        /// <summary>
        /// Generates CQT for the constant expression.
        /// </summary>
        /// <param name="row">The input row.</param>
        /// <param name="outputMember">The member to which this constant is directed</param>
        internal abstract DbExpression AsCqt(DbExpression row, MemberPath outputMember);
 
        public override bool Equals(object obj)
        {
            Constant cellConst = obj as Constant;
            if (cellConst == null)
            {
                return false;
            }
            else
            {
                return IsEqualTo(cellConst);
            }
        }
 
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
 
        protected abstract bool IsEqualTo(Constant right);
 
        internal abstract string ToUserString();
 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static void ConstantsToUserString(StringBuilder builder, Set<Constant> constants)
        {
            bool isFirst = true;
            foreach (Constant constant in constants)
            {
                if (isFirst == false)
                {
                    builder.Append(System.Data.Entity.Strings.ViewGen_CommaBlank);
                }
                isFirst = false;
                string constrStr = constant.ToUserString();
                builder.Append(constrStr);
            }
        }
        #endregion
 
        #region Comparer class
        private class CellConstantComparer : IEqualityComparer<Constant>
        {
            public bool Equals(Constant left, Constant right)
            {
                // Quick check with references
                if (object.ReferenceEquals(left, right))
                {
                    // Gets the Null and Undefined case as well
                    return true;
                }
                // One of them is non-null at least. So if the other one is
                // null, we cannot be equal
                if (left == null || right == null)
                {
                    return false;
                }
                // Both are non-null at this point
                return left.IsEqualTo(right);
            }
 
            public int GetHashCode(Constant key)
            {
                EntityUtil.CheckArgumentNull(key, "key");
                return key.GetHashCode();
            }
        }
        #endregion
 
        #region Special constant classes (NullConstant, UndefinedConstant, AllOtherConstants)
        private sealed class NullConstant : Constant
        {
            internal static readonly Constant Instance = new NullConstant();
 
            private NullConstant() { }
 
            #region Methods
            internal override bool IsNull()
            {
                return true;
            }
 
            internal override bool IsNotNull()
            {
                return false;
            }
 
            internal override bool IsUndefined()
            {
                return false;
            }
 
            internal override bool HasNotNull()
            {
                return false;
            }
 
            internal override StringBuilder AsEsql(StringBuilder builder, MemberPath outputMember, string blockAlias)
            {
                Debug.Assert(outputMember.LeafEdmMember != null, "Constant can't correspond to an empty member path.");
                EdmType constType = Helper.GetModelTypeUsage(outputMember.LeafEdmMember).EdmType;
 
                builder.Append("CAST(NULL AS ");
                CqlWriter.AppendEscapedTypeName(builder, constType);
                builder.Append(')');
                return builder;
            }
 
            internal override DbExpression AsCqt(DbExpression row, MemberPath outputMember)
            {
                Debug.Assert(outputMember.LeafEdmMember != null, "Constant can't correspond to an empty path.");
                EdmType constType = Helper.GetModelTypeUsage(outputMember.LeafEdmMember).EdmType;
 
                return TypeUsage.Create(constType).Null();
            }
 
            public override int GetHashCode()
            {
                return 0;
            }
 
            protected override bool IsEqualTo(Constant right)
            {
                Debug.Assert(Object.ReferenceEquals(this, Instance), "this must be == Instance for NullConstant");
                return Object.ReferenceEquals(this, right);
            }
 
            internal override string ToUserString()
            {
                return System.Data.Entity.Strings.ViewGen_Null;
            }
 
            internal override void ToCompactString(StringBuilder builder)
            {
                builder.Append("NULL");
            }
            #endregion
        }
        private sealed class UndefinedConstant : Constant
        {
            internal static readonly Constant Instance = new UndefinedConstant();
 
            private UndefinedConstant() { }
 
            #region Methods
            internal override bool IsNull()
            {
                return false;
            }
 
            internal override bool IsNotNull()
            {
                return false;
            }
 
            internal override bool IsUndefined()
            {
                return true;
            }
 
            internal override bool HasNotNull()
            {
                return false;
            }
 
            /// <summary>
            /// Not supported in this class.
            /// </summary>
            internal override StringBuilder AsEsql(StringBuilder builder, MemberPath outputMember, string blockAlias)
            {
                Debug.Fail("Should not be called.");
                return null; // To keep the compiler happy
            }
 
            /// <summary>
            /// Not supported in this class.
            /// </summary>
            internal override DbExpression AsCqt(DbExpression row, MemberPath outputMember)
            {
                Debug.Fail("Should not be called.");
                return null; // To keep the compiler happy
            }
 
            public override int GetHashCode()
            {
                return 0;
            }
 
            protected override bool IsEqualTo(Constant right)
            {
                Debug.Assert(Object.ReferenceEquals(this, Instance), "this must be == Instance for NullConstant");
                return Object.ReferenceEquals(this, right);
            }
 
            /// <summary>
            /// Not supported in this class.
            /// </summary>
            internal override string ToUserString()
            {
                Debug.Fail("We should not emit a message about Undefined constants to the user.");
                return null;
            }
 
            internal override void ToCompactString(StringBuilder builder)
            {
                builder.Append("?");
            }
            #endregion
        }
        private sealed class AllOtherConstantsConstant : Constant
        {
            internal static readonly Constant Instance = new AllOtherConstantsConstant();
 
            private AllOtherConstantsConstant() { }
 
            #region Methods
            internal override bool IsNull()
            {
                return false;
            }
 
            internal override bool IsNotNull()
            {
                return false;
            }
 
            internal override bool IsUndefined()
            {
                return false;
            }
 
            internal override bool HasNotNull()
            {
                return false;
            }
 
            /// <summary>
            /// Not supported in this class.
            /// </summary>
            internal override StringBuilder AsEsql(StringBuilder builder, MemberPath outputMember, string blockAlias)
            {
                Debug.Fail("Should not be called.");
                return null; // To keep the compiler happy
            }
 
            /// <summary>
            /// Not supported in this class.
            /// </summary>
            internal override DbExpression AsCqt(DbExpression row, MemberPath outputMember)
            {
                Debug.Fail("Should not be called.");
                return null; // To keep the compiler happy
            }
 
            public override int GetHashCode()
            {
                return 0;
            }
 
            protected override bool IsEqualTo(Constant right)
            {
                Debug.Assert(Object.ReferenceEquals(this, Instance), "this must be == Instance for NullConstant");
                return Object.ReferenceEquals(this, right);
            }
 
            /// <summary>
            /// Not supported in this class.
            /// </summary>
            internal override string ToUserString()
            {
                Debug.Fail("We should not emit a message about Undefined constants to the user.");
                return null;
            }
 
            internal override void ToCompactString(StringBuilder builder)
            {
                builder.Append("AllOtherConstants");
            }
            #endregion
        }
        #endregion
    }
}