Literal.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / Common / EntitySql / Literal.cs / 4 / Literal.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner [....] [....]
//--------------------------------------------------------------------- 
 

namespace System.Data.Common.EntitySql 
{
    using System;
    using System.Globalization;
    using System.Collections; 
    using System.Collections.Generic;
    using System.Diagnostics; 
    using System.Text; 

    ///  
    /// defines literal value class
    /// 
    internal enum LiteralKind
    { 
        Number,
        String, 
        NonUnicodeString, 
        UnicodeString,
        Boolean, 
        Binary,
        DateTime,
        Time,
        DateTimeOffset, 
        Guid,
        Null 
    } 

    ///  
    /// Represents a literal ast node.
    /// 
    internal sealed class Literal : Expr
    { 
        private string _originalValue;
        private object _computedValue; 
        private Type _type; 
        private bool _isNull;
        private bool _wasValueComputed = false; 
        private LiteralKind _literalKind;
        private static readonly Byte[] _emptyByteArray = new byte[0];

 
        /// 
        /// initializes a literal ast node. 
        ///  
        /// literal value in cql string representation
        /// literal value class 
        /// query
        /// input position
        internal Literal( string originalValue, LiteralKind kind, string query, int inputPos )
            : base(query, inputPos) 
        {
            _originalValue = originalValue; 
            _literalKind = kind; 
        }
 
        /// 
        /// static factory to create boolean literals by value only
        /// 
        ///  
        internal static Literal NewBooleanLiteral( bool value ) { return new Literal(value); }
 
        private Literal( bool boolLiteral ) 
            : base(null, 0)
        { 
            _wasValueComputed = true;
            _originalValue = String.Empty;
            _computedValue = boolLiteral;
            _type = typeof(System.Boolean); 
        }
 
        ///  
        /// returns true if original value is of number kind
        ///  
        internal bool IsNumberKind
        {
            get
            { 
                return (_literalKind == LiteralKind.Number);
            } 
        } 

        ///  
        /// returns true if original value is signed
        /// 
        internal bool IsSigned
        { 
            get
            { 
                return (_originalValue[0] == '-' || _originalValue[0] == '+'); 
            }
        } 

        /// 
        /// prefix a numeric literal with sign
        ///  
        /// 
        internal void PrefixSign( string sign ) 
        { 
            System.Diagnostics.Debug.Assert(IsNumberKind && !IsSigned);
            System.Diagnostics.Debug.Assert(sign[0] == '-' || sign[0] == '+', "sign symbol must be + or -"); 
            System.Diagnostics.Debug.Assert(_computedValue == null);

            _originalValue = sign + _originalValue;
        } 

 
        ///  
        /// returns the original literal value
        ///  
        internal string OriginalValue
        {
            get
            { 
                return _originalValue;
            } 
        } 

 
        //
        //  Computed members
        //
 
        /// 
        /// returns literal converted value 
        ///  
        /// 
        ///  
        /// 
        internal object Value
        {
            get 
            {
                ComputeValue(); 
 
                return _computedValue;
            } 
        }

        /// 
        /// Returns true if literal value is null, false otherwise 
        /// 
        ///  
        ///  
        /// 
        internal bool IsNullLiteral 
        {
            get
            {
                ComputeValue(); 

                return _isNull; 
            } 
        }
 
        /// 
        /// returns true if literal is string type, false otherwise
        /// 
        ///  
        /// 
        ///  
        internal bool IsString 
        {
            get 
            {
                ComputeValue();

                return (_computedValue is String); 
            }
        } 
 
        /// 
        /// returns true if literal is unicode string type, false otherwise 
        /// 
        /// 
        /// 
        ///  
        internal bool IsUnicodeString
        { 
            get 
            {
                return IsString && _literalKind == LiteralKind.UnicodeString; 
            }
        }

        ///  
        /// returns literal value type. if value is null, returns null
        ///  
        ///  
        /// 
        ///  
        internal Type Type
        {
            get
            { 
                ComputeValue();
 
                return _type; 
            }
        } 


        private void ComputeValue()
        { 
            if (!_wasValueComputed)
            { 
                _wasValueComputed = true; 

                switch (_literalKind) 
                {
                    case LiteralKind.Number:
                        _computedValue = ConvertNumericLiteral(ErrCtx, _originalValue);
                        break; 

                    case LiteralKind.NonUnicodeString: 
                        _computedValue = GetStringLiteralValue(_originalValue, false /* isUnicode */); 
                        break;
 
                    case LiteralKind.UnicodeString:
                        _computedValue = GetStringLiteralValue(_originalValue, true /* isUnicode */);
                        break;
 
                    case LiteralKind.Boolean:
                        _computedValue = ConvertBooleanLiteralValue(ErrCtx, _originalValue); 
                        break; 

                    case LiteralKind.Binary: 
                        _computedValue = ConvertBinaryLiteralValue(ErrCtx, _originalValue);
                        break;

                    case LiteralKind.DateTime: 
                        _computedValue = ConvertDateTimeLiteralValue(ErrCtx, _originalValue);
                        break; 
 
                    case LiteralKind.Time:
                        _computedValue = ConvertTimeLiteralValue(ErrCtx, _originalValue); 
                        break;

                    case LiteralKind.DateTimeOffset:
                        _computedValue = ConvertDateTimeOffsetLiteralValue(ErrCtx, _originalValue); 
                        break;
 
                    case LiteralKind.Guid: 
                        _computedValue = ConvertGuidLiteralValue(ErrCtx, _originalValue);
                        break; 

                    case LiteralKind.Null:
                        _computedValue = null;
                        _isNull = true; 
                        break;
 
                    default: 
                        throw EntityUtil.NotSupported(System.Data.Entity.Strings.LiteralTypeNotSupported(_literalKind.ToString()));
 
                }

                _type = _isNull ? null : _computedValue.GetType();
            } 
        }
 
 

        // 
        // Conversion Helpers
        //

        static char[] numberSuffixes = new char[] { 'U', 'u', 'L', 'l', 'F', 'f', 'M', 'm', 'D', 'd' }; 
        static char[] floatTokens = new char[] { '.', 'E', 'e' };
        private static object ConvertNumericLiteral(ErrorContext errCtx , string numericString) 
        { 

            int k = numericString.IndexOfAny(numberSuffixes); 
            if (-1 != k)
            {
                string suffix = numericString.Substring(k).ToUpperInvariant();
                string numberPart = numericString.Substring(0, numericString.Length - suffix.Length); 
                switch (suffix)
                { 
                    case "U": 
                        {
                            UInt32 value; 
                            if (!UInt32.TryParse(numberPart, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
                            {
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "unsigned int"));
                            } 
                            return value;
                        } 
                        ; 

                    case "L": 
                        {
                            long value;
                            if (!Int64.TryParse(numberPart, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
                            { 
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "long"));
                            } 
                            return value; 
                        }
                        ; 

                    case "UL":
                    case "LU":
                        { 
                            UInt64 value;
                            if (!UInt64.TryParse(numberPart, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) 
                            { 
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "unsigned long"));
                            } 
                            return value;
                        }
                        ;
 
                    case "F":
                        { 
                            Single value; 
                            if (!Single.TryParse(numberPart, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
                            { 
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "float"));
                            }
                            return value;
                        } 
                        ;
 
                    case "M": 
                        {
                            Decimal value; 
                            if (!Decimal.TryParse(numberPart, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value))
                            {
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "decimal"));
                            } 
                            return value;
                        } 
                        ; 

                    case "D": 
                        {
                            Double value;
                            if (!Double.TryParse(numberPart, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
                            { 
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "double"));
                            } 
                            return value; 
                        }
                        ; 

                }
            }
 
            //
            // if hit this point, try default conversion 
            // 
            return DefaultNumericConversion(numericString, errCtx);
 
        }


 
        /// 
        /// performs conversion of numeric strings that have no type suffix hint. 
        ///  
        /// 
        ///  
        /// 
        private static object DefaultNumericConversion( string numericString, ErrorContext errCtx )
        {
 
            if (-1 != numericString.IndexOfAny(floatTokens))
            { 
                Double value; 
                if (!Double.TryParse(numericString, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
                { 
                    throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "double"));
                }

                return value; 
            }
            else 
            { 
                Int32 int32Value;
                if (Int32.TryParse(numericString, NumberStyles.Integer, CultureInfo.InvariantCulture, out int32Value)) 
                {
                    return int32Value;
                }
 
                Int64 int64Value;
                if (!Int64.TryParse(numericString, NumberStyles.Integer, CultureInfo.InvariantCulture, out int64Value)) 
                { 
                    throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "long"));
                } 

                return int64Value;
            }
 
        }
 
        ///  
        /// converts boolean literal value
        ///  
        /// 
        /// 
        /// 
        private static bool ConvertBooleanLiteralValue( ErrorContext errCtx, string booleanLiteralValue ) 
        {
            bool result = false; 
            if (!Boolean.TryParse(booleanLiteralValue, out result)) 
            {
                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.InvalidLiteralFormat("Boolean", booleanLiteralValue)); 
            }
            return result;
        }
 

        ///  
        /// returns the string literal value. 
        /// 
        ///  
        /// 
        /// 
        private static string GetStringLiteralValue( string stringLiteralValue, bool isUnicode )
        { 
            Debug.Assert(stringLiteralValue.Length >= 2);
            Debug.Assert(isUnicode == ('N' == stringLiteralValue[0]),"invalid string literal value"); 
 
            int startIndex = (isUnicode ? 2 : 1);
            char delimiter = stringLiteralValue[startIndex - 1]; 

            Debug.Assert(delimiter.Equals('\'') || delimiter.Equals('\"'), "invalid string delimiter");

            // NOTE: this is not a precondition validation. This validation is for security purposes based on the 
            // paranoid assumption that all input is evil. we should not see this exception under normal
            // conditions. 
            if (delimiter != '\'' && delimiter != '\"') 
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.MalformedStringLiteralPayload); 
            }

            string result = "";
 
            // NOTE: this is not a precondition validation. This validation is for security purposes based on the
            // paranoid assumption that all input is evil. we should not see this exception under normal 
            // conditions. 
            int before = stringLiteralValue.Split(new char[] { delimiter }).Length - 1;
            Debug.Assert(before % 2 == 0, "must have an even number of delimiters in the string literal"); 
            if (0 != (before % 2))
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.MalformedStringLiteralPayload);
            } 

            // 
            // extract the payload and replace escaped chars that match the envelope delimiter 
            //
            result = stringLiteralValue.Substring(startIndex, stringLiteralValue.Length - (1 + startIndex)); 
            result = result.Replace(new String(delimiter, 2), new String(delimiter, 1));

            // NOTE: this is not a precondition validation. This validation is for security purposes based on the
            // paranoid assumption that all input is evil. we should not see this exception under normal 
            // conditions.
            int after = result.Split(new char[] { delimiter }).Length - 1; 
            Debug.Assert(after == (before - 2) / 2); 
            if ((after != ((before - 2) / 2)))
            { 
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.MalformedStringLiteralPayload);
            }

            return result; 
        }
 
 
        /// 
        /// converts hex string to byte array 
        /// 
        /// 
        /// 
        ///  
        private static byte[] ConvertBinaryLiteralValue( ErrorContext errCtx, string binaryLiteralValue )
        { 
            Debug.Assert(null != binaryLiteralValue, "binaryStringLiteral must not be null"); 

            if (String.IsNullOrEmpty(binaryLiteralValue)) 
            {
                return _emptyByteArray;
            }
 
            int startIndex = 0;
            int endIndex = binaryLiteralValue.Length - 1; 
            Debug.Assert(startIndex <= endIndex, "startIndex <= endIndex"); 
            int binaryStringLen = endIndex - startIndex + 1;
            int byteArrayLen = binaryStringLen / 2; 
            bool hasOddBytes = 0 != (binaryStringLen % 2);
            if (hasOddBytes)
            {
                byteArrayLen++; 
            }
 
            byte[] binaryValue = new byte[byteArrayLen]; 
            int arrayIndex = 0;
            if (hasOddBytes) 
            {
                binaryValue[arrayIndex++] = (byte)HexDigitToBinaryValue(binaryLiteralValue[startIndex++]);
            }
 
            while (startIndex < endIndex)
            { 
                binaryValue[arrayIndex++] = (byte)((HexDigitToBinaryValue(binaryLiteralValue[startIndex++]) << 4) | HexDigitToBinaryValue(binaryLiteralValue[startIndex++])); 
            }
 
            return binaryValue;
        }

        ///  
        /// parse single hex char
        /// PRECONDITION - hexChar must be valid hex digit 
        ///  
        /// 
        ///  
        private static int HexDigitToBinaryValue( char hexChar )
        {
            if ( hexChar >= '0' && hexChar <= '9' ) return (int)( hexChar - '0' );
            if ( hexChar >= 'A' && hexChar <= 'F' ) return (int)( hexChar - 'A' ) + 10; 
            if ( hexChar >= 'a' && hexChar <= 'f' ) return (int)( hexChar - 'a' ) + 10;
            Debug.Assert(false, "Invalid Hexadecimal Digit"); 
            throw EntityUtil.ArgumentOutOfRange("hexadecimal digit is not valid"); 
        }
 

        static readonly char[] _datetimeSeparators = new char[] { ' ', ':', '-', '.' };
        static readonly char[] _dateSeparators = new char[] { '-' };
        static readonly char[] _timeSeparators = new char[] { ':', '.' }; 
        static readonly char[] _datetimeOffsetSeparators = new char[] { ' ', ':', '-', '.', '+', '-' };
 
        ///  
        /// converts datetime literal value
        ///  
        /// 
        /// 
        /// 
        private static DateTime ConvertDateTimeLiteralValue( ErrorContext errCtx, string datetimeLiteralValue ) 
        {
            string[] datetimeParts = datetimeLiteralValue.Split(_datetimeSeparators, StringSplitOptions.RemoveEmptyEntries); 
 
            Debug.Assert(datetimeParts.Length >= 5, "datetime literal value must have at least 5 parts");
 
            int year;
            int month;
            int day;
            GetDateParts(datetimeLiteralValue, datetimeParts, out year, out month, out day); 
            int hour;
            int minute; 
            int second; 
            int ticks;
            GetTimeParts(datetimeLiteralValue, datetimeParts, 3, out hour, out minute, out second, out ticks); 

            Debug.Assert(year >= 1 && year <= 9999);
            Debug.Assert(month >= 1 && month <= 12);
            Debug.Assert(day >= 1 && day <= 31); 
            Debug.Assert(hour >= 0 && hour <= 24);
            Debug.Assert(minute >= 0 && minute <= 59); 
            Debug.Assert(second >= 0 && second <= 59); 
            Debug.Assert(ticks >= 0 && ticks <= 9999999);
            DateTime dateTime = new DateTime(year, month, day, hour, minute, second, 0); 
            dateTime = dateTime.AddTicks(ticks);
            return dateTime;
        }
 
        private static DateTimeOffset ConvertDateTimeOffsetLiteralValue(ErrorContext errCtx, string datetimeLiteralValue)
        { 
            string[] datetimeParts = datetimeLiteralValue.Split(_datetimeOffsetSeparators, StringSplitOptions.RemoveEmptyEntries); 

            Debug.Assert(datetimeParts.Length >= 7, "datetime literal value must have at least 7 parts"); 

            int year;
            int month;
            int day; 
            GetDateParts(datetimeLiteralValue, datetimeParts, out year, out month, out day);
            int hour; 
            int minute; 
            int second;
            int ticks; 
            //Copy the time parts into a different array since the last two parts will be handled in this method.
            string[] timeParts = new String[datetimeParts.Length - 2];
            Array.Copy(datetimeParts, timeParts, datetimeParts.Length - 2);
            GetTimeParts(datetimeLiteralValue, timeParts, 3, out hour, out minute, out second, out ticks); 

            Debug.Assert(year >= 1 && year <= 9999); 
            Debug.Assert(month >= 1 && month <= 12); 
            Debug.Assert(day >= 1 && day <= 31);
            Debug.Assert(hour >= 0 && hour <= 24); 
            Debug.Assert(minute >= 0 && minute <= 59);
            Debug.Assert(second >= 0 && second <= 59);
            Debug.Assert(ticks >= 0 && ticks <= 9999999);
            int offsetHours = Int32.Parse(datetimeParts[datetimeParts.Length - 2], NumberStyles.Integer, CultureInfo.InvariantCulture); 
            int offsetMinutes = Int32.Parse(datetimeParts[datetimeParts.Length - 1], NumberStyles.Integer, CultureInfo.InvariantCulture);
            TimeSpan offsetTimeSpan = new TimeSpan(offsetHours, offsetMinutes, 0); 
 
            //If DateTimeOffset had a negative offset, we should negate the timespan
            if(datetimeLiteralValue.IndexOf('+') == -1) 
            {
                offsetTimeSpan = offsetTimeSpan.Negate();
            }
            DateTime dateTime = new DateTime(year, month, day, hour, minute, second, 0); 
            dateTime = dateTime.AddTicks(ticks);
 
            try 
            {
                return new DateTimeOffset(dateTime, offsetTimeSpan); 
            }
            catch (ArgumentOutOfRangeException e)
            {
                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.InvalidDateTimeOffsetLiteral(datetimeLiteralValue), e); 
            }
        } 
 

 
        /// 
        /// converts time literal value
        /// 
        ///  
        /// 
        ///  
        private static TimeSpan ConvertTimeLiteralValue(ErrorContext errCtx, string datetimeLiteralValue) 
        {
            string[] datetimeParts = datetimeLiteralValue.Split(_datetimeSeparators, StringSplitOptions.RemoveEmptyEntries); 

            Debug.Assert(datetimeParts.Length >= 2, "time literal value must have at least 2 parts");

            int hour; 
            int minute;
            int second; 
            int ticks; 
            GetTimeParts(datetimeLiteralValue, datetimeParts, 0, out hour, out minute, out second, out ticks);
 
            Debug.Assert(hour >= 0 && hour <= 24);
            Debug.Assert(minute >= 0 && minute <= 59);
            Debug.Assert(second >= 0 && second <= 59);
            Debug.Assert(ticks >= 0 && ticks <= 9999999); 
            TimeSpan ts = new TimeSpan(hour, minute, second);
            ts = ts.Add(new TimeSpan(ticks)); 
            return ts; 
        }
 
        private static void GetTimeParts(string datetimeLiteralValue, string[] datetimeParts, int timePartStartIndex, out int hour, out int minute, out int second, out int ticks)
        {
            hour = Int32.Parse(datetimeParts[timePartStartIndex], NumberStyles.Integer, CultureInfo.InvariantCulture);
            if (hour > 23) 
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidHour(datetimeParts[timePartStartIndex], datetimeLiteralValue)); 
            } 
            minute = Int32.Parse(datetimeParts[++timePartStartIndex], NumberStyles.Integer, CultureInfo.InvariantCulture);
            if (minute > 59) 
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidMinute(datetimeParts[timePartStartIndex], datetimeLiteralValue));
            }
            second = 0; 
            ticks = 0;
            timePartStartIndex++; 
            if (datetimeParts.Length > timePartStartIndex) 
            {
                second = Int32.Parse(datetimeParts[timePartStartIndex], NumberStyles.Integer, CultureInfo.InvariantCulture); 
                if (second > 59)
                {
                    throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidSecond(datetimeParts[timePartStartIndex], datetimeLiteralValue));
                } 
                timePartStartIndex++;
                if (datetimeParts.Length > timePartStartIndex) 
                { 
                    //We need fractional time part to be seven digits
                    string ticksString = datetimeParts[timePartStartIndex].PadRight(7, '0'); 
                    ticks = Int32.Parse(ticksString , NumberStyles.Integer, CultureInfo.InvariantCulture);
                }

            } 
        }
 
        private static void GetDateParts(string datetimeLiteralValue, string[] datetimeParts, out int year, out int month, out int day) 
        {
            year = Int32.Parse(datetimeParts[0], NumberStyles.Integer, CultureInfo.InvariantCulture); 
            if (year < 1 || year > 9999)
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidYear(datetimeParts[0], datetimeLiteralValue));
            } 
            month = Int32.Parse(datetimeParts[1], NumberStyles.Integer, CultureInfo.InvariantCulture);
            if (month < 1 || month > 12) 
            { 
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidMonth(datetimeParts[1], datetimeLiteralValue));
            } 
            day = Int32.Parse(datetimeParts[2], NumberStyles.Integer, CultureInfo.InvariantCulture);
            if (day < 1)
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidDay(datetimeParts[2], datetimeLiteralValue)); 
            }
            if (day > DateTime.DaysInMonth(year, month)) 
            { 
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidDayInMonth(datetimeParts[2], datetimeParts[1], datetimeLiteralValue));
            } 
        }

        /// 
        /// converts guid literal value 
        /// 
        ///  
        ///  
        /// 
        private static Guid ConvertGuidLiteralValue( ErrorContext errCtx, string guidLiteralValue ) 
        {
            return new Guid(guidLiteralValue);
        }
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner [....] [....]
//--------------------------------------------------------------------- 
 

namespace System.Data.Common.EntitySql 
{
    using System;
    using System.Globalization;
    using System.Collections; 
    using System.Collections.Generic;
    using System.Diagnostics; 
    using System.Text; 

    ///  
    /// defines literal value class
    /// 
    internal enum LiteralKind
    { 
        Number,
        String, 
        NonUnicodeString, 
        UnicodeString,
        Boolean, 
        Binary,
        DateTime,
        Time,
        DateTimeOffset, 
        Guid,
        Null 
    } 

    ///  
    /// Represents a literal ast node.
    /// 
    internal sealed class Literal : Expr
    { 
        private string _originalValue;
        private object _computedValue; 
        private Type _type; 
        private bool _isNull;
        private bool _wasValueComputed = false; 
        private LiteralKind _literalKind;
        private static readonly Byte[] _emptyByteArray = new byte[0];

 
        /// 
        /// initializes a literal ast node. 
        ///  
        /// literal value in cql string representation
        /// literal value class 
        /// query
        /// input position
        internal Literal( string originalValue, LiteralKind kind, string query, int inputPos )
            : base(query, inputPos) 
        {
            _originalValue = originalValue; 
            _literalKind = kind; 
        }
 
        /// 
        /// static factory to create boolean literals by value only
        /// 
        ///  
        internal static Literal NewBooleanLiteral( bool value ) { return new Literal(value); }
 
        private Literal( bool boolLiteral ) 
            : base(null, 0)
        { 
            _wasValueComputed = true;
            _originalValue = String.Empty;
            _computedValue = boolLiteral;
            _type = typeof(System.Boolean); 
        }
 
        ///  
        /// returns true if original value is of number kind
        ///  
        internal bool IsNumberKind
        {
            get
            { 
                return (_literalKind == LiteralKind.Number);
            } 
        } 

        ///  
        /// returns true if original value is signed
        /// 
        internal bool IsSigned
        { 
            get
            { 
                return (_originalValue[0] == '-' || _originalValue[0] == '+'); 
            }
        } 

        /// 
        /// prefix a numeric literal with sign
        ///  
        /// 
        internal void PrefixSign( string sign ) 
        { 
            System.Diagnostics.Debug.Assert(IsNumberKind && !IsSigned);
            System.Diagnostics.Debug.Assert(sign[0] == '-' || sign[0] == '+', "sign symbol must be + or -"); 
            System.Diagnostics.Debug.Assert(_computedValue == null);

            _originalValue = sign + _originalValue;
        } 

 
        ///  
        /// returns the original literal value
        ///  
        internal string OriginalValue
        {
            get
            { 
                return _originalValue;
            } 
        } 

 
        //
        //  Computed members
        //
 
        /// 
        /// returns literal converted value 
        ///  
        /// 
        ///  
        /// 
        internal object Value
        {
            get 
            {
                ComputeValue(); 
 
                return _computedValue;
            } 
        }

        /// 
        /// Returns true if literal value is null, false otherwise 
        /// 
        ///  
        ///  
        /// 
        internal bool IsNullLiteral 
        {
            get
            {
                ComputeValue(); 

                return _isNull; 
            } 
        }
 
        /// 
        /// returns true if literal is string type, false otherwise
        /// 
        ///  
        /// 
        ///  
        internal bool IsString 
        {
            get 
            {
                ComputeValue();

                return (_computedValue is String); 
            }
        } 
 
        /// 
        /// returns true if literal is unicode string type, false otherwise 
        /// 
        /// 
        /// 
        ///  
        internal bool IsUnicodeString
        { 
            get 
            {
                return IsString && _literalKind == LiteralKind.UnicodeString; 
            }
        }

        ///  
        /// returns literal value type. if value is null, returns null
        ///  
        ///  
        /// 
        ///  
        internal Type Type
        {
            get
            { 
                ComputeValue();
 
                return _type; 
            }
        } 


        private void ComputeValue()
        { 
            if (!_wasValueComputed)
            { 
                _wasValueComputed = true; 

                switch (_literalKind) 
                {
                    case LiteralKind.Number:
                        _computedValue = ConvertNumericLiteral(ErrCtx, _originalValue);
                        break; 

                    case LiteralKind.NonUnicodeString: 
                        _computedValue = GetStringLiteralValue(_originalValue, false /* isUnicode */); 
                        break;
 
                    case LiteralKind.UnicodeString:
                        _computedValue = GetStringLiteralValue(_originalValue, true /* isUnicode */);
                        break;
 
                    case LiteralKind.Boolean:
                        _computedValue = ConvertBooleanLiteralValue(ErrCtx, _originalValue); 
                        break; 

                    case LiteralKind.Binary: 
                        _computedValue = ConvertBinaryLiteralValue(ErrCtx, _originalValue);
                        break;

                    case LiteralKind.DateTime: 
                        _computedValue = ConvertDateTimeLiteralValue(ErrCtx, _originalValue);
                        break; 
 
                    case LiteralKind.Time:
                        _computedValue = ConvertTimeLiteralValue(ErrCtx, _originalValue); 
                        break;

                    case LiteralKind.DateTimeOffset:
                        _computedValue = ConvertDateTimeOffsetLiteralValue(ErrCtx, _originalValue); 
                        break;
 
                    case LiteralKind.Guid: 
                        _computedValue = ConvertGuidLiteralValue(ErrCtx, _originalValue);
                        break; 

                    case LiteralKind.Null:
                        _computedValue = null;
                        _isNull = true; 
                        break;
 
                    default: 
                        throw EntityUtil.NotSupported(System.Data.Entity.Strings.LiteralTypeNotSupported(_literalKind.ToString()));
 
                }

                _type = _isNull ? null : _computedValue.GetType();
            } 
        }
 
 

        // 
        // Conversion Helpers
        //

        static char[] numberSuffixes = new char[] { 'U', 'u', 'L', 'l', 'F', 'f', 'M', 'm', 'D', 'd' }; 
        static char[] floatTokens = new char[] { '.', 'E', 'e' };
        private static object ConvertNumericLiteral(ErrorContext errCtx , string numericString) 
        { 

            int k = numericString.IndexOfAny(numberSuffixes); 
            if (-1 != k)
            {
                string suffix = numericString.Substring(k).ToUpperInvariant();
                string numberPart = numericString.Substring(0, numericString.Length - suffix.Length); 
                switch (suffix)
                { 
                    case "U": 
                        {
                            UInt32 value; 
                            if (!UInt32.TryParse(numberPart, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
                            {
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "unsigned int"));
                            } 
                            return value;
                        } 
                        ; 

                    case "L": 
                        {
                            long value;
                            if (!Int64.TryParse(numberPart, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
                            { 
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "long"));
                            } 
                            return value; 
                        }
                        ; 

                    case "UL":
                    case "LU":
                        { 
                            UInt64 value;
                            if (!UInt64.TryParse(numberPart, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) 
                            { 
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "unsigned long"));
                            } 
                            return value;
                        }
                        ;
 
                    case "F":
                        { 
                            Single value; 
                            if (!Single.TryParse(numberPart, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
                            { 
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "float"));
                            }
                            return value;
                        } 
                        ;
 
                    case "M": 
                        {
                            Decimal value; 
                            if (!Decimal.TryParse(numberPart, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value))
                            {
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "decimal"));
                            } 
                            return value;
                        } 
                        ; 

                    case "D": 
                        {
                            Double value;
                            if (!Double.TryParse(numberPart, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
                            { 
                                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "double"));
                            } 
                            return value; 
                        }
                        ; 

                }
            }
 
            //
            // if hit this point, try default conversion 
            // 
            return DefaultNumericConversion(numericString, errCtx);
 
        }


 
        /// 
        /// performs conversion of numeric strings that have no type suffix hint. 
        ///  
        /// 
        ///  
        /// 
        private static object DefaultNumericConversion( string numericString, ErrorContext errCtx )
        {
 
            if (-1 != numericString.IndexOfAny(floatTokens))
            { 
                Double value; 
                if (!Double.TryParse(numericString, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
                { 
                    throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "double"));
                }

                return value; 
            }
            else 
            { 
                Int32 int32Value;
                if (Int32.TryParse(numericString, NumberStyles.Integer, CultureInfo.InvariantCulture, out int32Value)) 
                {
                    return int32Value;
                }
 
                Int64 int64Value;
                if (!Int64.TryParse(numericString, NumberStyles.Integer, CultureInfo.InvariantCulture, out int64Value)) 
                { 
                    throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.CannotConvertNumericLiteral(numericString, "long"));
                } 

                return int64Value;
            }
 
        }
 
        ///  
        /// converts boolean literal value
        ///  
        /// 
        /// 
        /// 
        private static bool ConvertBooleanLiteralValue( ErrorContext errCtx, string booleanLiteralValue ) 
        {
            bool result = false; 
            if (!Boolean.TryParse(booleanLiteralValue, out result)) 
            {
                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.InvalidLiteralFormat("Boolean", booleanLiteralValue)); 
            }
            return result;
        }
 

        ///  
        /// returns the string literal value. 
        /// 
        ///  
        /// 
        /// 
        private static string GetStringLiteralValue( string stringLiteralValue, bool isUnicode )
        { 
            Debug.Assert(stringLiteralValue.Length >= 2);
            Debug.Assert(isUnicode == ('N' == stringLiteralValue[0]),"invalid string literal value"); 
 
            int startIndex = (isUnicode ? 2 : 1);
            char delimiter = stringLiteralValue[startIndex - 1]; 

            Debug.Assert(delimiter.Equals('\'') || delimiter.Equals('\"'), "invalid string delimiter");

            // NOTE: this is not a precondition validation. This validation is for security purposes based on the 
            // paranoid assumption that all input is evil. we should not see this exception under normal
            // conditions. 
            if (delimiter != '\'' && delimiter != '\"') 
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.MalformedStringLiteralPayload); 
            }

            string result = "";
 
            // NOTE: this is not a precondition validation. This validation is for security purposes based on the
            // paranoid assumption that all input is evil. we should not see this exception under normal 
            // conditions. 
            int before = stringLiteralValue.Split(new char[] { delimiter }).Length - 1;
            Debug.Assert(before % 2 == 0, "must have an even number of delimiters in the string literal"); 
            if (0 != (before % 2))
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.MalformedStringLiteralPayload);
            } 

            // 
            // extract the payload and replace escaped chars that match the envelope delimiter 
            //
            result = stringLiteralValue.Substring(startIndex, stringLiteralValue.Length - (1 + startIndex)); 
            result = result.Replace(new String(delimiter, 2), new String(delimiter, 1));

            // NOTE: this is not a precondition validation. This validation is for security purposes based on the
            // paranoid assumption that all input is evil. we should not see this exception under normal 
            // conditions.
            int after = result.Split(new char[] { delimiter }).Length - 1; 
            Debug.Assert(after == (before - 2) / 2); 
            if ((after != ((before - 2) / 2)))
            { 
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.MalformedStringLiteralPayload);
            }

            return result; 
        }
 
 
        /// 
        /// converts hex string to byte array 
        /// 
        /// 
        /// 
        ///  
        private static byte[] ConvertBinaryLiteralValue( ErrorContext errCtx, string binaryLiteralValue )
        { 
            Debug.Assert(null != binaryLiteralValue, "binaryStringLiteral must not be null"); 

            if (String.IsNullOrEmpty(binaryLiteralValue)) 
            {
                return _emptyByteArray;
            }
 
            int startIndex = 0;
            int endIndex = binaryLiteralValue.Length - 1; 
            Debug.Assert(startIndex <= endIndex, "startIndex <= endIndex"); 
            int binaryStringLen = endIndex - startIndex + 1;
            int byteArrayLen = binaryStringLen / 2; 
            bool hasOddBytes = 0 != (binaryStringLen % 2);
            if (hasOddBytes)
            {
                byteArrayLen++; 
            }
 
            byte[] binaryValue = new byte[byteArrayLen]; 
            int arrayIndex = 0;
            if (hasOddBytes) 
            {
                binaryValue[arrayIndex++] = (byte)HexDigitToBinaryValue(binaryLiteralValue[startIndex++]);
            }
 
            while (startIndex < endIndex)
            { 
                binaryValue[arrayIndex++] = (byte)((HexDigitToBinaryValue(binaryLiteralValue[startIndex++]) << 4) | HexDigitToBinaryValue(binaryLiteralValue[startIndex++])); 
            }
 
            return binaryValue;
        }

        ///  
        /// parse single hex char
        /// PRECONDITION - hexChar must be valid hex digit 
        ///  
        /// 
        ///  
        private static int HexDigitToBinaryValue( char hexChar )
        {
            if ( hexChar >= '0' && hexChar <= '9' ) return (int)( hexChar - '0' );
            if ( hexChar >= 'A' && hexChar <= 'F' ) return (int)( hexChar - 'A' ) + 10; 
            if ( hexChar >= 'a' && hexChar <= 'f' ) return (int)( hexChar - 'a' ) + 10;
            Debug.Assert(false, "Invalid Hexadecimal Digit"); 
            throw EntityUtil.ArgumentOutOfRange("hexadecimal digit is not valid"); 
        }
 

        static readonly char[] _datetimeSeparators = new char[] { ' ', ':', '-', '.' };
        static readonly char[] _dateSeparators = new char[] { '-' };
        static readonly char[] _timeSeparators = new char[] { ':', '.' }; 
        static readonly char[] _datetimeOffsetSeparators = new char[] { ' ', ':', '-', '.', '+', '-' };
 
        ///  
        /// converts datetime literal value
        ///  
        /// 
        /// 
        /// 
        private static DateTime ConvertDateTimeLiteralValue( ErrorContext errCtx, string datetimeLiteralValue ) 
        {
            string[] datetimeParts = datetimeLiteralValue.Split(_datetimeSeparators, StringSplitOptions.RemoveEmptyEntries); 
 
            Debug.Assert(datetimeParts.Length >= 5, "datetime literal value must have at least 5 parts");
 
            int year;
            int month;
            int day;
            GetDateParts(datetimeLiteralValue, datetimeParts, out year, out month, out day); 
            int hour;
            int minute; 
            int second; 
            int ticks;
            GetTimeParts(datetimeLiteralValue, datetimeParts, 3, out hour, out minute, out second, out ticks); 

            Debug.Assert(year >= 1 && year <= 9999);
            Debug.Assert(month >= 1 && month <= 12);
            Debug.Assert(day >= 1 && day <= 31); 
            Debug.Assert(hour >= 0 && hour <= 24);
            Debug.Assert(minute >= 0 && minute <= 59); 
            Debug.Assert(second >= 0 && second <= 59); 
            Debug.Assert(ticks >= 0 && ticks <= 9999999);
            DateTime dateTime = new DateTime(year, month, day, hour, minute, second, 0); 
            dateTime = dateTime.AddTicks(ticks);
            return dateTime;
        }
 
        private static DateTimeOffset ConvertDateTimeOffsetLiteralValue(ErrorContext errCtx, string datetimeLiteralValue)
        { 
            string[] datetimeParts = datetimeLiteralValue.Split(_datetimeOffsetSeparators, StringSplitOptions.RemoveEmptyEntries); 

            Debug.Assert(datetimeParts.Length >= 7, "datetime literal value must have at least 7 parts"); 

            int year;
            int month;
            int day; 
            GetDateParts(datetimeLiteralValue, datetimeParts, out year, out month, out day);
            int hour; 
            int minute; 
            int second;
            int ticks; 
            //Copy the time parts into a different array since the last two parts will be handled in this method.
            string[] timeParts = new String[datetimeParts.Length - 2];
            Array.Copy(datetimeParts, timeParts, datetimeParts.Length - 2);
            GetTimeParts(datetimeLiteralValue, timeParts, 3, out hour, out minute, out second, out ticks); 

            Debug.Assert(year >= 1 && year <= 9999); 
            Debug.Assert(month >= 1 && month <= 12); 
            Debug.Assert(day >= 1 && day <= 31);
            Debug.Assert(hour >= 0 && hour <= 24); 
            Debug.Assert(minute >= 0 && minute <= 59);
            Debug.Assert(second >= 0 && second <= 59);
            Debug.Assert(ticks >= 0 && ticks <= 9999999);
            int offsetHours = Int32.Parse(datetimeParts[datetimeParts.Length - 2], NumberStyles.Integer, CultureInfo.InvariantCulture); 
            int offsetMinutes = Int32.Parse(datetimeParts[datetimeParts.Length - 1], NumberStyles.Integer, CultureInfo.InvariantCulture);
            TimeSpan offsetTimeSpan = new TimeSpan(offsetHours, offsetMinutes, 0); 
 
            //If DateTimeOffset had a negative offset, we should negate the timespan
            if(datetimeLiteralValue.IndexOf('+') == -1) 
            {
                offsetTimeSpan = offsetTimeSpan.Negate();
            }
            DateTime dateTime = new DateTime(year, month, day, hour, minute, second, 0); 
            dateTime = dateTime.AddTicks(ticks);
 
            try 
            {
                return new DateTimeOffset(dateTime, offsetTimeSpan); 
            }
            catch (ArgumentOutOfRangeException e)
            {
                throw EntityUtil.EntitySqlError(errCtx, System.Data.Entity.Strings.InvalidDateTimeOffsetLiteral(datetimeLiteralValue), e); 
            }
        } 
 

 
        /// 
        /// converts time literal value
        /// 
        ///  
        /// 
        ///  
        private static TimeSpan ConvertTimeLiteralValue(ErrorContext errCtx, string datetimeLiteralValue) 
        {
            string[] datetimeParts = datetimeLiteralValue.Split(_datetimeSeparators, StringSplitOptions.RemoveEmptyEntries); 

            Debug.Assert(datetimeParts.Length >= 2, "time literal value must have at least 2 parts");

            int hour; 
            int minute;
            int second; 
            int ticks; 
            GetTimeParts(datetimeLiteralValue, datetimeParts, 0, out hour, out minute, out second, out ticks);
 
            Debug.Assert(hour >= 0 && hour <= 24);
            Debug.Assert(minute >= 0 && minute <= 59);
            Debug.Assert(second >= 0 && second <= 59);
            Debug.Assert(ticks >= 0 && ticks <= 9999999); 
            TimeSpan ts = new TimeSpan(hour, minute, second);
            ts = ts.Add(new TimeSpan(ticks)); 
            return ts; 
        }
 
        private static void GetTimeParts(string datetimeLiteralValue, string[] datetimeParts, int timePartStartIndex, out int hour, out int minute, out int second, out int ticks)
        {
            hour = Int32.Parse(datetimeParts[timePartStartIndex], NumberStyles.Integer, CultureInfo.InvariantCulture);
            if (hour > 23) 
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidHour(datetimeParts[timePartStartIndex], datetimeLiteralValue)); 
            } 
            minute = Int32.Parse(datetimeParts[++timePartStartIndex], NumberStyles.Integer, CultureInfo.InvariantCulture);
            if (minute > 59) 
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidMinute(datetimeParts[timePartStartIndex], datetimeLiteralValue));
            }
            second = 0; 
            ticks = 0;
            timePartStartIndex++; 
            if (datetimeParts.Length > timePartStartIndex) 
            {
                second = Int32.Parse(datetimeParts[timePartStartIndex], NumberStyles.Integer, CultureInfo.InvariantCulture); 
                if (second > 59)
                {
                    throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidSecond(datetimeParts[timePartStartIndex], datetimeLiteralValue));
                } 
                timePartStartIndex++;
                if (datetimeParts.Length > timePartStartIndex) 
                { 
                    //We need fractional time part to be seven digits
                    string ticksString = datetimeParts[timePartStartIndex].PadRight(7, '0'); 
                    ticks = Int32.Parse(ticksString , NumberStyles.Integer, CultureInfo.InvariantCulture);
                }

            } 
        }
 
        private static void GetDateParts(string datetimeLiteralValue, string[] datetimeParts, out int year, out int month, out int day) 
        {
            year = Int32.Parse(datetimeParts[0], NumberStyles.Integer, CultureInfo.InvariantCulture); 
            if (year < 1 || year > 9999)
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidYear(datetimeParts[0], datetimeLiteralValue));
            } 
            month = Int32.Parse(datetimeParts[1], NumberStyles.Integer, CultureInfo.InvariantCulture);
            if (month < 1 || month > 12) 
            { 
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidMonth(datetimeParts[1], datetimeLiteralValue));
            } 
            day = Int32.Parse(datetimeParts[2], NumberStyles.Integer, CultureInfo.InvariantCulture);
            if (day < 1)
            {
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidDay(datetimeParts[2], datetimeLiteralValue)); 
            }
            if (day > DateTime.DaysInMonth(year, month)) 
            { 
                throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.InvalidDayInMonth(datetimeParts[2], datetimeParts[1], datetimeLiteralValue));
            } 
        }

        /// 
        /// converts guid literal value 
        /// 
        ///  
        ///  
        /// 
        private static Guid ConvertGuidLiteralValue( ErrorContext errCtx, string guidLiteralValue ) 
        {
            return new Guid(guidLiteralValue);
        }
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK