2 // System.Data.SqlTypes.SqlDecimal
5 // Tim Coleman <tim@timcoleman.com>
6 // Ville Palo <vi64pa@koti.soon.fi>
8 // (C) Copyright 2002 Tim Coleman
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
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.
35 using Mono.Data.Tds.Protocol;
40 using System.Xml.Schema;
41 using System.Globalization;
42 using System.Xml.Serialization;
44 namespace System.Data.SqlTypes
47 [SerializableAttribute]
48 [XmlSchemaProvider ("GetXsdType")]
50 public struct SqlDecimal : INullable, IComparable
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};
75 public static readonly byte MaxPrecision = 38;
76 public static readonly byte MaxScale = 38;
78 // This should be 99999999999999999999999999999999999999
79 public static readonly SqlDecimal MaxValue = new SqlDecimal (MaxPrecision,
86 // This should be -99999999999999999999999999999999999999
87 public static readonly SqlDecimal MinValue = new SqlDecimal (MaxPrecision,
94 public static readonly SqlDecimal Null;
100 public SqlDecimal (decimal value)
102 int[] binData = Decimal.GetBits (value);
104 this.precision = MaxPrecision; // this value seems unclear
106 this.scale = (byte)(((uint)binData [3]) >> SCALE_SHIFT);
108 if (this.scale > MaxScale || ((uint)binData [3] & RESERVED_SS32_BITS) != 0)
109 throw new ArgumentException(Locale.GetText ("Invalid scale"));
111 this.value = new int[4];
112 this.value[0] = binData[0];
113 this.value[1] = binData[1];
114 this.value[2] = binData[2];
117 positive = (value >= 0);
119 precision = GetPrecision (value);
122 public SqlDecimal (double dVal) : this ((decimal) dVal)
125 int digits = 17 - precision;
127 n = AdjustScale (this, digits, false);
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;
137 public SqlDecimal (int value) : this ((decimal) value)
141 public SqlDecimal (long value) : this ((decimal) value)
145 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int[] bits) : this (bPrecision, bScale, fPositive, bits[0], bits[1], bits[2], bits[3])
149 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int data1, int data2, int data3, int data4)
151 this.precision = bPrecision;
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;
161 if (precision < scale)
162 throw new SqlTypeException (Locale.GetText ("Invalid presicion/scale combination."));
165 throw new SqlTypeException (Locale.GetText ("Invalid precision/scale combination."));
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 ");
176 public byte[] BinData {
178 byte [] b = new byte [value.Length * 4];
181 for (int i = 0; i < value.Length; i++) {
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);
196 throw new SqlNullValueException ();
197 // Data should always return clone, not to be modified
198 int [] ret = new int [4];
208 get { return !notNull; }
211 public bool IsPositive {
212 get { return positive; }
215 public byte Precision {
216 get { return precision; }
220 get { return scale; }
223 public decimal Value {
226 throw new SqlNullValueException ();
228 if (this.value[3] > 0)
229 throw new OverflowException ();
231 return new decimal (value[0], value[1], value[2], !positive, scale);
239 public static SqlDecimal Abs (SqlDecimal n)
243 return new SqlDecimal (n.Precision, n.Scale, true, n.Data);
246 public static SqlDecimal Add (SqlDecimal x, SqlDecimal y)
251 public static SqlDecimal AdjustScale (SqlDecimal n, int digits, bool fRound)
253 byte prec = n.Precision;
255 throw new SqlNullValueException ();
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++)
270 if (n.Scale < Math.Abs (digits))
271 throw new SqlTruncateException ();
274 n = Round (n, digits + n.scale);
276 n = Round (Truncate (n, digits + n.scale), digits + n.scale);
280 return new SqlDecimal (prec, scale, n.positive, n.Data);
283 public static SqlDecimal Ceiling (SqlDecimal n)
287 return AdjustScale (n, -(n.Scale), true);
290 public int CompareTo (object value)
294 if (!(value is SqlDecimal))
295 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlDecimal"));
297 return CompareTo ((SqlDecimal) value);
303 int CompareTo (SqlDecimal value)
308 return this.Value.CompareTo (value.Value);
311 public static SqlDecimal ConvertToPrecScale (SqlDecimal n, int precision, int scale)
313 int prec = n.Precision;
315 n = AdjustScale (n, scale-n.scale, true);
316 if ((n.Scale >= sc) && (precision < n.Precision))
317 throw new SqlTruncateException ();
320 return new SqlDecimal ((byte)prec, n.scale, n.IsPositive, n.Data);
324 public static SqlDecimal Divide (SqlDecimal x, SqlDecimal y)
329 public override bool Equals (object value)
331 if (!(value is SqlDecimal))
333 else if (this.IsNull)
334 return ((SqlDecimal)value).IsNull;
335 else if (((SqlDecimal)value).IsNull)
338 return (bool) (this == (SqlDecimal)value);
341 public static SqlBoolean Equals (SqlDecimal x, SqlDecimal y)
346 public static SqlDecimal Floor (SqlDecimal n)
348 return AdjustScale (n, -(n.Scale), false);
352 internal static SqlDecimal FromTdsBigDecimal (TdsBigDecimal x)
357 return new SqlDecimal (x.Precision, x.Scale, !x.IsNegative, x.Data);
361 public override int GetHashCode ()
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;
374 public static SqlBoolean GreaterThan (SqlDecimal x, SqlDecimal y)
379 public static SqlBoolean GreaterThanOrEqual (SqlDecimal x, SqlDecimal y)
384 public static SqlBoolean LessThan (SqlDecimal x, SqlDecimal y)
389 public static SqlBoolean LessThanOrEqual (SqlDecimal x, SqlDecimal y)
394 public static SqlDecimal Multiply (SqlDecimal x, SqlDecimal y)
399 public static SqlBoolean NotEquals (SqlDecimal x, SqlDecimal y)
404 public static SqlDecimal Parse (string s)
407 throw new ArgumentNullException (Locale.GetText ("string s"));
409 return new SqlDecimal (Decimal.Parse (s));
412 public static SqlDecimal Power (SqlDecimal n, double exp)
415 return SqlDecimal.Null;
417 return new SqlDecimal (Math.Pow (n.ToDouble (), exp));
420 public static SqlDecimal Round (SqlDecimal n, int position)
423 throw new SqlNullValueException ();
426 d = Decimal.Round (d, position);
427 return new SqlDecimal (d);
430 public static SqlInt32 Sign (SqlDecimal n)
433 return SqlInt32.Null;
434 return (SqlInt32) (n.IsPositive ? 1 : -1);
437 public static SqlDecimal Subtract (SqlDecimal x, SqlDecimal y)
442 private byte GetPrecision (decimal value)
444 string str = value.ToString ();
447 foreach (char c in str) {
449 if (c >= '0' && c <= '9')
456 public double ToDouble ()
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);
468 public SqlBoolean ToSqlBoolean ()
470 return ((SqlBoolean) this);
473 public SqlByte ToSqlByte ()
475 return ((SqlByte) this);
478 public SqlDouble ToSqlDouble ()
480 return ((SqlDouble) this);
483 public SqlInt16 ToSqlInt16 ()
485 return ((SqlInt16) this);
488 public SqlInt32 ToSqlInt32 ()
490 return ((SqlInt32) this);
493 public SqlInt64 ToSqlInt64 ()
495 return ((SqlInt64) this);
498 public SqlMoney ToSqlMoney ()
500 return ((SqlMoney) this);
503 public SqlSingle ToSqlSingle ()
505 return ((SqlSingle) this);
508 public SqlString ToSqlString ()
510 return ((SqlString) this);
513 public override string ToString ()
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);
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 ());
531 while (Result.Length > this.Precision)
532 Result.Remove (Result.Length - 1, 1);
535 Result.Insert (Result.Length - this.Scale, ".");
538 Result.Insert (0, '-');
540 return Result.ToString ();
544 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider)
547 return Div128By32 (ref hi, ref lo, divider, ref t);
551 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider, ref uint rest)
557 a = (uint)(hi >> 32);
565 hi = b << 32 | (uint)c;
567 a |= (uint)(lo >> 32);
574 lo = b << 32 | (uint)c;
578 return (a > divider || (a == divider && (c & 1) == 1)) ? 1 : 0;
582 [MonoTODO("Find out what is the right way to set scale and precision")]
583 private static SqlDecimal DecimalDiv (SqlDecimal x, SqlDecimal y)
589 byte prec = 0; // precision
590 bool positive = ! (x.positive ^ y.positive);
592 prec = x.Precision >= y.Precision ? x.Precision : y.Precision;
593 DecimalDivSub (ref x, ref y, ref lo, ref hi, ref texp);
595 sc = x.Scale - y.Scale;
597 Rescale128 (ref lo, ref hi, ref sc, texp, 0, 38, 1);
601 Div128By32(ref hi, ref lo, 10, ref r);
608 while ((((double)hi) * Math.Pow(2,64) + lo) - Math.Pow (10, prec) > 0)
611 while ((prec + sc) > MaxScale) {
612 Div128By32(ref hi, ref lo, 10, ref r);
618 int resultLo = (int) lo;
619 int resultMi = (int) (lo >> 32);
620 int resultMi2 = (int) (hi);
621 int resultHi = (int) (hi >> 32);
623 return new SqlDecimal (prec, (byte) sc, positive, resultLo,
629 private static void Rescale128 (ref ulong clo, ref ulong chi,
630 ref int scale, int texp,
631 int minScale, int maxScale,
643 while (texp > 0 && sc <= maxScale) {
644 overhang = (uint)(chi >> 64);
645 while (texp > 0 && (((clo & 1) == 0) || overhang > 0)) {
647 roundBit = (int)(clo & 1);
648 RShift128 (ref clo, ref chi);
650 overhang = (uint)(chi >> 32);
653 if (texp > DECIMAL_MAX_INTFACTORS)
654 i = DECIMAL_MAX_INTFACTORS;
658 if (sc + i > maxScale)
668 factor = constantsDecadeInt32Factors [i] >> i;
669 Mult128By32 (ref clo, ref chi, factor, 0);
674 roundBit = (int)(clo & 1);
675 RShift128 (ref clo, ref chi);
679 while (sc > maxScale) {
680 i = scale - maxScale;
681 if (i > DECIMAL_MAX_INTFACTORS)
682 i = DECIMAL_MAX_INTFACTORS;
684 roundBit = Div128By32 (ref clo, ref chi,
685 constantsDecadeInt32Factors[i]);
688 while (sc < minScale) {
692 if (i > DECIMAL_MAX_INTFACTORS)
693 i = DECIMAL_MAX_INTFACTORS;
695 Mult128By32 (ref clo, ref chi,
696 constantsDecadeInt32Factors[i], roundBit);
700 Normalize128 (ref clo, ref chi, ref sc, roundFlag, roundBit);
704 private static void Normalize128(ref ulong clo, ref ulong chi, ref int scale, int roundFlag, int roundBit)
709 if ((roundFlag != 0) && (roundBit != 0))
710 RoundUp128 (ref clo, ref chi);
714 private static void RoundUp128(ref ulong lo, ref ulong hi)
721 private static void DecimalDivSub (ref SqlDecimal x, ref SqlDecimal y, ref ulong clo, ref ulong chi, ref int exp)
735 xhi = (ulong) ((ulong) x.Data [3] << 32) | (ulong) x.Data [2];
736 xmi = (ulong) ((ulong) x.Data [1] << 32) | (ulong) x.Data [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];
743 if (ylo == 0 && ymi == 0 && ymi2 == 0 && yhi == 0)
744 throw new DivideByZeroException ();
746 if (xmi == 0 && xhi == 0) {
751 // enlarge dividend to get maximal precision
752 for (ashift = 0; (xhi & LIT_GUINT64_HIGHBIT) == 0; ++ashift)
753 LShift128 (ref xmi, ref xhi);
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);
759 thi = ((ulong)yhi) << 32 | (ulong)ymi2;
760 tmi = ((ulong)ymi) << 32 | (ulong)ylo;
763 if (xhi > thi || (xhi == thi && xmi >=tmi)) {
764 Sub192(xlo, xmi, xhi, tlo, tmi, thi, ref xlo, ref xmi, ref xhi);
770 Div192By128To128 (xlo, xmi, xhi, ylo, ymi, ymi2, yhi, ref clo, ref chi);
772 exp = 128 + ashift - bshift;
775 RShift128 (ref clo, ref chi);
776 chi += LIT_GUINT64_HIGHBIT;
780 // try loss free right shift
781 while (exp > 0 && (clo & 1) == 0) {
782 RShift128 (ref clo, ref chi);
789 private static void RShift192(ref ulong lo, ref ulong mi, ref ulong hi)
793 lo |= LIT_GUINT64_HIGHBIT;
797 mi |= LIT_GUINT64_HIGHBIT;
804 private static void RShift128(ref ulong lo, ref ulong hi)
808 lo |= LIT_GUINT64_HIGHBIT;
813 private static void LShift128(ref ulong lo, ref ulong hi)
817 if ((lo & LIT_GUINT64_HIGHBIT) != 0)
824 private static void LShift128(ref uint lo, ref uint mi, ref uint mi2, ref uint hi)
827 if ((mi2 & LIT_GUINT32_HIGHBIT) != 0)
831 if ((mi & LIT_GUINT32_HIGHBIT) != 0)
835 if ((lo & LIT_GUINT32_HIGHBIT) != 0)
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)
846 ulong rlo, rmi, rhi; // remainders
853 h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
856 rhi = (rhi << 32) | (rmi >> 32);
857 rmi = (rmi << 32) | (rlo >> 32);
860 chi = (((ulong)h) << 32) | Div192By128To32WithRest (
861 ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
864 rhi = (rhi << 32) | (rmi >> 32);
865 rmi = (rmi << 32) | (rlo >> 32);
868 h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi,
869 ylo, ymi, ymi2, yhi);
871 // estimate lowest 32 bit (two last bits may be wrong)
876 c = (uint)(rhi / yhi);
879 clo = (((ulong)h) << 32) | 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)
887 ulong rlo, rmi, rhi; // remainder
896 if (rhi >= (((ulong)yhi << 32)))
899 c = (uint) (rhi / yhi);
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);
904 while (((long)rhi) < 0) {
906 Add192 (rlo, rmi, rhi, 0, (((ulong)ymi) << 32) | ylo, yhi | ymi2, ref rlo, ref rmi, ref rhi);
917 private static void Mult192By32 (ref ulong clo, ref ulong cmi, ref ulong chi, ulong factor, int roundBit)
923 a = ((ulong)(uint)clo) * factor;
930 a += (clo >> 32) * factor;
933 clo = ((ulong)h1) << 32 | h0;
936 a += ((ulong)(uint)cmi) * factor;
940 a += (cmi >> 32) * factor;
943 cmi = ((ulong)h1) << 32 | h0;
945 a += ((ulong)(uint)chi) * factor;
949 a += (chi >> 32) * factor;
951 chi = ((ulong)h1) << 32 | h0;
956 private static void Mult128By32 (ref ulong clo, ref ulong chi, uint factor, int roundBit)
962 a = ((ulong)(uint)clo) * factor;
970 a += (clo >> 32) * factor;
973 clo = ((ulong)h1) << 32 | h0;
976 a += ((ulong)(uint)chi) * factor;
980 a += (chi >> 32) * factor;
983 chi = ((ulong)h1) << 32 | h0;
987 private static void Mult128By32To128(uint xlo, uint xmi, uint xmi2, uint xhi,
988 uint factor, ref ulong clo, ref ulong chi)
993 a = ((ulong)xlo) * factor;
997 a += ((ulong)xmi) * factor;
1001 a += ((ulong)xmi2) * factor;
1005 a += ((ulong)xhi) * factor;
1007 clo = ((ulong)h1) << 32 | h0;
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)
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)
1062 public static SqlDecimal Truncate (SqlDecimal n, int position)
1064 int diff = n.scale - position;
1067 int [] data = n.Data;
1068 decimal d = new decimal (data [0], data [1], data [2], !n.positive, 0);
1070 for (int i = 0; i < diff; i++, x *= 10)
1072 data = Decimal.GetBits (d);
1074 return new SqlDecimal (n.precision, n.scale, n.positive, data);
1077 public static SqlDecimal operator + (SqlDecimal x, SqlDecimal y)
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);
1086 if (!x.IsPositive && y.IsPositive){
1087 x = new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
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);
1094 return new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
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);
1102 byte resultPrecision = (byte)(Math.Max (x.Scale, y.Scale) +
1103 Math.Max (x.Precision - x.Scale, y.Precision - y.Scale) + 1);
1105 if (resultPrecision > MaxPrecision)
1106 resultPrecision = MaxPrecision;
1108 int [] xData = x.Data;
1109 int [] yData = y.Data;
1110 int [] resultBits = new int[4];
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));
1120 throw new OverflowException ();
1122 return new SqlDecimal (resultPrecision, x.Scale, x.IsPositive, resultBits);
1125 public static SqlDecimal operator / (SqlDecimal x, SqlDecimal y)
1127 if (x.IsNull || y.IsNull)
1128 return SqlDecimal.Null;
1130 return DecimalDiv (x, y);
1133 public static SqlBoolean operator == (SqlDecimal x, SqlDecimal y)
1135 if (x.IsNull || y.IsNull)
1136 return SqlBoolean.Null;
1138 if (x.IsPositive != y.IsPositive)
1139 return SqlBoolean.False;
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);
1146 for (int i = 0; i < 4; i += 1)
1147 if (x.Data[i] != y.Data[i])
1148 return SqlBoolean.False;
1150 return SqlBoolean.True;
1153 public static SqlBoolean operator > (SqlDecimal x, SqlDecimal y)
1155 if (x.IsNull || y.IsNull)
1156 return SqlBoolean.Null;
1158 if (x.IsPositive != y.IsPositive)
1159 return new SqlBoolean (x.IsPositive);
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);
1166 for (int i = 3; i >= 0; i--)
1168 if (x.Data[i] == 0 && y.Data[i] == 0)
1171 return new SqlBoolean (x.Data[i] > y.Data[i]);
1173 return new SqlBoolean (false);
1176 public static SqlBoolean operator >= (SqlDecimal x, SqlDecimal y)
1178 if (x.IsNull || y.IsNull)
1179 return SqlBoolean.Null;
1181 if (x.IsPositive != y.IsPositive)
1182 return new SqlBoolean (x.IsPositive);
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);
1189 for (int i = 3; i >= 0; i -= 1)
1191 if (x.Data[i] == 0 && y.Data[i] == 0)
1194 return new SqlBoolean (x.Data[i] >= y.Data[i]);
1196 return new SqlBoolean (true);
1199 public static SqlBoolean operator != (SqlDecimal x, SqlDecimal y)
1201 if (x.IsNull || y.IsNull)
1202 return SqlBoolean.Null;
1204 if (x.IsPositive != y.IsPositive)
1205 return SqlBoolean.True;
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);
1212 for (int i = 0; i < 4; i += 1)
1214 if (x.Data[i] != y.Data[i])
1215 return SqlBoolean.True;
1217 return SqlBoolean.False;
1220 public static SqlBoolean operator < (SqlDecimal x, SqlDecimal y)
1222 if (x.IsNull || y.IsNull)
1223 return SqlBoolean.Null;
1225 if (x.IsPositive != y.IsPositive)
1226 return new SqlBoolean (y.IsPositive);
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);
1233 for (int i = 3; i >= 0; i -= 1) {
1234 if (x.Data[i] == 0 && y.Data[i] == 0)
1236 return new SqlBoolean (x.Data[i] < y.Data[i]);
1238 return new SqlBoolean (false);
1241 public static SqlBoolean operator <= (SqlDecimal x, SqlDecimal y)
1243 if (x.IsNull || y.IsNull)
1244 return SqlBoolean.Null;
1246 if (x.IsPositive != y.IsPositive)
1247 return new SqlBoolean (y.IsPositive);
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);
1254 for (int i = 3; i >= 0; i -= 1) {
1255 if (x.Data[i] == 0 && y.Data[i] == 0)
1258 return new SqlBoolean (x.Data[i] <= y.Data[i]);
1260 return new SqlBoolean (true);
1263 public static SqlDecimal operator * (SqlDecimal x, SqlDecimal y)
1265 if (x.IsNull || y.IsNull)
1266 return SqlDecimal.Null;
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;
1274 int[] xData = x.Data;
1275 int[] yData = y.Data;
1276 int[] resultBits = new int[4];
1281 for (int i=0; i<4; ++i) {
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);
1289 // if we have carry left, then throw an exception
1291 throw new OverflowException ();
1293 return new SqlDecimal (resultPrecision, resultScale, (x.IsPositive == y.IsPositive), resultBits);
1296 public static SqlDecimal operator - (SqlDecimal x, SqlDecimal y)
1298 if (x.IsNull || y.IsNull)
1299 return SqlDecimal.Null;
1301 if (x.IsPositive && !y.IsPositive){
1302 y = new SqlDecimal (y.Precision, y.Scale, !y.IsPositive, y.Data);
1305 if (!x.IsPositive && y.IsPositive){
1306 x = new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
1308 return new SqlDecimal (x.Precision, x.Scale, false, x.Data);
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);
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);
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));
1337 int[] resultBits = new int[4];
1341 if ((uint)op2_Data [i] > (uint)op1_Data [i]) {
1342 carry = UInt32.MaxValue;
1343 op2_Data [i] = op2_Data [i] >> 1;
1346 res = (uint)carry; +(ulong)((uint)op1_Data [i]) - (ulong)((uint)op2_Data [i])
1349 for (int i = 0; i < 4; i += 1) {
1350 res = (ulong)((uint)op1_Data [i]) - (ulong)((uint)op2_Data [i]) + (ulong)carry;
1352 if ((uint)op2_Data [i] > (uint)op1_Data [i])
1354 resultBits [i] = (int)res;
1358 throw new OverflowException ();
1360 return new SqlDecimal (resultPrecision, x.Scale, (x>=y).Value, resultBits);
1363 public static SqlDecimal operator - (SqlDecimal x)
1365 return new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
1368 public static explicit operator SqlDecimal (SqlBoolean x)
1373 return new SqlDecimal ((decimal)x.ByteValue);
1376 public static explicit operator Decimal (SqlDecimal x)
1381 public static explicit operator SqlDecimal (SqlDouble x)
1387 return new SqlDecimal ((double)x.Value);
1391 public static explicit operator SqlDecimal (SqlSingle x)
1397 return new SqlDecimal ((double)x.Value);
1401 public static explicit operator SqlDecimal (SqlString x)
1404 return Parse (x.Value);
1409 public static explicit operator SqlDecimal (double x)
1411 return new SqlDecimal (x);
1414 public static implicit operator SqlDecimal (long x)
1416 return new SqlDecimal (x);
1420 public static implicit operator SqlDecimal (decimal x)
1422 return new SqlDecimal (x);
1425 public static implicit operator SqlDecimal (SqlByte x)
1430 return new SqlDecimal ((decimal) x.Value);
1433 public static implicit operator SqlDecimal (SqlInt16 x)
1438 return new SqlDecimal ((decimal) x.Value);
1441 public static implicit operator SqlDecimal (SqlInt32 x)
1446 return new SqlDecimal ((decimal) x.Value);
1449 public static implicit operator SqlDecimal (SqlInt64 x)
1454 return new SqlDecimal ((decimal) x.Value);
1457 public static implicit operator SqlDecimal (SqlMoney x)
1462 return new SqlDecimal ((decimal) x.Value);
1466 public static XmlQualifiedName GetXsdType (XmlSchemaSet schemaSet)
1468 if (schemaSet != null && schemaSet.Count == 0) {
1469 XmlSchema xs = new XmlSchema ();
1470 XmlSchemaComplexType ct = new XmlSchemaComplexType ();
1471 ct.Name = "decimal";
1475 return new XmlQualifiedName ("decimal", "http://www.w3.org/2001/XMLSchema");
1478 XmlSchema IXmlSerializable.GetSchema ()
1483 void IXmlSerializable.ReadXml (XmlReader reader)
1490 switch (reader.ReadState) {
1491 case ReadState.EndOfFile:
1492 case ReadState.Error:
1493 case ReadState.Closed:
1497 // Skip XML declaration and prolog
1498 // or do I need to validate for the <SqlInt32> tag?
1499 reader.MoveToContent ();
1504 if (reader.NodeType == XmlNodeType.EndElement)
1507 if (reader.Value.Length > 0) {
1508 if (String.Compare ("Null", reader.Value) == 0) {
1509 // means a null reference/invalid value
1513 // FIXME: do we need to handle the FormatException?
1514 retval = new SqlDecimal (Decimal.Parse (reader.Value));
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;
1525 void IXmlSerializable.WriteXml (XmlWriter writer)
1527 writer.WriteString (this.Value.ToString ());