2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.Data / System.Data.SqlTypes / SqlDecimal.cs
index 96f527ccaac9eac2d77cffd023d5a1a1a79f0e85..85e33561c69900eaabfafab059244793f1846237 100644 (file)
@@ -8,6 +8,29 @@
 // (C) Copyright 2002 Tim Coleman
 //
 
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
 using Mono.Data.Tds.Protocol;
 using System;
 using System.Text;
@@ -120,9 +143,12 @@ namespace System.Data.SqlTypes
                        this.value[2] = data3;
                        this.value[3] = data4;
                        notNull = true;
-                       
+
                        if (precision < scale)
-                               throw new ArgumentException(Locale.GetText ("Invalid scale"));
+                               throw new SqlTypeException (Locale.GetText ("Invalid presicion/scale combination."));
+
+                       if (precision > 38)
+                               throw new SqlTypeException (Locale.GetText ("Invalid precision/scale combination."));
 
                        if (this.ToDouble () > (Math.Pow (10, 38) - 1)  || 
                            this.ToDouble () < -(Math.Pow (10, 38)))
@@ -160,6 +186,7 @@ namespace System.Data.SqlTypes
                                ret [0] = value [0];
                                ret [1] = value [1];
                                ret [2] = value [2];
+                               ret [3] = value [3];
                                return ret;
                        }
                }
@@ -198,9 +225,9 @@ namespace System.Data.SqlTypes
 
                public static SqlDecimal Abs (SqlDecimal n)
                {
-                               return new SqlDecimal (n.Precision, n.Scale, true, 
-                                                      n.BinData [0], n.BinData [1], 
-                                                      n.BinData [2], n.BinData [3]);
+                       if (!n.notNull)
+                               return n;
+                       return new SqlDecimal (n.Precision, n.Scale, true, n.Data);
                }
 
                public static SqlDecimal Add (SqlDecimal x, SqlDecimal y)
@@ -216,7 +243,9 @@ namespace System.Data.SqlTypes
 
                        int [] data;
                        byte newScale;
-                       if (digits > 0) {
+                       if (digits == 0)
+                               return n;
+                       else if (digits > 0) {
                                prec = (byte)(prec + digits);
                                decimal d = n.Value;
                                if (digits > 0)
@@ -229,7 +258,7 @@ namespace System.Data.SqlTypes
                                if (fRound)
                                        n = Round (n, digits + n.scale);
                                else
-                                       n = Truncate (n, digits + n.scale);
+                                       n = Round (Truncate (n, digits + n.scale), digits + n.scale);
                                data = n.Data;
                                newScale = n.scale;
                        }
@@ -239,6 +268,8 @@ namespace System.Data.SqlTypes
 
                public static SqlDecimal Ceiling (SqlDecimal n)
                {
+                       if (!n.notNull)
+                               return n;
                        return AdjustScale (n, -(n.Scale), true);
                }
 
@@ -256,7 +287,9 @@ namespace System.Data.SqlTypes
 
                public static SqlDecimal ConvertToPrecScale (SqlDecimal n, int precision, int scale)
                {
-                       return new SqlDecimal ((byte)precision, (byte)scale, n.IsPositive, n.Data);
+//                     return new SqlDecimal ((byte)precision, (byte)scale, n.IsPositive, n.Data);
+                       // FIXME: precision
+                       return AdjustScale (n, scale - n.scale, true);
                }
 
                public static SqlDecimal Divide (SqlDecimal x, SqlDecimal y)
@@ -480,6 +513,9 @@ namespace System.Data.SqlTypes
                        if (this.Scale > 0)
                                Result.Insert (Result.Length - this.Scale, ".");
 
+                       if (!positive)
+                               Result.Insert (0, '-');
+
                        return Result.ToString ();
                }
 
@@ -531,6 +567,7 @@ namespace System.Data.SqlTypes
                        int texp = 0;
                        int rc = 0;
                        byte prec = 0; // precision
+                       bool positive = ! (x.positive ^ y.positive);
 
                        prec = x.Precision >= y.Precision ? x.Precision : y.Precision;
                        DecimalDivSub (ref x, ref y, ref lo, ref hi, ref texp);
@@ -563,7 +600,7 @@ namespace System.Data.SqlTypes
                        int resultMi2 = (int)(hi);
                        int resultHi = (int)(hi >> 32);
 
-                       return new SqlDecimal (prec, (byte)sc, true, resultLo,
+                       return new SqlDecimal (prec, (byte)sc, positive, resultLo,
                                                       resultMi, resultMi2,
                                                       resultHi);
                }
@@ -613,9 +650,9 @@ namespace System.Data.SqlTypes
 
                                        // 10^i/2^i=5^i 
                                        factor = constantsDecadeInt32Factors [i] >> i; 
-                                       System.Console.WriteLine ("***");
+//                                     System.Console.WriteLine ("***");
                                        Mult128By32 (ref clo, ref chi, factor, 0);
-                                       System.Console.WriteLine ((((double)chi) * Math.Pow (2,64) + clo));
+//                                     System.Console.WriteLine ((((double)chi) * Math.Pow (2,64) + clo));
 
                                }
 
@@ -1030,12 +1067,12 @@ namespace System.Data.SqlTypes
                        // if one of them is negative, perform subtraction
                        if (x.IsPositive && !y.IsPositive) return x - y;
                        if (y.IsPositive && !x.IsPositive) return y - x;
-               
-                       // adjust the scale to the smaller of the two beforehand
-                       if (x.Scale > y.Scale)
-                               x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
-                       else if (y.Scale > x.Scale)
-                               y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
+
+                       // adjust the scale to the larger of the two beforehand
+                       if (x.scale > y.scale)
+                               y = SqlDecimal.AdjustScale (y, x.scale - y.scale, true); // FIXME: should be false (fix it after AdjustScale(,,false) is fixed)
+                       else if (y.scale > x.scale)
+                               x = SqlDecimal.AdjustScale (x, y.scale - x.scale, true); // FIXME: should be false (fix it after AdjustScale(,,false) is fixed)
 
                        // set the precision to the greater of the two
                        byte resultPrecision;