OracleDateTime.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / DataOracleClient / System / Data / OracleClient / OracleDateTime.cs / 1 / OracleDateTime.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Data.OracleClient 
{
    using System; 
    using System.Data.SqlTypes;
    using System.Data.Common;
    using System.Diagnostics;
    using System.Globalization; 
    using System.Runtime.InteropServices;
    using System.Text; 
 
    //---------------------------------------------------------------------
    // OracleDateTime 
    //
    //  This class implements support for Oracle's DATE internal data
    //  type, which is really contains both Date and Time values (but
    //  doesn't contain fractional seconds). 
    //
    //  It also implements support for the Oracle 9i 'TIMESTAMP', 
    //  'TIMESTAMP WITH LOCAL TIME ZONE' and 'TIMESTAMP WITH TIME ZONE' 
    //  internal data types.
    // 
    [StructLayout(LayoutKind.Sequential, Pack=1)]
    public struct OracleDateTime : IComparable, INullable {

        private const int MaxOracleFSecPrecision = 9; 

        private byte[]   _value;    // null == value is null; length(7) == date; length(11) == timestamp; length(13) == timestampwithtz 
 
        private const byte x_DATE_Length                    = 7;
        private const byte x_TIMESTAMP_Length               = 11; 
        private const byte x_TIMESTAMP_WITH_TIMEZONE_Length = 13;

        private const int  FractionalSecondsPerTick = 100;
 
        public static readonly OracleDateTime MaxValue = new OracleDateTime(DateTime.MaxValue);
 
        public static readonly OracleDateTime MinValue = new OracleDateTime(DateTime.MinValue); 

        public static readonly OracleDateTime Null = new OracleDateTime(true); 


        // Construct from nothing -- the value will be null
        private OracleDateTime(bool isNull) { 
            _value = null;
        } 
 
        // Construct from System.DateTime type
        public OracleDateTime (DateTime dt) { 
            _value = new byte[x_TIMESTAMP_Length];
            Pack (_value, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, (int)(dt.Ticks % TimeSpan.TicksPerSecond) * FractionalSecondsPerTick);
        }
 
        public OracleDateTime (Int64 ticks) {
            _value = new byte[x_TIMESTAMP_Length]; 
            DateTime    dt = new DateTime(ticks); 
            Pack (_value, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, (int)(dt.Ticks % TimeSpan.TicksPerSecond) * FractionalSecondsPerTick);
        } 

        public OracleDateTime (int year, int month, int day)
                : this (year, month, day, 0, 0, 0, 0) {}
 
        public OracleDateTime (int year, int month, int day, Calendar calendar)
                : this (year, month, day, 0, 0, 0, 0, calendar) {} 
 
        public OracleDateTime (int year, int month, int day, int hour, int minute, int second)
                : this (year, month, day, hour, minute, second, 0) {} 

        public OracleDateTime (int year, int month, int day, int hour, int minute, int second, Calendar calendar)
                : this (year, month, day, hour, minute, second, 0, calendar) {}
 
        public OracleDateTime (int year, int month, int day, int hour, int minute, int second, int millisecond) {
            _value = new byte[x_TIMESTAMP_Length]; 
            // WebData 109872 - we really need to validate this value, because 
            // Oracle doesn't.  If the year is negative, we just don't bother,
            // because DateTime won't support it. 
            new DateTime((year < 0) ? 0 : year, month, (year < 0) ? 1 : day, hour, minute, second, millisecond);
            Pack (_value, year, month, day, hour, minute, second, (int)(millisecond * TimeSpan.TicksPerMillisecond) * FractionalSecondsPerTick);
        }
 
        public OracleDateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar) {
            _value = new byte[x_TIMESTAMP_Length]; 
            DateTime    dt = new DateTime(year, month, day, hour, minute, second, millisecond, calendar); 
            Pack (_value, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, (int)(dt.Ticks % TimeSpan.TicksPerSecond) * FractionalSecondsPerTick);
        } 

        // Copy constructor
        public OracleDateTime (OracleDateTime from) {
            _value = new byte[from._value.Length]; 
            from._value.CopyTo(_value, 0);
        } 
 
        // (internal) construct OracleDateTime:
        // * from parameter binding buffer for DATE type only 
        // * from row fetch buffer: DATE and INT_TIMESTAMP* types
        internal OracleDateTime(NativeBuffer buffer, int valueOffset, int lengthOffset, MetaType metaType, OracleConnection connection) {
            _value = GetBytesFromBuffer(buffer, valueOffset, lengthOffset, metaType, connection);
        } 

        // (internal) construct from Oracle descriptor for INT_TIMESTAMP types for parameter binding only 
        internal OracleDateTime(OciDateTimeDescriptor dateTimeDescriptor, MetaType metaType, OracleConnection connection) { 
            _value = GetBytesFromDescriptor(dateTimeDescriptor, metaType, connection);
        } 

        static private void Pack (byte[] dateval, int year, int month, int day, int hour, int minute, int second, int fsecs) {
            // DEVNOTE: undoubtedly, this is Intel byte order specific, but how
            //          do I verify what Oracle needs on a non Intel machine? 

            dateval[0] = (byte)((year / 100) + 100); 
            dateval[1] = (byte)((year % 100) + 100); 
            dateval[2] = (byte)(month);
            dateval[3] = (byte)(day); 
            dateval[4] = (byte)(hour   + 1);
            dateval[5] = (byte)(minute + 1);
            dateval[6] = (byte)(second + 1);
            dateval[7] = (byte)((fsecs >> 24)); 
            dateval[8] = (byte)((fsecs >> 16) & 0xff);
            dateval[9] = (byte)((fsecs >>  8) & 0xff); 
            dateval[10]= (byte)(fsecs & 0xff); 
        }
 
        static private int Unpack (byte[] dateval, out int year, out int month, out int day, out int hour, out int minute, out int second, out int fsec) {
            int tzh, tzm;

            // DEVNOTE: undoubtedly, this is Intel byte order specific, but how 
            //          do I verify what Oracle needs on a non Intel machine?
 
            year    =(((int)dateval[0] - 100) * 100) + ((int)dateval[1] - 100); 
            month   = (int)dateval[2];
            day     = (int)dateval[3]; 
            hour    = (int)dateval[4] - 1;
            minute  = (int)dateval[5] - 1;
            second  = (int)dateval[6] - 1;
 
            if (x_DATE_Length == dateval.Length) {
                fsec = tzh = tzm = 0; 
            } 
            else {
                fsec = (int)dateval[7] << 24 
                     | (int)dateval[8] << 16
                     | (int)dateval[9] <<  8
                     | (int)dateval[10]
                     ; 
                if (x_TIMESTAMP_Length == dateval.Length) {
                    tzh = tzm = 0; 
                } 
                else {
                    tzh = dateval[11] - 20; 
                    tzm = dateval[12] - 60;
                }
            }
 
            if (x_TIMESTAMP_WITH_TIMEZONE_Length == dateval.Length) {
                // DEVNOTE: I'm not really all that excited about the fact that I'm 
                //          constructing a System.DateTime value to unpack, but if you 
                //          look at what is involved in adjusting the value for the
                //          timezone, it turns into the same thing that DateTime does. 

                DateTime utcValue = (new DateTime(year, month, day, hour, minute, second))
                                  + (new TimeSpan(tzh, tzm, 0));
 
                year    = utcValue.Year;
                month   = utcValue.Month; 
                day     = utcValue.Day; 
                hour    = utcValue.Hour;
                minute  = utcValue.Minute; 
                // Seconds and Fractional Seconds aren't affected by time zones (yet!)
            }
            return dateval.Length;
        } 

 
        public bool IsNull { 
            get {
                return (null == _value); 
            }
        }

        public DateTime Value { 
            get {
                if (IsNull) { 
                    throw ADP.DataIsNull(); 
                }
                DateTime result = ToDateTime(_value); 
                return result;
            }
        }
 
        public int Year {
            get { 
                if (IsNull) { 
                    throw ADP.DataIsNull();
                } 
                int year, month, day, hour, minute, second, fsec;

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec);
                return year; 
            }
        } 
 
        public int Month {
            get { 
                if (IsNull) {
                    throw ADP.DataIsNull();
                }
                int year, month, day, hour, minute, second, fsec; 

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec); 
                return month; 
            }
        } 

        public int Day {
            get {
                if (IsNull) { 
                    throw ADP.DataIsNull();
                } 
                int year, month, day, hour, minute, second, fsec; 

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec); 
                return day;
            }
        }
 
        public int Hour {
            get { 
                if (IsNull) { 
                    throw ADP.DataIsNull();
                } 
                int year, month, day, hour, minute, second, fsec;

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec);
                return hour; 
            }
        } 
 
        public int Minute {
            get { 
                if (IsNull) {
                    throw ADP.DataIsNull();
                }
                int year, month, day, hour, minute, second, fsec; 

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec); 
                return minute; 
            }
        } 

        public int Second {
            get {
                if (IsNull) { 
                    throw ADP.DataIsNull();
                } 
                int year, month, day, hour, minute, second, fsec; 

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec); 
                return second;
            }
        }
 
        public int Millisecond {
            get { 
                if (IsNull) { 
                    throw ADP.DataIsNull();
                } 
                int year, month, day, hour, minute, second, fsec;

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec);
 
                int milliseconds = (int)((fsec / FractionalSecondsPerTick) /  TimeSpan.TicksPerMillisecond);
                return milliseconds; 
            } 
        }
 

        public int CompareTo( object obj ) {
            if (obj.GetType() == typeof(OracleDateTime)) {
                OracleDateTime odt = (OracleDateTime)obj; 

                // If both values are Null, consider them equal. 
                // Otherwise, Null is less than anything. 
                if (IsNull) {
                    return odt.IsNull ? 0  : -1; 
                }
                if (odt.IsNull) {
                    return 1;
                } 
                // Neither value is null, do the comparison, but take the Timezone into account.
 
                int year1, month1, day1, hour1, minute1, second1, fsec1; 
                int year2, month2, day2, hour2, minute2, second2, fsec2;
 
                Unpack( _value,     out year1, out month1, out day1, out hour1, out minute1, out second1, out fsec1);
                Unpack( odt._value, out year2, out month2, out day2, out hour2, out minute2, out second2, out fsec2);

                int delta; 

                delta = (year1 - year2);        if (0 != delta) return delta; 
                delta = (month1 - month2);      if (0 != delta) return delta; 
                delta = (day1 - day2);          if (0 != delta) return delta;
                delta = (hour1 - hour2);        if (0 != delta) return delta; 
                delta = (minute1 - minute2);    if (0 != delta) return delta;
                delta = (second1 - second2);    if (0 != delta) return delta;
                delta = (fsec1 - fsec2);        if (0 != delta) return delta;
                return 0; 
            }
 
            throw ADP.WrongType(obj.GetType(), typeof(OracleDateTime)); 
        }
 
        public override bool Equals(object value) {
            if (value is OracleDateTime) {
                return (this == (OracleDateTime)value).Value;
            } 
            else {
                return false; 
            } 
        }
 
        // returns the raw data bytes from the OCI's OracleDateTime descriptor buffer for INT_TIMESTAMP* types,
        // taking the binding type into account and adjusting it for the server time zones, as appropriate.
        static internal byte[] GetBytesFromDescriptor(OciDateTimeDescriptor dateTimeDescriptor, MetaType metaType, OracleConnection connection) {
 
            // allocate the result buffer
 
            uint ociBytes; 
            OCI.DATATYPE ociType = metaType.OciType;
 
            switch (ociType) {

                case OCI.DATATYPE.INT_TIMESTAMP:
                    ociBytes = x_TIMESTAMP_Length; 
                    break;
 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ: 
                    ociBytes = x_TIMESTAMP_WITH_TIMEZONE_Length;
                    break; 

                default:
                    Debug.Assert(OCI.DATATYPE.INT_TIMESTAMP_TZ == ociType, "unrecognized type");
                    ociBytes = x_TIMESTAMP_WITH_TIMEZONE_Length; 
                    break;
            } 
 
            byte[] result = new byte[ociBytes];
            uint templen = (uint)ociBytes; 
            OciIntervalDescriptor tz = new OciIntervalDescriptor(connection.EnvironmentHandle);

            // read the byte array from descriptor
            int rc = UnsafeNativeMethods.OCIDateTimeToArray( 
                connection.EnvironmentHandle,
                connection.ErrorHandle, 
                dateTimeDescriptor, 
                tz, // used for LTZ only - to be compatible with 2.0 RTM, we do not set the offset timezone to client's timezone, so it is not used in calculations
                result, 
                ref templen,
                MaxOracleFSecPrecision // use the max fsec precision
                );
 
            if (0 != rc) {
                connection.CheckError(connection.ErrorHandle, rc); 
            } 

            // fill timezone, depending on the type 
            if (OCI.DATATYPE.INT_TIMESTAMP_LTZ == ociType) {
                // user connection to get the server's timezone

                TimeSpan tzadjust = connection.ServerTimeZoneAdjustmentToUTC; 
                result[11] = (byte)(tzadjust.Hours + 20);
                result[12] = (byte)(tzadjust.Minutes + 60); 
            } 
            else if (OCI.DATATYPE.INT_TIMESTAMP_TZ == ociType) {
                // use OCI API to retrieve the timezone information from the descriptor itself 

                sbyte tzHour;
                sbyte tzMin;
 
                rc = UnsafeNativeMethods.OCIDateTimeGetTimeZoneOffset(
                                                    connection.EnvironmentHandle, 
                                                    connection.ErrorHandle, 
                                                    dateTimeDescriptor,
                                                    out tzHour, 
                                                    out tzMin);
                if (0 != rc) {
                    connection.CheckError(connection.ErrorHandle, rc);
                } 

                result[11] = (byte)(tzHour + 20); 
                result[12] = (byte)(tzMin + 60); 
            }
 
            return result;
        }

        static internal byte[] GetBytesFromBuffer (NativeBuffer buffer, int valueOffset, int lengthOffset, MetaType metaType, OracleConnection connection) { 
            // Static method to return the raw data bytes from the row/parameter
            // buffer, taking the binding type into account and adjusting it for 
            // the server time zones, as appropriate. 

            uint ociBytes; 
            OCI.DATATYPE ociType = metaType.OciType;

            short length = buffer.ReadInt16(lengthOffset);
 
            switch (ociType) {
                case OCI.DATATYPE.DATE: 
                    ociBytes = x_DATE_Length; 
                    break;
 
                case OCI.DATATYPE.INT_TIMESTAMP:
                    ociBytes = x_TIMESTAMP_Length;
                    break;
 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                    ociBytes = x_TIMESTAMP_WITH_TIMEZONE_Length; 
                    break; 

                default: 
                    Debug.Assert(OCI.DATATYPE.INT_TIMESTAMP_TZ == ociType, "unrecognized type");
                    ociBytes = x_TIMESTAMP_WITH_TIMEZONE_Length;
                    break;
            } 

            byte[] result = new byte[ociBytes]; // NOTE: will zero the data 
            buffer.ReadBytes(valueOffset, result, 0, length); 

            if (OCI.DATATYPE.INT_TIMESTAMP_LTZ == ociType) { 
                TimeSpan tzadjust = connection.ServerTimeZoneAdjustmentToUTC;
                result[11] = (byte)(tzadjust.Hours + 20);
                result[12] = (byte)(tzadjust.Minutes + 60);
            } 
            else if (OCI.DATATYPE.INT_TIMESTAMP_TZ == ociType && 0x80 < result[11]) {
                // WebData 114105 - as it happens, Oracle has two formats for 
                // TIMESTAMP WITH TIME ZONE -- one is the format that includes 
                // the time zone offset hours and minutes in the value, the other
                // includes some funky value that they translate into the name 
                // of the time zone when they format it.  The first format is
                // relatively straight-forward, the latter is unintelligable, but
                // it does seem to be valid.  Since Oracle knows what to do with
                // those, we simply hand it to Oracle and ask them to convert it 
                // to something we can use.
                // 
                // NOTE, that Oracle requires that we give them an interval for 
                //       conversion from TIMESTAMP_LTZ, but we have already pre-
                //       qualified that we don't have one of those, so we simply 
                //       create an empty interval instead and pass it on.
                int rc;
                OciIntervalDescriptor tz = new OciIntervalDescriptor(connection.EnvironmentHandle);
                OciDateTimeDescriptor ts = new OciDateTimeDescriptor(connection.EnvironmentHandle, OCI.HTYPE.OCI_DTYPE_TIMESTAMP_TZ); 
                sbyte tzHour;
                sbyte tzMin; 
 
                rc = UnsafeNativeMethods.OCIDateTimeFromArray(
                                                    connection.EnvironmentHandle, 
                                                    connection.ErrorHandle,
                                                    result,
                                                    ociBytes,
                                                    (byte)OCI.DATATYPE.TIMESTAMP_TZ, 
                                                    ts,
                                                    tz, 
                                                    0); 
                if (0 != rc) {
                    connection.CheckError(connection.ErrorHandle, rc); 
                }
                rc = UnsafeNativeMethods.OCIDateTimeGetTimeZoneOffset(
                                                    connection.EnvironmentHandle,
                                                    connection.ErrorHandle, 
                                                    ts,
                                                    out tzHour, 
                                                    out tzMin); 
                if (0 != rc) {
                    connection.CheckError(connection.ErrorHandle, rc); 
                }
                result[11] = (byte)(tzHour + 20);
                result[12] = (byte)(tzMin + 60);
            } 

            return result; 
        } 

        public override int GetHashCode() { 
            int retval = IsNull ? 0 : _value.GetHashCode();
            return retval;
        }
 
        // used to deserialize DATE and INT_TIMESTAMP types from native buffer and convert it to DateTime
        static internal DateTime MarshalToDateTime(NativeBuffer buffer, int valueOffset, int lengthOffset, MetaType metaType, OracleConnection connection) { 
            byte[] rawValue = GetBytesFromBuffer(buffer, valueOffset, lengthOffset, metaType, connection); 
            DateTime result = ToDateTime(rawValue);
            return result; 
        }

        // used to serialize DATE type only into native buffer for parameter binding
        static internal int MarshalDateToNative(object value, NativeBuffer buffer, int offset, OCI.DATATYPE ociType, OracleConnection connection) { 
            byte[] from;
 
            if (value is OracleDateTime) { 
                from = ((OracleDateTime)value)._value;
            } 
            else {
                DateTime dt = (DateTime)value;
                from = new byte[x_TIMESTAMP_Length];  // Pack requires at least x_TIMESTAMP_Length
                // pack the date and time only, fsec is not used in DATE type 
                Pack(from, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, 0);
            } 
 
            int ociBytes = x_DATE_Length;
 
            buffer.WriteBytes(offset, from, 0, ociBytes);
            return ociBytes;
        }
 
        // used to deserialize INT_TIMESTAMP* values from OCI's OracleDateTime descriptor and construct CLR's DateTime for them
        static internal DateTime MarshalTimestampToDateTime(OciDateTimeDescriptor dateTimeDescriptor, MetaType metaType, OracleConnection connection) { 
            byte[] rawValue = GetBytesFromDescriptor(dateTimeDescriptor, metaType, connection); 
            DateTime result = ToDateTime(rawValue);
            return result; 
        }

        // creates empty OCI's OracleDateTime descriptor to be used for INT_TIMESTAMP* values serialization
        // caller should ensure ociType validity before calling this method 
        static internal OciDateTimeDescriptor CreateEmptyDescriptor(OCI.DATATYPE ociType, OracleConnection connection) {
            // convert DATATYPE to HTYPE 
            OCI.HTYPE dbType; 
            switch (ociType) {
                case OCI.DATATYPE.INT_TIMESTAMP: 
                    dbType = OCI.HTYPE.OCI_DTYPE_TIMESTAMP;
                    break;

                case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                    dbType = OCI.HTYPE.OCI_DTYPE_TIMESTAMP_TZ;
                    break; 
 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                default: 
                    Debug.Assert(OCI.DATATYPE.INT_TIMESTAMP_LTZ == ociType, "unrecognized type");
                    dbType = OCI.HTYPE.OCI_DTYPE_TIMESTAMP_LTZ;
                    break;
            } 

            OciDateTimeDescriptor descriptor = new OciDateTimeDescriptor(connection.EnvironmentHandle, dbType); 
            return descriptor; 
        }
 
        // creates OCI's OracleDateTime descriptor and fills it with given DateTime or OracleDateTime value
        // this method is used with INT_TIMESTAMP* values only, caller should ensure ociType validity before calling it
        static internal OciDateTimeDescriptor CreateDescriptor(OCI.DATATYPE ociType, OracleConnection connection, object value) {
            // this array will be used as an input to OCIDateTimeFromArray to construct the OCI Datetime descriptor 
            byte[] from;
            if (value is OracleDateTime) { 
                from = ((OracleDateTime)value)._value; 
            }
            else { 
                // this will raise cast exception if value is neither OracleDateTime nor DateTime (backward compatibility)
                DateTime dt = (DateTime)value;
                OracleDateTime temp = new OracleDateTime(dt);
                from = temp._value; 
            }
 
            OCI.DATATYPE dbType; 
            switch (ociType) {
                case OCI.DATATYPE.INT_TIMESTAMP: 
                    dbType = OCI.DATATYPE.TIMESTAMP;
                    break;

                case OCI.DATATYPE.INT_TIMESTAMP_LTZ: 
                    dbType = OCI.DATATYPE.TIMESTAMP_LTZ;
                    break; 
 
                case OCI.DATATYPE.INT_TIMESTAMP_TZ:
                default: 
                    Debug.Assert(OCI.DATATYPE.INT_TIMESTAMP_TZ == ociType, "unrecognized type");

                    dbType = OCI.DATATYPE.TIMESTAMP_TZ;
 
                    // for TIMESTAMP with time zone: we have to specify explicitly the timezone to preserve full backward compatibility with 2.0 RTM
                    // if the input byte array does not have time zone information in it, create a new byte array and explicitly initialize the time zone 
                    // from the Oracle's database time zone (dbtimezone). 
                    TimeSpan tzadjust = connection.ServerTimeZoneAdjustmentToUTC;
                    if (from.Length < x_TIMESTAMP_WITH_TIMEZONE_Length) { 
                        byte[] valueWithTZ = new byte[x_TIMESTAMP_WITH_TIMEZONE_Length];
                        Buffer.BlockCopy(from, 0, valueWithTZ, 0, from.Length);
                        from = valueWithTZ;
 
                        // set the timezone into array
                        from[11] = (byte)(20 + tzadjust.Hours); 
                        from[12] = (byte)(60 + tzadjust.Minutes); 
                    }
 
                    break;
            }

            // create empty descriptor 
            OciDateTimeDescriptor descriptor = CreateEmptyDescriptor(ociType, connection);
            OciIntervalDescriptor tz = new OciIntervalDescriptor(connection.EnvironmentHandle); 
 
            // NOTE: VSTS 225565: we've tried to use OCIDateTimeConstruct API, but it looks like that API ignores the timezone argument for TIMESTAMP_TZ type.
            // Using OCIDateTimeFromArray we can set the timezone information into the descriptor 
            int rc = UnsafeNativeMethods.OCIDateTimeFromArray(
                connection.EnvironmentHandle,
                connection.ErrorHandle,
                from, 
                (uint)from.Length,
                (byte)dbType, 
                descriptor, 
                tz, // used for LTZ only - to be compatible with 2.0 RTM, we do not set the offset timezone to client's timezone, so it is not used in calculations
                MaxOracleFSecPrecision // use the max fsec precision 
                );

            if (0 != rc) {
                connection.CheckError(connection.ErrorHandle, rc); 
            }
 
            return descriptor; 
        }
 
        internal bool HasTimeZoneInfo {
            get {
                return _value != null && _value.Length >= x_TIMESTAMP_WITH_TIMEZONE_Length;
            } 
        }
 
        internal bool HasTimeInfo { 
            get {
                return _value != null && _value.Length >= x_TIMESTAMP_Length; 
            }
        }

        public static OracleDateTime Parse(string s) { 
            // Rather than figure out which formats, etc, we just simplify our
            // life and convert this to a DateTime, which we can use to build 
            // the real Oracle Date from. 
            DateTime datetime = DateTime.Parse(s, null);
            return new OracleDateTime(datetime); 
        }

        static private DateTime ToDateTime(byte[] rawValue) {
            int year, month, day, hour, minute, second, fsec; 
            int length = Unpack( rawValue, out year, out month, out day, out hour, out minute, out second, out fsec);
 
            DateTime result = new DateTime(year, month, day, hour, minute, second); 

            if (length > x_DATE_Length && fsec > FractionalSecondsPerTick) { 
                // DEVNOTE: Yes, there's a mismatch in the precision between Oracle,
                //          (which has 9 digits) and System.DateTime (which has 7
                //          digits);  All the other providers truncate the precision,
                //          so we do as well. 
                result = result.AddTicks((long)fsec / FractionalSecondsPerTick);
            } 
            return result; 
        }
 
        public override string ToString() {
            if (IsNull) {
                return ADP.NullString;
            } 
            string retval = Value.ToString((IFormatProvider)null);
            return retval; 
        } 

        public static OracleBoolean Equals(OracleDateTime x, OracleDateTime y) { 
            // Alternative method for operator ==
            return (x == y);
        }
 
        public static OracleBoolean GreaterThan(OracleDateTime x, OracleDateTime y) {
            // Alternative method for operator > 
            return (x > y); 
        }
 
        public static OracleBoolean GreaterThanOrEqual(OracleDateTime x, OracleDateTime y) {
            // Alternative method for operator >=
            return (x >= y);
        } 

        public static OracleBoolean LessThan(OracleDateTime x, OracleDateTime y) { 
            // Alternative method for operator < 
            return (x < y);
        } 

        public static OracleBoolean LessThanOrEqual(OracleDateTime x, OracleDateTime y) {
            // Alternative method for operator <=
            return (x <= y); 
        }
 
        public static OracleBoolean NotEquals(OracleDateTime x, OracleDateTime y) { 
            // Alternative method for operator !=
            return (x != y); 
        }

        public static explicit operator DateTime(OracleDateTime x) {
            if (x.IsNull) { 
                throw ADP.DataIsNull();
            } 
            return x.Value; 
        }
 
        public static explicit operator OracleDateTime(string x) {
            return OracleDateTime.Parse(x);
        }
 

        public static OracleBoolean operator==  (OracleDateTime x, OracleDateTime y) { 
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) == 0); 
        }
 
        public static OracleBoolean operator>   (OracleDateTime x, OracleDateTime y) {
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) > 0);
        }
 
        public static OracleBoolean operator>=  (OracleDateTime x, OracleDateTime y) {
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) >= 0); 
        } 

        public static OracleBoolean operator<   (OracleDateTime x, OracleDateTime y) { 
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) < 0);
        }

        public static OracleBoolean operator<=  (OracleDateTime x, OracleDateTime y) { 
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) <= 0);
        } 
 
        public static OracleBoolean operator!=  (OracleDateTime x, OracleDateTime y) {
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) != 0); 
        }

    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Data.OracleClient 
{
    using System; 
    using System.Data.SqlTypes;
    using System.Data.Common;
    using System.Diagnostics;
    using System.Globalization; 
    using System.Runtime.InteropServices;
    using System.Text; 
 
    //---------------------------------------------------------------------
    // OracleDateTime 
    //
    //  This class implements support for Oracle's DATE internal data
    //  type, which is really contains both Date and Time values (but
    //  doesn't contain fractional seconds). 
    //
    //  It also implements support for the Oracle 9i 'TIMESTAMP', 
    //  'TIMESTAMP WITH LOCAL TIME ZONE' and 'TIMESTAMP WITH TIME ZONE' 
    //  internal data types.
    // 
    [StructLayout(LayoutKind.Sequential, Pack=1)]
    public struct OracleDateTime : IComparable, INullable {

        private const int MaxOracleFSecPrecision = 9; 

        private byte[]   _value;    // null == value is null; length(7) == date; length(11) == timestamp; length(13) == timestampwithtz 
 
        private const byte x_DATE_Length                    = 7;
        private const byte x_TIMESTAMP_Length               = 11; 
        private const byte x_TIMESTAMP_WITH_TIMEZONE_Length = 13;

        private const int  FractionalSecondsPerTick = 100;
 
        public static readonly OracleDateTime MaxValue = new OracleDateTime(DateTime.MaxValue);
 
        public static readonly OracleDateTime MinValue = new OracleDateTime(DateTime.MinValue); 

        public static readonly OracleDateTime Null = new OracleDateTime(true); 


        // Construct from nothing -- the value will be null
        private OracleDateTime(bool isNull) { 
            _value = null;
        } 
 
        // Construct from System.DateTime type
        public OracleDateTime (DateTime dt) { 
            _value = new byte[x_TIMESTAMP_Length];
            Pack (_value, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, (int)(dt.Ticks % TimeSpan.TicksPerSecond) * FractionalSecondsPerTick);
        }
 
        public OracleDateTime (Int64 ticks) {
            _value = new byte[x_TIMESTAMP_Length]; 
            DateTime    dt = new DateTime(ticks); 
            Pack (_value, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, (int)(dt.Ticks % TimeSpan.TicksPerSecond) * FractionalSecondsPerTick);
        } 

        public OracleDateTime (int year, int month, int day)
                : this (year, month, day, 0, 0, 0, 0) {}
 
        public OracleDateTime (int year, int month, int day, Calendar calendar)
                : this (year, month, day, 0, 0, 0, 0, calendar) {} 
 
        public OracleDateTime (int year, int month, int day, int hour, int minute, int second)
                : this (year, month, day, hour, minute, second, 0) {} 

        public OracleDateTime (int year, int month, int day, int hour, int minute, int second, Calendar calendar)
                : this (year, month, day, hour, minute, second, 0, calendar) {}
 
        public OracleDateTime (int year, int month, int day, int hour, int minute, int second, int millisecond) {
            _value = new byte[x_TIMESTAMP_Length]; 
            // WebData 109872 - we really need to validate this value, because 
            // Oracle doesn't.  If the year is negative, we just don't bother,
            // because DateTime won't support it. 
            new DateTime((year < 0) ? 0 : year, month, (year < 0) ? 1 : day, hour, minute, second, millisecond);
            Pack (_value, year, month, day, hour, minute, second, (int)(millisecond * TimeSpan.TicksPerMillisecond) * FractionalSecondsPerTick);
        }
 
        public OracleDateTime (int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar) {
            _value = new byte[x_TIMESTAMP_Length]; 
            DateTime    dt = new DateTime(year, month, day, hour, minute, second, millisecond, calendar); 
            Pack (_value, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, (int)(dt.Ticks % TimeSpan.TicksPerSecond) * FractionalSecondsPerTick);
        } 

        // Copy constructor
        public OracleDateTime (OracleDateTime from) {
            _value = new byte[from._value.Length]; 
            from._value.CopyTo(_value, 0);
        } 
 
        // (internal) construct OracleDateTime:
        // * from parameter binding buffer for DATE type only 
        // * from row fetch buffer: DATE and INT_TIMESTAMP* types
        internal OracleDateTime(NativeBuffer buffer, int valueOffset, int lengthOffset, MetaType metaType, OracleConnection connection) {
            _value = GetBytesFromBuffer(buffer, valueOffset, lengthOffset, metaType, connection);
        } 

        // (internal) construct from Oracle descriptor for INT_TIMESTAMP types for parameter binding only 
        internal OracleDateTime(OciDateTimeDescriptor dateTimeDescriptor, MetaType metaType, OracleConnection connection) { 
            _value = GetBytesFromDescriptor(dateTimeDescriptor, metaType, connection);
        } 

        static private void Pack (byte[] dateval, int year, int month, int day, int hour, int minute, int second, int fsecs) {
            // DEVNOTE: undoubtedly, this is Intel byte order specific, but how
            //          do I verify what Oracle needs on a non Intel machine? 

            dateval[0] = (byte)((year / 100) + 100); 
            dateval[1] = (byte)((year % 100) + 100); 
            dateval[2] = (byte)(month);
            dateval[3] = (byte)(day); 
            dateval[4] = (byte)(hour   + 1);
            dateval[5] = (byte)(minute + 1);
            dateval[6] = (byte)(second + 1);
            dateval[7] = (byte)((fsecs >> 24)); 
            dateval[8] = (byte)((fsecs >> 16) & 0xff);
            dateval[9] = (byte)((fsecs >>  8) & 0xff); 
            dateval[10]= (byte)(fsecs & 0xff); 
        }
 
        static private int Unpack (byte[] dateval, out int year, out int month, out int day, out int hour, out int minute, out int second, out int fsec) {
            int tzh, tzm;

            // DEVNOTE: undoubtedly, this is Intel byte order specific, but how 
            //          do I verify what Oracle needs on a non Intel machine?
 
            year    =(((int)dateval[0] - 100) * 100) + ((int)dateval[1] - 100); 
            month   = (int)dateval[2];
            day     = (int)dateval[3]; 
            hour    = (int)dateval[4] - 1;
            minute  = (int)dateval[5] - 1;
            second  = (int)dateval[6] - 1;
 
            if (x_DATE_Length == dateval.Length) {
                fsec = tzh = tzm = 0; 
            } 
            else {
                fsec = (int)dateval[7] << 24 
                     | (int)dateval[8] << 16
                     | (int)dateval[9] <<  8
                     | (int)dateval[10]
                     ; 
                if (x_TIMESTAMP_Length == dateval.Length) {
                    tzh = tzm = 0; 
                } 
                else {
                    tzh = dateval[11] - 20; 
                    tzm = dateval[12] - 60;
                }
            }
 
            if (x_TIMESTAMP_WITH_TIMEZONE_Length == dateval.Length) {
                // DEVNOTE: I'm not really all that excited about the fact that I'm 
                //          constructing a System.DateTime value to unpack, but if you 
                //          look at what is involved in adjusting the value for the
                //          timezone, it turns into the same thing that DateTime does. 

                DateTime utcValue = (new DateTime(year, month, day, hour, minute, second))
                                  + (new TimeSpan(tzh, tzm, 0));
 
                year    = utcValue.Year;
                month   = utcValue.Month; 
                day     = utcValue.Day; 
                hour    = utcValue.Hour;
                minute  = utcValue.Minute; 
                // Seconds and Fractional Seconds aren't affected by time zones (yet!)
            }
            return dateval.Length;
        } 

 
        public bool IsNull { 
            get {
                return (null == _value); 
            }
        }

        public DateTime Value { 
            get {
                if (IsNull) { 
                    throw ADP.DataIsNull(); 
                }
                DateTime result = ToDateTime(_value); 
                return result;
            }
        }
 
        public int Year {
            get { 
                if (IsNull) { 
                    throw ADP.DataIsNull();
                } 
                int year, month, day, hour, minute, second, fsec;

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec);
                return year; 
            }
        } 
 
        public int Month {
            get { 
                if (IsNull) {
                    throw ADP.DataIsNull();
                }
                int year, month, day, hour, minute, second, fsec; 

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec); 
                return month; 
            }
        } 

        public int Day {
            get {
                if (IsNull) { 
                    throw ADP.DataIsNull();
                } 
                int year, month, day, hour, minute, second, fsec; 

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec); 
                return day;
            }
        }
 
        public int Hour {
            get { 
                if (IsNull) { 
                    throw ADP.DataIsNull();
                } 
                int year, month, day, hour, minute, second, fsec;

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec);
                return hour; 
            }
        } 
 
        public int Minute {
            get { 
                if (IsNull) {
                    throw ADP.DataIsNull();
                }
                int year, month, day, hour, minute, second, fsec; 

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec); 
                return minute; 
            }
        } 

        public int Second {
            get {
                if (IsNull) { 
                    throw ADP.DataIsNull();
                } 
                int year, month, day, hour, minute, second, fsec; 

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec); 
                return second;
            }
        }
 
        public int Millisecond {
            get { 
                if (IsNull) { 
                    throw ADP.DataIsNull();
                } 
                int year, month, day, hour, minute, second, fsec;

                Unpack( _value, out year, out month, out day, out hour, out minute, out second, out fsec);
 
                int milliseconds = (int)((fsec / FractionalSecondsPerTick) /  TimeSpan.TicksPerMillisecond);
                return milliseconds; 
            } 
        }
 

        public int CompareTo( object obj ) {
            if (obj.GetType() == typeof(OracleDateTime)) {
                OracleDateTime odt = (OracleDateTime)obj; 

                // If both values are Null, consider them equal. 
                // Otherwise, Null is less than anything. 
                if (IsNull) {
                    return odt.IsNull ? 0  : -1; 
                }
                if (odt.IsNull) {
                    return 1;
                } 
                // Neither value is null, do the comparison, but take the Timezone into account.
 
                int year1, month1, day1, hour1, minute1, second1, fsec1; 
                int year2, month2, day2, hour2, minute2, second2, fsec2;
 
                Unpack( _value,     out year1, out month1, out day1, out hour1, out minute1, out second1, out fsec1);
                Unpack( odt._value, out year2, out month2, out day2, out hour2, out minute2, out second2, out fsec2);

                int delta; 

                delta = (year1 - year2);        if (0 != delta) return delta; 
                delta = (month1 - month2);      if (0 != delta) return delta; 
                delta = (day1 - day2);          if (0 != delta) return delta;
                delta = (hour1 - hour2);        if (0 != delta) return delta; 
                delta = (minute1 - minute2);    if (0 != delta) return delta;
                delta = (second1 - second2);    if (0 != delta) return delta;
                delta = (fsec1 - fsec2);        if (0 != delta) return delta;
                return 0; 
            }
 
            throw ADP.WrongType(obj.GetType(), typeof(OracleDateTime)); 
        }
 
        public override bool Equals(object value) {
            if (value is OracleDateTime) {
                return (this == (OracleDateTime)value).Value;
            } 
            else {
                return false; 
            } 
        }
 
        // returns the raw data bytes from the OCI's OracleDateTime descriptor buffer for INT_TIMESTAMP* types,
        // taking the binding type into account and adjusting it for the server time zones, as appropriate.
        static internal byte[] GetBytesFromDescriptor(OciDateTimeDescriptor dateTimeDescriptor, MetaType metaType, OracleConnection connection) {
 
            // allocate the result buffer
 
            uint ociBytes; 
            OCI.DATATYPE ociType = metaType.OciType;
 
            switch (ociType) {

                case OCI.DATATYPE.INT_TIMESTAMP:
                    ociBytes = x_TIMESTAMP_Length; 
                    break;
 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ: 
                    ociBytes = x_TIMESTAMP_WITH_TIMEZONE_Length;
                    break; 

                default:
                    Debug.Assert(OCI.DATATYPE.INT_TIMESTAMP_TZ == ociType, "unrecognized type");
                    ociBytes = x_TIMESTAMP_WITH_TIMEZONE_Length; 
                    break;
            } 
 
            byte[] result = new byte[ociBytes];
            uint templen = (uint)ociBytes; 
            OciIntervalDescriptor tz = new OciIntervalDescriptor(connection.EnvironmentHandle);

            // read the byte array from descriptor
            int rc = UnsafeNativeMethods.OCIDateTimeToArray( 
                connection.EnvironmentHandle,
                connection.ErrorHandle, 
                dateTimeDescriptor, 
                tz, // used for LTZ only - to be compatible with 2.0 RTM, we do not set the offset timezone to client's timezone, so it is not used in calculations
                result, 
                ref templen,
                MaxOracleFSecPrecision // use the max fsec precision
                );
 
            if (0 != rc) {
                connection.CheckError(connection.ErrorHandle, rc); 
            } 

            // fill timezone, depending on the type 
            if (OCI.DATATYPE.INT_TIMESTAMP_LTZ == ociType) {
                // user connection to get the server's timezone

                TimeSpan tzadjust = connection.ServerTimeZoneAdjustmentToUTC; 
                result[11] = (byte)(tzadjust.Hours + 20);
                result[12] = (byte)(tzadjust.Minutes + 60); 
            } 
            else if (OCI.DATATYPE.INT_TIMESTAMP_TZ == ociType) {
                // use OCI API to retrieve the timezone information from the descriptor itself 

                sbyte tzHour;
                sbyte tzMin;
 
                rc = UnsafeNativeMethods.OCIDateTimeGetTimeZoneOffset(
                                                    connection.EnvironmentHandle, 
                                                    connection.ErrorHandle, 
                                                    dateTimeDescriptor,
                                                    out tzHour, 
                                                    out tzMin);
                if (0 != rc) {
                    connection.CheckError(connection.ErrorHandle, rc);
                } 

                result[11] = (byte)(tzHour + 20); 
                result[12] = (byte)(tzMin + 60); 
            }
 
            return result;
        }

        static internal byte[] GetBytesFromBuffer (NativeBuffer buffer, int valueOffset, int lengthOffset, MetaType metaType, OracleConnection connection) { 
            // Static method to return the raw data bytes from the row/parameter
            // buffer, taking the binding type into account and adjusting it for 
            // the server time zones, as appropriate. 

            uint ociBytes; 
            OCI.DATATYPE ociType = metaType.OciType;

            short length = buffer.ReadInt16(lengthOffset);
 
            switch (ociType) {
                case OCI.DATATYPE.DATE: 
                    ociBytes = x_DATE_Length; 
                    break;
 
                case OCI.DATATYPE.INT_TIMESTAMP:
                    ociBytes = x_TIMESTAMP_Length;
                    break;
 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                    ociBytes = x_TIMESTAMP_WITH_TIMEZONE_Length; 
                    break; 

                default: 
                    Debug.Assert(OCI.DATATYPE.INT_TIMESTAMP_TZ == ociType, "unrecognized type");
                    ociBytes = x_TIMESTAMP_WITH_TIMEZONE_Length;
                    break;
            } 

            byte[] result = new byte[ociBytes]; // NOTE: will zero the data 
            buffer.ReadBytes(valueOffset, result, 0, length); 

            if (OCI.DATATYPE.INT_TIMESTAMP_LTZ == ociType) { 
                TimeSpan tzadjust = connection.ServerTimeZoneAdjustmentToUTC;
                result[11] = (byte)(tzadjust.Hours + 20);
                result[12] = (byte)(tzadjust.Minutes + 60);
            } 
            else if (OCI.DATATYPE.INT_TIMESTAMP_TZ == ociType && 0x80 < result[11]) {
                // WebData 114105 - as it happens, Oracle has two formats for 
                // TIMESTAMP WITH TIME ZONE -- one is the format that includes 
                // the time zone offset hours and minutes in the value, the other
                // includes some funky value that they translate into the name 
                // of the time zone when they format it.  The first format is
                // relatively straight-forward, the latter is unintelligable, but
                // it does seem to be valid.  Since Oracle knows what to do with
                // those, we simply hand it to Oracle and ask them to convert it 
                // to something we can use.
                // 
                // NOTE, that Oracle requires that we give them an interval for 
                //       conversion from TIMESTAMP_LTZ, but we have already pre-
                //       qualified that we don't have one of those, so we simply 
                //       create an empty interval instead and pass it on.
                int rc;
                OciIntervalDescriptor tz = new OciIntervalDescriptor(connection.EnvironmentHandle);
                OciDateTimeDescriptor ts = new OciDateTimeDescriptor(connection.EnvironmentHandle, OCI.HTYPE.OCI_DTYPE_TIMESTAMP_TZ); 
                sbyte tzHour;
                sbyte tzMin; 
 
                rc = UnsafeNativeMethods.OCIDateTimeFromArray(
                                                    connection.EnvironmentHandle, 
                                                    connection.ErrorHandle,
                                                    result,
                                                    ociBytes,
                                                    (byte)OCI.DATATYPE.TIMESTAMP_TZ, 
                                                    ts,
                                                    tz, 
                                                    0); 
                if (0 != rc) {
                    connection.CheckError(connection.ErrorHandle, rc); 
                }
                rc = UnsafeNativeMethods.OCIDateTimeGetTimeZoneOffset(
                                                    connection.EnvironmentHandle,
                                                    connection.ErrorHandle, 
                                                    ts,
                                                    out tzHour, 
                                                    out tzMin); 
                if (0 != rc) {
                    connection.CheckError(connection.ErrorHandle, rc); 
                }
                result[11] = (byte)(tzHour + 20);
                result[12] = (byte)(tzMin + 60);
            } 

            return result; 
        } 

        public override int GetHashCode() { 
            int retval = IsNull ? 0 : _value.GetHashCode();
            return retval;
        }
 
        // used to deserialize DATE and INT_TIMESTAMP types from native buffer and convert it to DateTime
        static internal DateTime MarshalToDateTime(NativeBuffer buffer, int valueOffset, int lengthOffset, MetaType metaType, OracleConnection connection) { 
            byte[] rawValue = GetBytesFromBuffer(buffer, valueOffset, lengthOffset, metaType, connection); 
            DateTime result = ToDateTime(rawValue);
            return result; 
        }

        // used to serialize DATE type only into native buffer for parameter binding
        static internal int MarshalDateToNative(object value, NativeBuffer buffer, int offset, OCI.DATATYPE ociType, OracleConnection connection) { 
            byte[] from;
 
            if (value is OracleDateTime) { 
                from = ((OracleDateTime)value)._value;
            } 
            else {
                DateTime dt = (DateTime)value;
                from = new byte[x_TIMESTAMP_Length];  // Pack requires at least x_TIMESTAMP_Length
                // pack the date and time only, fsec is not used in DATE type 
                Pack(from, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, 0);
            } 
 
            int ociBytes = x_DATE_Length;
 
            buffer.WriteBytes(offset, from, 0, ociBytes);
            return ociBytes;
        }
 
        // used to deserialize INT_TIMESTAMP* values from OCI's OracleDateTime descriptor and construct CLR's DateTime for them
        static internal DateTime MarshalTimestampToDateTime(OciDateTimeDescriptor dateTimeDescriptor, MetaType metaType, OracleConnection connection) { 
            byte[] rawValue = GetBytesFromDescriptor(dateTimeDescriptor, metaType, connection); 
            DateTime result = ToDateTime(rawValue);
            return result; 
        }

        // creates empty OCI's OracleDateTime descriptor to be used for INT_TIMESTAMP* values serialization
        // caller should ensure ociType validity before calling this method 
        static internal OciDateTimeDescriptor CreateEmptyDescriptor(OCI.DATATYPE ociType, OracleConnection connection) {
            // convert DATATYPE to HTYPE 
            OCI.HTYPE dbType; 
            switch (ociType) {
                case OCI.DATATYPE.INT_TIMESTAMP: 
                    dbType = OCI.HTYPE.OCI_DTYPE_TIMESTAMP;
                    break;

                case OCI.DATATYPE.INT_TIMESTAMP_TZ: 
                    dbType = OCI.HTYPE.OCI_DTYPE_TIMESTAMP_TZ;
                    break; 
 
                case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
                default: 
                    Debug.Assert(OCI.DATATYPE.INT_TIMESTAMP_LTZ == ociType, "unrecognized type");
                    dbType = OCI.HTYPE.OCI_DTYPE_TIMESTAMP_LTZ;
                    break;
            } 

            OciDateTimeDescriptor descriptor = new OciDateTimeDescriptor(connection.EnvironmentHandle, dbType); 
            return descriptor; 
        }
 
        // creates OCI's OracleDateTime descriptor and fills it with given DateTime or OracleDateTime value
        // this method is used with INT_TIMESTAMP* values only, caller should ensure ociType validity before calling it
        static internal OciDateTimeDescriptor CreateDescriptor(OCI.DATATYPE ociType, OracleConnection connection, object value) {
            // this array will be used as an input to OCIDateTimeFromArray to construct the OCI Datetime descriptor 
            byte[] from;
            if (value is OracleDateTime) { 
                from = ((OracleDateTime)value)._value; 
            }
            else { 
                // this will raise cast exception if value is neither OracleDateTime nor DateTime (backward compatibility)
                DateTime dt = (DateTime)value;
                OracleDateTime temp = new OracleDateTime(dt);
                from = temp._value; 
            }
 
            OCI.DATATYPE dbType; 
            switch (ociType) {
                case OCI.DATATYPE.INT_TIMESTAMP: 
                    dbType = OCI.DATATYPE.TIMESTAMP;
                    break;

                case OCI.DATATYPE.INT_TIMESTAMP_LTZ: 
                    dbType = OCI.DATATYPE.TIMESTAMP_LTZ;
                    break; 
 
                case OCI.DATATYPE.INT_TIMESTAMP_TZ:
                default: 
                    Debug.Assert(OCI.DATATYPE.INT_TIMESTAMP_TZ == ociType, "unrecognized type");

                    dbType = OCI.DATATYPE.TIMESTAMP_TZ;
 
                    // for TIMESTAMP with time zone: we have to specify explicitly the timezone to preserve full backward compatibility with 2.0 RTM
                    // if the input byte array does not have time zone information in it, create a new byte array and explicitly initialize the time zone 
                    // from the Oracle's database time zone (dbtimezone). 
                    TimeSpan tzadjust = connection.ServerTimeZoneAdjustmentToUTC;
                    if (from.Length < x_TIMESTAMP_WITH_TIMEZONE_Length) { 
                        byte[] valueWithTZ = new byte[x_TIMESTAMP_WITH_TIMEZONE_Length];
                        Buffer.BlockCopy(from, 0, valueWithTZ, 0, from.Length);
                        from = valueWithTZ;
 
                        // set the timezone into array
                        from[11] = (byte)(20 + tzadjust.Hours); 
                        from[12] = (byte)(60 + tzadjust.Minutes); 
                    }
 
                    break;
            }

            // create empty descriptor 
            OciDateTimeDescriptor descriptor = CreateEmptyDescriptor(ociType, connection);
            OciIntervalDescriptor tz = new OciIntervalDescriptor(connection.EnvironmentHandle); 
 
            // NOTE: VSTS 225565: we've tried to use OCIDateTimeConstruct API, but it looks like that API ignores the timezone argument for TIMESTAMP_TZ type.
            // Using OCIDateTimeFromArray we can set the timezone information into the descriptor 
            int rc = UnsafeNativeMethods.OCIDateTimeFromArray(
                connection.EnvironmentHandle,
                connection.ErrorHandle,
                from, 
                (uint)from.Length,
                (byte)dbType, 
                descriptor, 
                tz, // used for LTZ only - to be compatible with 2.0 RTM, we do not set the offset timezone to client's timezone, so it is not used in calculations
                MaxOracleFSecPrecision // use the max fsec precision 
                );

            if (0 != rc) {
                connection.CheckError(connection.ErrorHandle, rc); 
            }
 
            return descriptor; 
        }
 
        internal bool HasTimeZoneInfo {
            get {
                return _value != null && _value.Length >= x_TIMESTAMP_WITH_TIMEZONE_Length;
            } 
        }
 
        internal bool HasTimeInfo { 
            get {
                return _value != null && _value.Length >= x_TIMESTAMP_Length; 
            }
        }

        public static OracleDateTime Parse(string s) { 
            // Rather than figure out which formats, etc, we just simplify our
            // life and convert this to a DateTime, which we can use to build 
            // the real Oracle Date from. 
            DateTime datetime = DateTime.Parse(s, null);
            return new OracleDateTime(datetime); 
        }

        static private DateTime ToDateTime(byte[] rawValue) {
            int year, month, day, hour, minute, second, fsec; 
            int length = Unpack( rawValue, out year, out month, out day, out hour, out minute, out second, out fsec);
 
            DateTime result = new DateTime(year, month, day, hour, minute, second); 

            if (length > x_DATE_Length && fsec > FractionalSecondsPerTick) { 
                // DEVNOTE: Yes, there's a mismatch in the precision between Oracle,
                //          (which has 9 digits) and System.DateTime (which has 7
                //          digits);  All the other providers truncate the precision,
                //          so we do as well. 
                result = result.AddTicks((long)fsec / FractionalSecondsPerTick);
            } 
            return result; 
        }
 
        public override string ToString() {
            if (IsNull) {
                return ADP.NullString;
            } 
            string retval = Value.ToString((IFormatProvider)null);
            return retval; 
        } 

        public static OracleBoolean Equals(OracleDateTime x, OracleDateTime y) { 
            // Alternative method for operator ==
            return (x == y);
        }
 
        public static OracleBoolean GreaterThan(OracleDateTime x, OracleDateTime y) {
            // Alternative method for operator > 
            return (x > y); 
        }
 
        public static OracleBoolean GreaterThanOrEqual(OracleDateTime x, OracleDateTime y) {
            // Alternative method for operator >=
            return (x >= y);
        } 

        public static OracleBoolean LessThan(OracleDateTime x, OracleDateTime y) { 
            // Alternative method for operator < 
            return (x < y);
        } 

        public static OracleBoolean LessThanOrEqual(OracleDateTime x, OracleDateTime y) {
            // Alternative method for operator <=
            return (x <= y); 
        }
 
        public static OracleBoolean NotEquals(OracleDateTime x, OracleDateTime y) { 
            // Alternative method for operator !=
            return (x != y); 
        }

        public static explicit operator DateTime(OracleDateTime x) {
            if (x.IsNull) { 
                throw ADP.DataIsNull();
            } 
            return x.Value; 
        }
 
        public static explicit operator OracleDateTime(string x) {
            return OracleDateTime.Parse(x);
        }
 

        public static OracleBoolean operator==  (OracleDateTime x, OracleDateTime y) { 
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) == 0); 
        }
 
        public static OracleBoolean operator>   (OracleDateTime x, OracleDateTime y) {
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) > 0);
        }
 
        public static OracleBoolean operator>=  (OracleDateTime x, OracleDateTime y) {
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) >= 0); 
        } 

        public static OracleBoolean operator<   (OracleDateTime x, OracleDateTime y) { 
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) < 0);
        }

        public static OracleBoolean operator<=  (OracleDateTime x, OracleDateTime y) { 
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) <= 0);
        } 
 
        public static OracleBoolean operator!=  (OracleDateTime x, OracleDateTime y) {
            return (x.IsNull || y.IsNull) ? OracleBoolean.Null : new OracleBoolean(x.CompareTo(y) != 0); 
        }

    }
} 

// 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