Merge pull request #1304 from slluis/mac-proxy-autoconfig
[mono.git] / mcs / class / System.Data / System.Data.SqlTypes / SqlDecimal.cs
1 //
2 // System.Data.SqlTypes.SqlDecimal
3 //
4 // Author:
5 //   Tim Coleman <tim@timcoleman.com>
6 //   Ville Palo <vi64pa@koti.soon.fi>
7 //
8 // (C) Copyright 2002 Tim Coleman
9 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using Mono.Data.Tds.Protocol;
35 using System;
36 using System.Xml;
37 using System.Text;
38 using System.Xml.Schema;
39 using System.Globalization;
40 using System.Xml.Serialization;
41
42 namespace System.Data.SqlTypes
43 {
44 #if NET_2_0
45         [SerializableAttribute]
46         [XmlSchemaProvider ("GetXsdType")]
47 #endif
48         public struct SqlDecimal : INullable, IComparable
49 #if NET_2_0
50                                 , IXmlSerializable
51 #endif
52         {
53                 #region Fields
54
55                 int[] value;
56                 byte precision;
57                 byte scale;
58                 bool positive;
59
60                 private bool notNull;
61
62                 // borrowed from System.Decimal
63                 const int SCALE_SHIFT = 16;
64                 const int SIGN_SHIFT = 31;
65                 const int RESERVED_SS32_BITS = 0x7F00FFFF;
66                 const ulong LIT_GUINT64_HIGHBIT = 0x8000000000000000;
67                 const ulong LIT_GUINT32_HIGHBIT = 0x80000000;
68                 const byte DECIMAL_MAX_INTFACTORS = 9;
69                 static uint [] constantsDecadeInt32Factors = new uint [10] {
70                         1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u, 
71                         10000000u, 100000000u, 1000000000u};
72
73                 public static readonly byte MaxPrecision = 38; 
74                 public static readonly byte MaxScale = 38;
75
76                 // This should be 99999999999999999999999999999999999999
77                 public static readonly SqlDecimal MaxValue = new SqlDecimal (MaxPrecision, 
78                                                                              (byte)0, 
79                                                                              true, 
80                                                                              (int)-1, 
81                                                                              160047679,
82                                                                              1518781562, 
83                                                                              1262177448);
84                 // This should be -99999999999999999999999999999999999999
85                 public static readonly SqlDecimal MinValue = new SqlDecimal (MaxPrecision, 
86                                                                              (byte)0, false,
87                                                                              -1,
88                                                                              160047679,
89                                                                              1518781562,
90                                                                              1262177448);
91
92                 public static readonly SqlDecimal Null;
93
94                 #endregion
95
96                 #region Constructors
97
98                 public SqlDecimal (decimal value)
99                 {
100                         int[] binData = Decimal.GetBits (value);
101
102                         this.precision = MaxPrecision; // this value seems unclear
103
104                         this.scale = (byte)(((uint)binData [3]) >> SCALE_SHIFT);
105                         
106                         if (this.scale > MaxScale || ((uint)binData [3] & RESERVED_SS32_BITS) != 0)
107                                 throw new ArgumentException(Locale.GetText ("Invalid scale"));
108
109                         this.value = new int[4];
110                         this.value[0] = binData[0];
111                         this.value[1] = binData[1];
112                         this.value[2] = binData[2];
113                         this.value[3] = 0;
114
115                         positive = (value >= 0);
116                         notNull = true;
117                         precision = GetPrecision (value);
118                 }
119
120                 public SqlDecimal (double dVal) : this ((decimal) dVal)
121                 {
122                         SqlDecimal n = this;
123                         int digits = 17 - precision;
124                         if (digits > 0)
125                                 n = AdjustScale (this, digits, false);
126                         else
127                                 n = Round (this, 17);
128                         this.notNull = n.notNull;
129                         this.positive = n.positive;
130                         this.precision = n.precision;
131                         this.scale = n.scale;
132                         this.value = n.value;
133                 }
134
135                 public SqlDecimal (int value) : this ((decimal) value)
136                 {
137                 }
138
139                 public SqlDecimal (long value) : this ((decimal) value)
140                 {
141                 }
142
143                 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int[] bits) : this (bPrecision, bScale, fPositive, bits[0], bits[1], bits[2], bits[3])
144                 {
145                 }
146
147                 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int data1, int data2, int data3, int data4)
148                 {
149                         this.precision = bPrecision;
150                         this.scale = bScale;
151                         this.positive = fPositive;
152                         this.value = new int[4];
153                         this.value[0] = data1;
154                         this.value[1] = data2;
155                         this.value[2] = data3;
156                         this.value[3] = data4;
157                         notNull = true;
158
159                         if (precision < scale)
160                                 throw new SqlTypeException (Locale.GetText ("Invalid presicion/scale combination."));
161
162                         if (precision > 38)
163                                 throw new SqlTypeException (Locale.GetText ("Invalid precision/scale combination."));
164
165                         if (this.ToDouble () > (Math.Pow (10, 38) - 1) ||
166                             this.ToDouble () < -(Math.Pow (10, 38)))
167                                 throw new OverflowException ("Can't convert to SqlDecimal, Out of range ");
168                 }
169
170                 #endregion
171
172                 #region Properties
173
174                 public byte[] BinData {
175                         get {
176                                 byte [] b = new byte [value.Length * 4];
177                                 
178                                 int j = 0;
179                                 for (int i = 0; i < value.Length; i++) {
180
181                                         b [j++] = (byte)(0xff & value [i]);
182                                         b [j++] = (byte)(0xff & value [i] >> 8);
183                                         b [j++] = (byte)(0xff & value [i] >> 16);
184                                         b [j++] = (byte)(0xff & value [i] >> 24);
185                                 }
186
187                                 return b;
188                         }
189                 }
190
191                 public int[] Data {
192                         get {
193                                 if (this.IsNull)
194                                         throw new SqlNullValueException ();
195                                 // Data should always return clone, not to be modified
196                                 int [] ret = new int [4];
197                                 ret [0] = value [0];
198                                 ret [1] = value [1];
199                                 ret [2] = value [2];
200                                 ret [3] = value [3];
201                                 return ret;
202                         }
203                 }
204
205                 public bool IsNull {
206                         get { return !notNull; }
207                 }
208
209                 public bool IsPositive {
210                         get { return positive; }
211                 }
212
213                 public byte Precision {
214                         get { return precision; }
215                 }
216
217                 public byte Scale {
218                         get { return scale; }
219                 }
220
221                 public decimal Value {
222                         get {
223                                 if (this.IsNull) 
224                                         throw new SqlNullValueException ();
225
226                                 if (this.value[3] > 0)
227                                         throw new OverflowException ();
228
229                                 return new decimal (value[0], value[1], value[2], !positive, scale);
230                         }
231                 }
232
233                 #endregion
234
235                 #region Methods
236
237                 public static SqlDecimal Abs (SqlDecimal n)
238                 {
239                         if (!n.notNull)
240                                 return n;
241                         return new SqlDecimal (n.Precision, n.Scale, true, n.Data);
242                 }
243
244                 public static SqlDecimal Add (SqlDecimal x, SqlDecimal y)
245                 {
246                         return (x + y);
247                 }
248
249                 public static SqlDecimal AdjustScale (SqlDecimal n, int digits, bool fRound)
250                 {
251                         byte prec = n.Precision;
252                         if (n.IsNull)
253                                 throw new SqlNullValueException ();
254
255                         byte scale;
256                         if (digits == 0)
257                                 return n;
258                         else if (digits > 0) {
259                                 prec = (byte)(prec + digits);
260                                 scale = (byte) (n.scale + digits);
261                                 // use Math.Pow once the Ctr (double) is fixed to  handle
262                                 // values greater than Decimal.MaxValue
263                                 // the current code creates too many sqldecimal objects 
264                                 //n = n * (new SqlDecimal ((double)Math.Pow (10, digits)));
265                                 for (int i = 0; i < digits; i++)
266                                         n *= 10;
267                         } else {
268                                 if (n.Scale < Math.Abs (digits))
269                                         throw new SqlTruncateException ();
270
271                                 if (fRound)
272                                         n = Round (n, digits + n.scale);
273                                 else
274                                         n = Round (Truncate (n, digits + n.scale), digits + n.scale);
275                                 scale = n.scale;
276                         }
277
278                         return new SqlDecimal (prec, scale, n.positive, n.Data);
279                 }
280
281                 public static SqlDecimal Ceiling (SqlDecimal n)
282                 {
283                         if (!n.notNull)
284                                 return n;
285                         return AdjustScale (n, -(n.Scale), true);
286                 }
287
288                 public int CompareTo (object value)
289                 {
290                         if (value == null)
291                                 return 1;
292                         if (!(value is SqlDecimal))
293                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlDecimal"));
294
295                         return CompareTo ((SqlDecimal) value);
296                 }
297
298 #if NET_2_0
299                 public
300 #endif
301                 int CompareTo (SqlDecimal value)
302                 {
303                         if (value.IsNull)
304                                 return 1;
305                         else
306                                 return this.Value.CompareTo (value.Value);
307                 }
308
309                 public static SqlDecimal ConvertToPrecScale (SqlDecimal n, int precision, int scale)
310                 {
311                         int prec = n.Precision;
312                         int sc = n.Scale;
313                         n = AdjustScale (n, scale-n.scale, true);
314                         if ((n.Scale >= sc) && (precision < n.Precision))
315                                 throw new SqlTruncateException ();
316                         else{
317                                 prec = precision;
318                                 return new SqlDecimal ((byte)prec, n.scale, n.IsPositive, n.Data);
319                         }
320                 }
321
322                 public static SqlDecimal Divide (SqlDecimal x, SqlDecimal y)
323                 {
324                         return (x / y);
325                 }
326
327                 public override bool Equals (object value)
328                 {
329                         if (!(value is SqlDecimal))
330                                 return false;
331                         else if (this.IsNull)
332                                 return ((SqlDecimal)value).IsNull;
333                         else if (((SqlDecimal)value).IsNull)
334                                 return false;
335                         else
336                                 return (bool) (this == (SqlDecimal)value);
337                 }
338
339                 public static SqlBoolean Equals (SqlDecimal x, SqlDecimal y)
340                 {
341                         return (x == y);
342                 }
343
344                 public static SqlDecimal Floor (SqlDecimal n)
345                 {
346                         return AdjustScale (n, -(n.Scale), false);
347                 }
348
349                 internal static SqlDecimal FromTdsBigDecimal (TdsBigDecimal x)
350                 {
351                         if (x == null)
352                                 return Null;
353                         else
354                                 return new SqlDecimal (x.Precision, x.Scale, !x.IsNegative, x.Data);
355                 }
356
357                 public override int GetHashCode ()
358                 {
359                         int result = 10;
360                         result = 91 * result + this.Data[0];
361                         result = 91 * result + this.Data[1];
362                         result = 91 * result + this.Data[2];
363                         result = 91 * result + this.Data[3];
364                         result = 91 * result + (int) this.Scale;
365                         result = 91 * result + (int) this.Precision;
366
367                         return result;
368                 }
369
370                 public static SqlBoolean GreaterThan (SqlDecimal x, SqlDecimal y)
371                 {
372                         return (x > y);
373                 }
374
375                 public static SqlBoolean GreaterThanOrEqual (SqlDecimal x, SqlDecimal y)
376                 {
377                         return (x >= y);
378                 }
379
380                 public static SqlBoolean LessThan (SqlDecimal x, SqlDecimal y)
381                 {
382                         return (x < y);
383                 }
384
385                 public static SqlBoolean LessThanOrEqual (SqlDecimal x, SqlDecimal y)
386                 {
387                         return (x <= y);
388                 }
389
390                 public static SqlDecimal Multiply (SqlDecimal x, SqlDecimal y)
391                 {
392                         return (x * y);
393                 }
394
395                 public static SqlBoolean NotEquals (SqlDecimal x, SqlDecimal y)
396                 {
397                         return (x != y);
398                 }
399
400                 public static SqlDecimal Parse (string s)
401                 {
402                         if (s == null)
403                                 throw new ArgumentNullException (Locale.GetText ("string s"));
404                         else
405                                 return new SqlDecimal (Decimal.Parse (s));
406                 }
407
408                 public static SqlDecimal Power (SqlDecimal n, double exp)
409                 {
410                         if (n.IsNull)
411                                 return SqlDecimal.Null;
412
413                         return new SqlDecimal (Math.Pow (n.ToDouble (), exp));
414                 }
415
416                 public static SqlDecimal Round (SqlDecimal n, int position)
417                 {
418                         if (n.IsNull)
419                                 throw new SqlNullValueException ();
420
421                         decimal d = n.Value;
422                         d = Decimal.Round (d, position);
423                         return new SqlDecimal (d);
424                 }
425
426                 public static SqlInt32 Sign (SqlDecimal n)
427                 {
428                         if (n.IsNull)
429                                 return SqlInt32.Null;
430                         return (SqlInt32) (n.IsPositive ? 1 : -1);
431                 }
432
433                 public static SqlDecimal Subtract (SqlDecimal x, SqlDecimal y)
434                 {
435                         return (x - y);
436                 }
437
438                 private byte GetPrecision (decimal value)
439                 {
440                         string str = value.ToString ();
441                         byte result = 0;
442
443                         foreach (char c in str) {
444                                 
445                                 if (c >= '0' && c <= '9')
446                                         result++;
447                         }
448                         
449                         return result;
450                 }
451
452                 public double ToDouble ()
453                 {
454                         // FIXME: This is wrong way to do this
455                         double d = (uint)this.Data [0];
456                         d += ((uint)this.Data [1]) * Math.Pow (2, 32);
457                         d += ((uint)this.Data [2]) * Math.Pow (2, 64);
458                         d += ((uint)this.Data [3]) * Math.Pow (2, 96);
459                         d = d / Math.Pow (10, scale);
460
461                         return d;
462                 }
463
464                 public SqlBoolean ToSqlBoolean ()
465                 {
466                         return ((SqlBoolean) this);
467                 }
468                 
469                 public SqlByte ToSqlByte ()
470                 {
471                         return ((SqlByte) this);
472                 }
473
474                 public SqlDouble ToSqlDouble ()
475                 {
476                         return ((SqlDouble) this);
477                 }
478
479                 public SqlInt16 ToSqlInt16 ()
480                 {
481                         return ((SqlInt16) this);
482                 }
483
484                 public SqlInt32 ToSqlInt32 ()
485                 {
486                         return ((SqlInt32) this);
487                 }
488
489                 public SqlInt64 ToSqlInt64 ()
490                 {
491                         return ((SqlInt64) this);
492                 }
493
494                 public SqlMoney ToSqlMoney ()
495                 {
496                         return ((SqlMoney) this);
497                 }
498
499                 public SqlSingle ToSqlSingle ()
500                 {
501                         return ((SqlSingle) this);
502                 }
503
504                 public SqlString ToSqlString ()
505                 {
506                         return ((SqlString) this);
507                 }
508
509                 public override string ToString ()
510                 {
511                         if (this.IsNull)
512                                 return "Null";
513                         
514                         // convert int [4] --> ulong [2]
515                         ulong lo = (uint)this.Data [0];
516                         lo += (ulong)((ulong)this.Data [1] << 32);
517                         ulong hi = (uint)this.Data [2];
518                         hi += (ulong)((ulong)this.Data [3] << 32);
519
520                         uint rest = 0;
521                         StringBuilder Result = new StringBuilder ();
522                         for (int i = 0; lo != 0 || hi != 0; i++) {
523                                 Div128By32 (ref hi, ref lo, 10, ref rest);
524                                 Result.Insert (0, rest.ToString ());
525                         }
526
527                         while (Result.Length > this.Precision)
528                                 Result.Remove (Result.Length - 1, 1);
529  
530                         if (this.Scale > 0)
531                                 Result.Insert (Result.Length - this.Scale, ".");
532
533                         if (!positive)
534                                 Result.Insert (0, '-');
535
536                         return Result.ToString ();
537                 }
538
539                 // From decimal.c
540                 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider)
541                 {
542                         uint t = 0;
543                         return Div128By32 (ref hi, ref lo, divider, ref t);
544                 }
545
546                 // From decimal.c
547                 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider, ref uint rest)
548                 {
549                         ulong a = 0;
550                         ulong b = 0;
551                         ulong c = 0;
552                         
553                         a = (uint)(hi >> 32);
554                         b = a / divider;
555                         a -= b * divider;
556                         a <<= 32;
557                         a |= (uint)hi;
558                         c = a / divider;
559                         a -= c * divider;
560                         a <<= 32;
561                         hi = b << 32 | (uint)c;
562                         
563                         a |= (uint)(lo >> 32);
564                         b = a / divider;
565                         a -= b * divider;
566                         a <<= 32;
567                         a |= (uint)lo;
568                         c = a / divider;
569                         a -= c * divider;
570                         lo = b << 32 | (uint)c;
571                         rest = (uint)a;
572                         a <<= 1;
573
574                         return (a > divider || (a == divider && (c & 1) == 1)) ? 1 : 0;
575
576                 }
577
578                 [MonoTODO("Find out what is the right way to set scale and precision")]
579                 private static SqlDecimal DecimalDiv (SqlDecimal x, SqlDecimal y)
580                 {
581                         ulong lo = 0;
582                         ulong hi = 0;
583                         int sc = 0; // scale
584                         int texp = 0;
585                         byte prec = 0; // precision
586                         bool positive = ! (x.positive ^ y.positive);
587
588                         prec = x.Precision >= y.Precision ? x.Precision : y.Precision;
589                         DecimalDivSub (ref x, ref y, ref lo, ref hi, ref texp);
590
591                         sc = x.Scale - y.Scale;
592
593                         Rescale128 (ref lo, ref hi, ref sc, texp, 0, 38, 1);
594
595                         uint r = 0;
596                         while (prec < sc) {
597                                 Div128By32(ref hi, ref lo, 10, ref r);
598                                 sc--;
599                         }
600
601                         if (r >= 5) 
602                                 lo++;
603
604                         while ((((double)hi) * Math.Pow(2,64) + lo) - Math.Pow (10, prec) > 0)
605                                 prec++;
606
607                         while ((prec + sc) > MaxScale) {
608                                 Div128By32(ref hi, ref lo, 10, ref r);
609                                 sc--;
610                                 if (r >= 5)
611                                         lo++;
612                         }
613
614                         int resultLo = (int) lo;
615                         int resultMi = (int) (lo >> 32);
616                         int resultMi2 = (int) (hi);
617                         int resultHi = (int) (hi >> 32);
618
619                         return new SqlDecimal (prec, (byte) sc, positive, resultLo,
620                                                        resultMi, resultMi2,
621                                                        resultHi);
622                 }
623
624                 // From decimal.c
625                 private static void Rescale128 (ref ulong clo, ref ulong chi, 
626                                              ref int scale, int texp,
627                                              int minScale, int maxScale,
628                                              int roundFlag)
629                 {
630                         uint factor = 0;
631                         uint overhang = 0;
632                         int sc = 0;
633                         int i = 0;
634                         int roundBit = 0;
635
636                         sc = scale;
637                         if (texp > 0) {
638                                 // reduce exp 
639                                 while (texp > 0 && sc <= maxScale) {
640                                         overhang = (uint)(chi >> 64);
641                                         while (texp > 0 && (((clo & 1) == 0) || overhang > 0)) {
642                                                 if (--texp == 0)
643                                                         roundBit = (int)(clo & 1);
644                                                 RShift128 (ref clo, ref chi);
645
646                                                 overhang = (uint)(chi >> 32);
647                                         }
648
649                                         if (texp > DECIMAL_MAX_INTFACTORS)
650                                                 i = DECIMAL_MAX_INTFACTORS;
651                                         else 
652                                                 i = texp;
653
654                                         if (sc + i > maxScale) 
655                                                 i = maxScale - sc;
656
657                                         if (i == 0)
658                                                 break;
659
660                                         texp -= i;
661                                         sc += i;
662
663                                         // 10^i/2^i=5^i 
664                                         factor = constantsDecadeInt32Factors [i] >> i; 
665                                         Mult128By32 (ref clo, ref chi, factor, 0);
666                                 }
667
668                                 while (texp > 0) {
669                                         if (--texp == 0) 
670                                                 roundBit = (int)(clo & 1);
671                                         RShift128 (ref clo, ref chi);
672                                 }
673                         }
674         
675                         while (sc > maxScale) {
676                                 i = scale - maxScale;
677                                 if (i > DECIMAL_MAX_INTFACTORS)
678                                         i = DECIMAL_MAX_INTFACTORS;
679                                 sc -= i;
680                                 roundBit = Div128By32 (ref clo, ref chi, 
681                                                        constantsDecadeInt32Factors[i]);
682                         }
683
684                         while (sc < minScale) {
685                                 if (roundFlag == 0)
686                                         roundBit = 0;
687                                 i = minScale - sc;
688                                 if (i > DECIMAL_MAX_INTFACTORS)
689                                         i = DECIMAL_MAX_INTFACTORS;
690                                 sc += i;
691                                 Mult128By32 (ref clo, ref chi, 
692                                              constantsDecadeInt32Factors[i], roundBit);
693                                 roundBit = 0;
694                         }
695                         scale = sc;
696                         Normalize128 (ref clo, ref chi, ref sc, roundFlag, roundBit);
697                 }
698
699                 // From decimal.c
700                 private static void Normalize128(ref ulong clo, ref ulong chi, ref int scale, int roundFlag, int roundBit)
701                 {
702                         int sc = scale;
703                         
704                         scale = sc;
705                         if ((roundFlag != 0) && (roundBit != 0)) 
706                                 RoundUp128 (ref clo, ref chi); 
707                 }
708
709                 // From decimal.c
710                 private static void RoundUp128(ref ulong lo, ref ulong hi)
711                 {
712                             if ((++lo) == 0) 
713                                     ++hi;
714                 }
715                 
716                 // From decimal.c
717                 private static void DecimalDivSub (ref SqlDecimal x, ref SqlDecimal y, ref ulong clo, ref ulong chi, ref int exp)
718                 {
719                         ulong xlo, xmi, xhi;
720                         ulong tlo = 0; 
721                         ulong tmi = 0;
722                         ulong thi = 0;;
723                         uint ylo = 0;
724                         uint ymi = 0;
725                         uint ymi2 = 0;
726                         uint yhi = 0;
727                         int ashift = 0; 
728                         int bshift = 0;
729                         int extraBit = 0;
730
731                         xhi = (ulong) ((ulong) x.Data [3] << 32) | (ulong) x.Data [2];
732                         xmi = (ulong) ((ulong) x.Data [1] << 32) | (ulong) x.Data [0];
733                         xlo = (uint) 0;
734                         ylo = (uint) y.Data [0];
735                         ymi = (uint) y.Data [1];
736                         ymi2 = (uint) y.Data [2];
737                         yhi = (uint) y.Data [3];
738                         
739                         if (ylo == 0 && ymi == 0 && ymi2 == 0 && yhi == 0)
740                                 throw new DivideByZeroException ();
741
742                         if (xmi == 0 && xhi == 0) {
743                                 clo = chi = 0;
744                                 return;
745                         }
746                         
747                         // enlarge dividend to get maximal precision
748                         for (ashift = 0; (xhi & LIT_GUINT64_HIGHBIT) == 0; ++ashift)
749                                 LShift128 (ref xmi, ref xhi);
750                         
751                         // ensure that divisor is at least 2^95 
752                         for (bshift = 0; (yhi & LIT_GUINT32_HIGHBIT) == 0; ++bshift) 
753                                 LShift128 (ref ylo, ref ymi, ref ymi2, ref yhi);
754                         
755                         thi = ((ulong)yhi) << 32 | (ulong)ymi2;
756                         tmi = ((ulong)ymi) << 32 | (ulong)ylo;
757                         tlo = 0;
758
759                         if (xhi > thi || (xhi == thi && xmi >=tmi)) {
760                                 Sub192(xlo, xmi, xhi, tlo, tmi, thi, ref xlo, ref xmi, ref xhi);
761                                 extraBit = 1;
762                         } else {
763                                 extraBit = 0;
764                         }
765                         
766                         Div192By128To128 (xlo, xmi, xhi, ylo, ymi, ymi2, yhi, ref clo, ref chi);
767  
768                         exp = 128 + ashift - bshift;
769
770                         if (extraBit != 0) {
771                                 RShift128 (ref clo, ref chi);
772                                 chi += LIT_GUINT64_HIGHBIT;
773                                 exp--;
774                         }
775
776                         // try loss free right shift
777                         while (exp > 0 && (clo & 1) == 0) {
778                                 RShift128 (ref clo, ref chi);
779                                 exp--;
780                         }
781                 }
782
783                 // From decimal.c
784                 /*
785                 private static void RShift192(ref ulong lo, ref ulong mi, ref ulong hi)
786                 {
787                         lo >>= 1;
788                         if ((mi & 1) != 0)
789                                 lo |= LIT_GUINT64_HIGHBIT;
790                         
791                         mi >>= 1;
792                         if ((hi & 1) != 0)
793                                 mi |= LIT_GUINT64_HIGHBIT;
794
795                         hi >>= 1;
796                 }
797                 */
798
799                 // From decimal.c
800                 private static void RShift128(ref ulong lo, ref ulong hi)
801                 {
802                         lo >>=1;
803                         if ((hi & 1) != 0) 
804                                 lo |= LIT_GUINT64_HIGHBIT;
805                         hi >>= 1;
806                 }
807                 
808                 // From decimal.c
809                 private static void LShift128(ref ulong lo, ref ulong hi)
810                 {
811                         hi <<= 1;
812
813                         if ((lo & LIT_GUINT64_HIGHBIT) != 0) 
814                                 hi++;
815
816                         lo <<= 1;
817                 }
818                 
819                 // From decimal.c
820                 private static void LShift128(ref uint lo, ref uint mi, ref uint mi2, ref uint hi)
821                 {
822                         hi <<= 1;
823                         if ((mi2 & LIT_GUINT32_HIGHBIT) != 0) 
824                                 hi++;
825
826                         mi2 <<= 1;
827                         if ((mi & LIT_GUINT32_HIGHBIT) != 0) 
828                                 mi2++;
829                         
830                         mi <<= 1;
831                         if ((lo & LIT_GUINT32_HIGHBIT) != 0) 
832                                 mi++;
833
834                         lo <<= 1;
835                 }
836
837                 // From decimal.c
838                 private static void Div192By128To128 (ulong xlo, ulong xmi, ulong xhi,
839                                                uint ylo, uint ymi, uint ymi2, 
840                                                uint yhi, ref ulong clo, ref ulong chi)
841                 {
842                         ulong rlo, rmi, rhi; // remainders
843                         uint h, c;
844
845                         rlo = xlo;
846                         rmi = xmi;
847                         rhi = xhi;
848
849                         h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
850
851                         // mid 32 bit
852                         rhi = (rhi << 32) | (rmi >> 32);
853                         rmi = (rmi << 32) | (rlo >> 32);
854                         rlo <<= 32;
855
856                         chi = (((ulong)h) << 32) | Div192By128To32WithRest (
857                                 ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
858
859                         // low 32 bit
860                         rhi = (rhi << 32) | (rmi >> 32);
861                         rmi = (rmi << 32) | (rlo >> 32);
862                         rlo <<= 32;
863
864                         h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi,
865                                                      ylo, ymi, ymi2, yhi);
866
867                         // estimate lowest 32 bit (two last bits may be wrong)
868                         if (rhi >= yhi) 
869                                 c =  0xFFFFFFFF;
870                         else {
871                                 rhi <<= 32;
872                                 c = (uint)(rhi / yhi);
873                         }
874                                 
875                         clo = (((ulong)h) << 32) | c;
876                 }
877                         
878                 // From decimal.c
879                 private static uint Div192By128To32WithRest(ref ulong xlo, ref ulong xmi,
880                                                 ref ulong xhi, uint ylo, 
881                                                 uint ymi, uint ymi2, uint yhi)
882                 {
883                         ulong rlo, rmi, rhi; // remainder
884                         ulong tlo = 0;
885                         ulong thi = 0;
886                         uint c;
887                         
888                         rlo = xlo;
889                         rmi = xmi;
890                         rhi = xhi;
891
892                         if (rhi >= (((ulong)yhi << 32)))
893                                 c = 0xFFFFFFFF;
894                         else
895                                 c = (uint) (rhi / yhi);
896
897                         Mult128By32To128 (ylo, ymi, ymi2, yhi, c, ref tlo, ref thi);
898                         Sub192 (rlo, rmi, rhi, 0, tlo, thi, ref rlo, ref rmi, ref rhi);
899
900                         while (((long)rhi) < 0) {
901                                 c--;
902                                 Add192 (rlo, rmi, rhi, 0, (((ulong)ymi) << 32) | ylo, yhi | ymi2, ref rlo, ref rmi, ref rhi);
903                         }
904                         xlo = rlo;
905                         xmi = rmi;
906                         xhi = rhi;
907
908                         return c;
909                 }
910
911                 // From decimal.c
912                 /*
913                 private static void Mult192By32 (ref ulong clo, ref ulong cmi, ref ulong chi, ulong factor, int roundBit)
914                 {
915                         ulong a = 0;
916                         uint h0 = 0;
917                         uint h1 = 0;
918
919                         a = ((ulong)(uint)clo) * factor;
920
921                         if (roundBit != 0)
922                                 a += factor / 2;
923
924                         h0 = (uint)a;
925                         a >>= 32;
926                         a += (clo >> 32) * factor;
927                         h1 = (uint)a;
928                         
929                         clo = ((ulong)h1) << 32 | h0;
930
931                         a >>= 32;
932                         a += ((ulong)(uint)cmi) * factor;
933                         h0 = (uint)a;
934                         
935                         a >>= 32;
936                         a += (cmi >> 32) * factor;
937                         h1 = (uint)a;
938                         
939                         cmi = ((ulong)h1) << 32 | h0;
940                         a >>= 32;
941                         a += ((ulong)(uint)chi) * factor;
942                         h0 = (uint)a;
943
944                         a >>= 32;
945                         a += (chi >> 32) * factor;
946                         h1 = (uint)a;
947                         chi = ((ulong)h1) << 32 | h0;
948                 }
949                 */
950
951                 // From decimal.c
952                 private static void Mult128By32 (ref ulong clo, ref ulong chi, uint factor, int roundBit)
953                 {
954                         ulong a = 0;
955                         uint h0 = 0;
956                         uint h1 = 0;
957
958                         a = ((ulong)(uint)clo) * factor;
959
960                         if (roundBit != 0)
961                                 a += factor / 2;
962
963                         h0 = (uint)a;
964
965                         a >>= 32;
966                         a += (clo >> 32) * factor;
967                         h1 = (uint)a;
968                         
969                         clo = ((ulong)h1) << 32 | h0;
970
971                         a >>= 32;
972                         a += ((ulong)(uint)chi) * factor;
973                         h0 = (uint)a;
974                         
975                         a >>= 32;
976                         a += (chi >> 32) * factor;
977                         h1 = (uint)a;
978
979                         chi = ((ulong)h1) << 32 | h0;
980                 }
981
982                 // From decimal.c
983                 private static void Mult128By32To128(uint xlo, uint xmi, uint xmi2, uint xhi,
984                                          uint factor, ref ulong clo, ref ulong chi)
985                 {
986                         ulong a;
987                         uint h0, h1, h2;
988
989                         a = ((ulong)xlo) * factor;
990                         h0 = (uint)a;
991                         
992                         a >>= 32;
993                         a += ((ulong)xmi) * factor;
994                         h1 = (uint)a;
995
996                         a >>= 32;
997                         a += ((ulong)xmi2) * factor;
998                         h2 = (uint)a;
999
1000                         a >>= 32;
1001                         a += ((ulong)xhi) * factor;
1002                         
1003                         clo = ((ulong)h1) << 32 | h0;
1004                         chi = a | h2;
1005                 }
1006
1007                 // From decimal.c
1008                 private static void Add192 (ulong xlo, ulong xmi, ulong xhi,
1009                                      ulong ylo, ulong ymi, ulong yhi,
1010                                      ref ulong clo, ref ulong cmi, ref ulong chi)
1011                 {
1012                         xlo += ylo;
1013                         if (xlo < ylo) {
1014                                 xmi++;
1015                                 if (xmi == 0)
1016                                         xhi++;
1017                         }
1018
1019                         xmi += ymi;
1020
1021                         if (xmi < ymi)
1022                                 xmi++;
1023
1024                         xhi += yhi;
1025                         clo = xlo;
1026                         cmi = xmi;
1027                         chi = xhi;
1028                 }
1029
1030                 // From decimal.c
1031                 private static void Sub192 (ulong xlo, ulong xmi, ulong xhi,
1032                                      ulong ylo, ulong ymi, ulong yhi,
1033                                      ref ulong lo, ref ulong mi, ref ulong hi)
1034                 {
1035                         
1036                         ulong clo = 0;
1037                         ulong cmi = 0;
1038                         ulong chi = 0;
1039                         
1040                         clo = xlo - ylo;
1041                         cmi = xmi - ymi;
1042                         chi = xhi - yhi;
1043
1044                         if (xlo < ylo) {
1045                                 if (cmi == 0)
1046                                         chi--;
1047                                 cmi--;
1048                         }
1049
1050                         if (xmi < ymi)
1051                                 chi--;
1052
1053                         lo = clo;
1054                         mi = cmi;
1055                         hi = chi;
1056                 }
1057
1058                 public static SqlDecimal Truncate (SqlDecimal n, int position)
1059                 {
1060                         int diff = n.scale - position;
1061                         if (diff == 0)
1062                                 return n;
1063                         int [] data = n.Data;
1064                         decimal d = new decimal (data [0], data [1], data [2], !n.positive, 0);
1065                         decimal x = 10;
1066                         for (int i = 0; i < diff; i++, x *= 10)
1067                                 d = d - d % x;
1068                         data = Decimal.GetBits (d);
1069                         data [3] = 0;
1070                         return new SqlDecimal (n.precision, n.scale, n.positive, data);
1071                 }
1072
1073                 public static SqlDecimal operator + (SqlDecimal x, SqlDecimal y)
1074                 {
1075                         if (x.IsNull || y.IsNull)
1076                                 return SqlDecimal.Null;
1077                          //if one of them is negative, perform subtraction
1078                         if (x.IsPositive && !y.IsPositive){
1079                                 y = new SqlDecimal (y.Precision, y.Scale, !y.IsPositive, y.Data);
1080                                 return (x - y);
1081                         }
1082                         if (!x.IsPositive && y.IsPositive){
1083                                 x = new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
1084                                 return (y - x);
1085                         }
1086                         if (!x.IsPositive && !y.IsPositive){
1087                                 x = new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
1088                                 y = new SqlDecimal (y.Precision, y.Scale, !y.IsPositive, y.Data);
1089                                 x = (x + y);
1090                                 return new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
1091                         }
1092                         // adjust the scale to the larger of the two beforehand
1093                         if (x.scale > y.scale)
1094                                 y = SqlDecimal.AdjustScale (y, x.scale - y.scale, false); 
1095                         else if (y.scale > x.scale)
1096                                 x = SqlDecimal.AdjustScale (x, y.scale - x.scale, false); 
1097
1098                         byte resultPrecision = (byte)(Math.Max (x.Scale, y.Scale) +
1099                                                  Math.Max (x.Precision - x.Scale, y.Precision - y.Scale) + 1);
1100
1101                         if (resultPrecision > MaxPrecision)
1102                                 resultPrecision = MaxPrecision;
1103                         
1104                         int [] xData = x.Data; 
1105                         int [] yData = y.Data;
1106                         int [] resultBits = new int[4];
1107                         ulong carry = 0;
1108                         ulong res = 0;
1109                         for (int i = 0; i < 4; i++){
1110                                 res = (ulong)((uint)xData [i]) + (ulong)((uint)yData [i]) + carry;
1111                                 resultBits [i] = (int) (res & (UInt32.MaxValue));
1112                                 carry = res >> 32;
1113                         }
1114
1115                         if (carry > 0)
1116                                 throw new OverflowException ();
1117                         else
1118                                 return new SqlDecimal (resultPrecision, x.Scale, x.IsPositive, resultBits);
1119                 }
1120
1121                 public static SqlDecimal operator / (SqlDecimal x, SqlDecimal y)
1122                 {
1123                         if (x.IsNull || y.IsNull)
1124                                 return SqlDecimal.Null;
1125
1126                         return DecimalDiv (x, y);
1127                 }
1128
1129                 public static SqlBoolean operator == (SqlDecimal x, SqlDecimal y)
1130                 {
1131                         if (x.IsNull || y.IsNull) 
1132                                 return SqlBoolean.Null;
1133
1134                         if (x.IsPositive != y.IsPositive)
1135                                 return SqlBoolean.False;
1136
1137                         if (x.Scale > y.Scale)
1138                                 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, false);
1139                         else if (y.Scale > x.Scale)
1140                                 x = SqlDecimal.AdjustScale(y, y.Scale - x.Scale, false);
1141
1142                         for (int i = 0; i < 4; i += 1)
1143                                 if (x.Data[i] != y.Data[i])
1144                                         return SqlBoolean.False;
1145
1146                         return SqlBoolean.True;
1147                 }
1148
1149                 public static SqlBoolean operator > (SqlDecimal x, SqlDecimal y)
1150                 {
1151                         if (x.IsNull || y.IsNull) 
1152                                 return SqlBoolean.Null;
1153
1154                         if (x.IsPositive != y.IsPositive)
1155                                 return new SqlBoolean (x.IsPositive);
1156
1157                         if (x.Scale > y.Scale)
1158                                 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, false);
1159                         else if (y.Scale > x.Scale)
1160                                 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, false);
1161
1162                         for (int i = 3; i >= 0; i--)
1163                         {
1164                                 if (x.Data[i] == 0 && y.Data[i] == 0) 
1165                                         continue;
1166                                 else
1167                                         return new SqlBoolean (x.Data[i] > y.Data[i]);
1168                         }
1169                         return new SqlBoolean (false);
1170                 }
1171
1172                 public static SqlBoolean operator >= (SqlDecimal x, SqlDecimal y)
1173                 {
1174                         if (x.IsNull || y.IsNull)
1175                                 return SqlBoolean.Null;
1176
1177                         if (x.IsPositive != y.IsPositive)
1178                                 return new SqlBoolean (x.IsPositive);
1179
1180                         if (x.Scale > y.Scale)
1181                                 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1182                         else if (y.Scale > x.Scale)
1183                                 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1184
1185                         for (int i = 3; i >= 0; i -= 1)
1186                         {
1187                                 if (x.Data[i] == 0 && y.Data[i] == 0) 
1188                                         continue;
1189                                 else
1190                                         return new SqlBoolean (x.Data[i] >= y.Data[i]);
1191                         }
1192                         return new SqlBoolean (true);
1193                 }
1194
1195                 public static SqlBoolean operator != (SqlDecimal x, SqlDecimal y)
1196                 {
1197                         if (x.IsNull || y.IsNull) 
1198                                 return SqlBoolean.Null;
1199
1200                         if (x.IsPositive != y.IsPositive)
1201                                 return SqlBoolean.True;
1202
1203                         if (x.Scale > y.Scale)
1204                                 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1205                         else if (y.Scale > x.Scale)
1206                                 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1207
1208                         for (int i = 0; i < 4; i += 1)
1209                         {
1210                                 if (x.Data[i] != y.Data[i])
1211                                         return SqlBoolean.True;
1212                         }
1213                         return SqlBoolean.False;
1214                 }
1215
1216                 public static SqlBoolean operator < (SqlDecimal x, SqlDecimal y)
1217                 {
1218                         if (x.IsNull || y.IsNull) 
1219                                 return SqlBoolean.Null;
1220
1221                         if (x.IsPositive != y.IsPositive)
1222                                 return new SqlBoolean (y.IsPositive);
1223
1224                         if (x.Scale > y.Scale)
1225                                 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1226                         else if (y.Scale > x.Scale)
1227                                 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1228
1229                         for (int i = 3; i >= 0; i -= 1) {
1230                                 if (x.Data[i] == 0 && y.Data[i] == 0) 
1231                                         continue;
1232                                 return new SqlBoolean (x.Data[i] < y.Data[i]);
1233                         }
1234                         return new SqlBoolean (false);
1235                 }
1236
1237                 public static SqlBoolean operator <= (SqlDecimal x, SqlDecimal y)
1238                 {
1239                         if (x.IsNull || y.IsNull)
1240                                 return SqlBoolean.Null;
1241
1242                         if (x.IsPositive != y.IsPositive)
1243                                 return new SqlBoolean (y.IsPositive);
1244
1245                         if (x.Scale > y.Scale)
1246                                 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1247                         else if (y.Scale > x.Scale)
1248                                 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1249
1250                         for (int i = 3; i >= 0; i -= 1) {
1251                                 if (x.Data[i] == 0 && y.Data[i] == 0) 
1252                                         continue;
1253                                 else
1254                                         return new SqlBoolean (x.Data[i] <= y.Data[i]);
1255                         }
1256                         return new SqlBoolean (true);
1257                 }
1258
1259                 public static SqlDecimal operator * (SqlDecimal x, SqlDecimal y)
1260                 {
1261                         if (x.IsNull || y.IsNull)
1262                                 return SqlDecimal.Null;
1263
1264                         // set the precision to the greater of the two
1265                         byte resultPrecision = (byte)(x.Precision + y.Precision + 1);
1266                         byte resultScale = (byte)(x.Scale + y.Scale);
1267                         if (resultPrecision > MaxPrecision)
1268                                 resultPrecision = MaxPrecision;
1269
1270                         int[] xData = x.Data;
1271                         int[] yData = y.Data;
1272                         int[] resultBits = new int[4];
1273
1274                         ulong res; 
1275                         ulong carry = 0;
1276
1277                         for (int i=0; i<4; ++i) {
1278                                 res = 0;
1279                                 for (int j=i; j<=i; ++j)
1280                                         res += ((ulong)(uint) xData[j]) *  ((ulong)(uint) yData[i-j]);
1281                                 resultBits [i] = (int) ((res + carry) & UInt32.MaxValue);
1282                                 carry = res >> 32;
1283                         }
1284                         
1285                         // if we have carry left, then throw an exception
1286                         if (carry > 0)
1287                                 throw new OverflowException ();
1288                         else
1289                                 return new SqlDecimal (resultPrecision, resultScale, (x.IsPositive == y.IsPositive), resultBits);
1290                 }
1291
1292                 public static SqlDecimal operator - (SqlDecimal x, SqlDecimal y)
1293                 {
1294                         if (x.IsNull || y.IsNull)
1295                                 return SqlDecimal.Null;
1296
1297                         if (x.IsPositive && !y.IsPositive){
1298                                 y = new SqlDecimal (y.Precision, y.Scale, !y.IsPositive, y.Data);
1299                                 return x + y;
1300                         }
1301                         if (!x.IsPositive && y.IsPositive){
1302                                 x = new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
1303                                 x = (x + y);
1304                                 return new SqlDecimal (x.Precision, x.Scale, false, x.Data);
1305                         }
1306                         if (!x.IsPositive && !y.IsPositive){
1307                                 y = new SqlDecimal (y.Precision, y.Scale, !y.IsPositive, y.Data);
1308                                 x = new SqlDecimal(x.Precision, x.Scale, !x.IsPositive, x.Data);
1309                                 return (y - x);
1310                         }
1311                         // adjust the scale to the larger of the two beforehand
1312                         if (x.scale > y.scale)
1313                                 y = SqlDecimal.AdjustScale (y, x.scale - y.scale, false); 
1314                         else if (y.scale > x.scale)
1315                                 x = SqlDecimal.AdjustScale (x, y.scale - x.scale, false);
1316
1317                         //calculation of the new Precision for the result
1318                         byte resultPrecision = (byte)(Math.Max (x.Scale, y.Scale) +
1319                                         Math.Max (x.Precision - x.Scale, y.Precision - y.Scale));
1320
1321                         int[] op1_Data;
1322                         int[] op2_Data;
1323                         if (x >= y) {
1324                                 op1_Data = x.Data;
1325                                 op2_Data = y.Data;
1326                         } else {
1327                                 op1_Data = y.Data;
1328                                 op2_Data = x.Data;
1329                         }
1330
1331                         ulong res = 0;
1332                         int carry = 0;
1333                         int[] resultBits = new int[4];
1334
1335
1336                         /*
1337                          if ((uint)op2_Data [i] > (uint)op1_Data [i]) {
1338                                  carry = UInt32.MaxValue;
1339                                  op2_Data [i] = op2_Data [i] >> 1;
1340                          } else
1341                                  carr = 0;
1342                                 res = (uint)carry; +(ulong)((uint)op1_Data [i]) - (ulong)((uint)op2_Data [i]) 
1343                         */
1344
1345                         for (int i = 0; i < 4; i += 1) {
1346                                 res = (ulong)((uint)op1_Data [i]) - (ulong)((uint)op2_Data [i]) + (ulong)carry;
1347                                 carry = 0;
1348                                 if ((uint)op2_Data [i] > (uint)op1_Data [i])
1349                                         carry = -1;
1350                                 resultBits [i] = (int)res;
1351                         }
1352
1353                         if (carry > 0)
1354                                 throw new OverflowException ();
1355                         else
1356                                 return new SqlDecimal (resultPrecision, x.Scale, (x>=y).Value, resultBits);
1357                 }
1358
1359                 public static SqlDecimal operator - (SqlDecimal x)
1360                 {
1361                         return new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
1362                 }
1363
1364                 public static explicit operator SqlDecimal (SqlBoolean x)
1365                 {
1366                         if (x.IsNull)
1367                                 return Null;
1368                         else
1369                                 return new SqlDecimal ((decimal)x.ByteValue);
1370                 }
1371
1372                 public static explicit operator Decimal (SqlDecimal x)
1373                 {
1374                         return x.Value;
1375                 }
1376
1377                 public static explicit operator SqlDecimal (SqlDouble x)
1378                 {
1379                         checked {
1380                                 if (x.IsNull) 
1381                                         return Null;
1382                                 else
1383                                         return new SqlDecimal ((double)x.Value);
1384                         }
1385                 }
1386
1387                 public static explicit operator SqlDecimal (SqlSingle x)
1388                 {
1389                         checked {
1390                                 if (x.IsNull) 
1391                                         return Null;
1392                                 else
1393                                         return new SqlDecimal ((double)x.Value);
1394                         }
1395                 }
1396
1397                 public static explicit operator SqlDecimal (SqlString x)
1398                 {
1399                         checked {
1400                                 return Parse (x.Value);
1401                         }
1402                 }
1403
1404 #if NET_2_0
1405                 public static explicit operator SqlDecimal (double x)
1406                 {
1407                         return new SqlDecimal (x);
1408                 }
1409
1410                 public static implicit operator SqlDecimal (long x)
1411                 {
1412                         return new SqlDecimal (x);
1413                 }
1414 #endif
1415
1416                 public static implicit operator SqlDecimal (decimal x)
1417                 {
1418                         return new SqlDecimal (x);
1419                 }
1420
1421                 public static implicit operator SqlDecimal (SqlByte x)
1422                 {
1423                         if (x.IsNull)
1424                                 return Null;
1425                         else
1426                                 return new SqlDecimal ((decimal) x.Value);
1427                 }
1428
1429                 public static implicit operator SqlDecimal (SqlInt16 x)
1430                 {
1431                         if (x.IsNull)
1432                                 return Null;
1433                         else
1434                                 return new SqlDecimal ((decimal) x.Value);
1435                 }
1436
1437                 public static implicit operator SqlDecimal (SqlInt32 x)
1438                 {
1439                         if (x.IsNull)
1440                                 return Null;
1441                         else
1442                                 return new SqlDecimal ((decimal) x.Value);
1443                 }
1444
1445                 public static implicit operator SqlDecimal (SqlInt64 x)
1446                 {
1447                         if (x.IsNull)
1448                                 return Null;
1449                         else
1450                                 return new SqlDecimal ((decimal) x.Value);
1451                 }
1452
1453                 public static implicit operator SqlDecimal (SqlMoney x)
1454                 {
1455                         if (x.IsNull)
1456                                 return Null;
1457                         else
1458                                 return new SqlDecimal ((decimal) x.Value);
1459                 }
1460
1461 #if NET_2_0
1462                 public static XmlQualifiedName GetXsdType (XmlSchemaSet schemaSet)
1463                 {
1464                         if (schemaSet != null && schemaSet.Count == 0) {
1465                                 XmlSchema xs = new XmlSchema ();
1466                                 XmlSchemaComplexType ct = new XmlSchemaComplexType ();
1467                                 ct.Name = "decimal";
1468                                 xs.Items.Add (ct);
1469                                 schemaSet.Add (xs);
1470                         }
1471                         return new XmlQualifiedName ("decimal", "http://www.w3.org/2001/XMLSchema");
1472                 }
1473                 
1474                 XmlSchema IXmlSerializable.GetSchema ()
1475                 {
1476                         return null;
1477                 }
1478                 
1479                 void IXmlSerializable.ReadXml (XmlReader reader)
1480                 {
1481                         SqlDecimal retval;
1482
1483                         if (reader == null)
1484                                 return;
1485
1486                         switch (reader.ReadState) {
1487                         case ReadState.EndOfFile:
1488                         case ReadState.Error:
1489                         case ReadState.Closed:
1490                                 return;
1491                         }
1492
1493                         // Skip XML declaration and prolog
1494                         // or do I need to validate for the <SqlInt32> tag?
1495                         reader.MoveToContent ();
1496                         if (reader.EOF)
1497                                 return;
1498
1499                         reader.Read ();
1500                         if (reader.NodeType == XmlNodeType.EndElement)
1501                                 return;
1502
1503                         if (reader.Value.Length > 0) {
1504                                 if (String.Compare ("Null", reader.Value) == 0) {
1505                                         // means a null reference/invalid value
1506                                         notNull = false;
1507                                         return; 
1508                                 }
1509                                 // FIXME: do we need to handle the FormatException?
1510                                 retval = new SqlDecimal (Decimal.Parse (reader.Value));
1511
1512                                 // SqlDecimal.Data returns a clone'd array
1513                                 this.value = retval.Data; 
1514                                 this.notNull = true;
1515                                 this.scale = retval.Scale;
1516                                 this.precision = retval.Precision;
1517                                 this.positive = retval.IsPositive;
1518                         }
1519                 }
1520
1521                 void IXmlSerializable.WriteXml (XmlWriter writer)
1522                 {
1523                         writer.WriteString (this.Value.ToString ());
1524                 }
1525 #endif
1526
1527                 #endregion
1528         }
1529 }