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