// (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.
+//
+
+#if !TARGET_JVM
using Mono.Data.Tds.Protocol;
+#endif
using System;
+using System.Xml;
using System.Text;
+using System.Xml.Schema;
using System.Globalization;
+using System.Xml.Serialization;
namespace System.Data.SqlTypes
{
+#if NET_2_0
+ [SerializableAttribute]
+ [XmlSchemaProvider ("GetXsdType")]
+#endif
public struct SqlDecimal : INullable, IComparable
+#if NET_2_0
+ , IXmlSerializable
+#endif
{
#region Fields
const ulong LIT_GUINT64_HIGHBIT = 0x8000000000000000;
const ulong LIT_GUINT32_HIGHBIT = 0x80000000;
const byte DECIMAL_MAX_INTFACTORS = 9;
- static uint [] constantsDecadeInt32Factors = new uint [10]
- {
- 1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u,
- 10000000u, 100000000u, 1000000000u
- };
+ static uint [] constantsDecadeInt32Factors = new uint [10] {
+ 1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u,
+ 10000000u, 100000000u, 1000000000u};
public static readonly byte MaxPrecision = 38;
public static readonly byte MaxScale = 38;
// This should be -99999999999999999999999999999999999999
public static readonly SqlDecimal MinValue = new SqlDecimal (MaxPrecision,
(byte)0, false,
- -1,
+ -1,
160047679,
- 1518781562,
+ 1518781562,
1262177448);
public static readonly SqlDecimal Null;
#region Constructors
- public SqlDecimal (decimal value)
+ public SqlDecimal (decimal value)
{
int[] binData = Decimal.GetBits (value);
this.value[2] = binData[2];
this.value[3] = 0;
- if (value >= 0)
- positive = true;
- else
- positive = false;
-
+ positive = (value >= 0);
notNull = true;
precision = GetPrecision (value);
}
-
- public SqlDecimal (double value) : this ((decimal)value)
+
+ public SqlDecimal (double dVal) : this ((decimal) dVal)
{
SqlDecimal n = this;
int digits = 17 - precision;
this.scale = n.scale;
this.value = n.value;
}
- public SqlDecimal (int value) : this ((decimal)value) { }
- public SqlDecimal (long value) : this ((decimal)value) { }
- public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int[] bits) : this (bPrecision, bScale, fPositive, bits[0], bits[1], bits[2], bits[3]) { }
+ public SqlDecimal (int value) : this ((decimal) value)
+ {
+ }
- public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int data1, int data2, int data3, int data4)
+ public SqlDecimal (long value) : this ((decimal) value)
+ {
+ }
+
+ public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int[] bits) : this (bPrecision, bScale, fPositive, bits[0], bits[1], bits[2], bits[3])
+ {
+ }
+
+ public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int data1, int data2, int data3, int data4)
{
this.precision = bPrecision;
this.scale = bScale;
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 (this.ToDouble () > (Math.Pow (10, 38) - 1) ||
+ 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)))
- throw new SqlTypeException ("Can't convert to SqlDecimal, Out of range ");
+ throw new OverflowException ("Can't convert to SqlDecimal, Out of range ");
}
#endregion
#region Properties
public byte[] BinData {
- get {
-
+ get {
byte [] b = new byte [value.Length * 4];
int j = 0;
}
}
- public int[] Data {
- get {
+ public int[] Data {
+ get {
if (this.IsNull)
throw new SqlNullValueException ();
// Data should always return clone, not to be modified
ret [0] = value [0];
ret [1] = value [1];
ret [2] = value [2];
+ ret [3] = value [3];
return ret;
}
}
- public bool IsNull {
+ public bool IsNull {
get { return !notNull; }
}
- public bool IsPositive {
+ public bool IsPositive {
get { return positive; }
}
- public byte Precision {
+ public byte Precision {
get { return precision; }
}
- public byte Scale {
+ public byte Scale {
get { return scale; }
}
- public decimal Value {
- get {
+ public decimal Value {
+ get {
if (this.IsNull)
throw new SqlNullValueException ();
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)
public static SqlDecimal AdjustScale (SqlDecimal n, int digits, bool fRound)
{
- byte prec = n.Precision;
+ byte prec = n.Precision;
if (n.IsNull)
throw new SqlNullValueException ();
- int [] data;
- byte newScale;
- if (digits > 0) {
- prec = (byte)(prec + digits);
- decimal d = n.Value;
- if (digits > 0)
- for (int i = 0; i < digits; i++)
- d *= 10;
- data = Decimal.GetBits (d);
- data [3] = 0;
- newScale = (byte) (n.scale + digits);
+ byte scale;
+ if (digits == 0)
+ return n;
+ else if (digits > 0) {
+ prec = (byte)(prec + digits);
+ scale = (byte) (n.scale + digits);
+ // use Math.Pow once the Ctr (double) is fixed to handle
+ // values greater than Decimal.MaxValue
+ // the current code creates too many sqldecimal objects
+ //n = n * (new SqlDecimal ((double)Math.Pow (10, digits)));
+ for (int i = 0; i < digits; i++)
+ n *= 10;
} else {
+ if (n.Scale < Math.Abs (digits))
+ throw new SqlTruncateException ();
+
if (fRound)
n = Round (n, digits + n.scale);
else
- n = Truncate (n, digits + n.scale);
- data = n.Data;
- newScale = n.scale;
+ n = Round (Truncate (n, digits + n.scale), digits + n.scale);
+ scale = n.scale;
}
- return new SqlDecimal (prec, newScale, n.positive, data);
+ return new SqlDecimal (prec, scale, n.positive, n.Data);
}
public static SqlDecimal Ceiling (SqlDecimal n)
{
+ if (!n.notNull)
+ return n;
return AdjustScale (n, -(n.Scale), true);
}
{
if (value == null)
return 1;
- else if (!(value is SqlDecimal))
+ if (!(value is SqlDecimal))
throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlDecimal"));
- else if (((SqlDecimal)value).IsNull)
+
+ return CompareTo ((SqlDecimal) value);
+ }
+
+#if NET_2_0
+ public
+#endif
+ int CompareTo (SqlDecimal value)
+ {
+ if (value.IsNull)
return 1;
else
- return this.Value.CompareTo (((SqlDecimal)value).Value);
+ return this.Value.CompareTo (value.Value);
}
public static SqlDecimal ConvertToPrecScale (SqlDecimal n, int precision, int scale)
{
- return new SqlDecimal ((byte)precision, (byte)scale, n.IsPositive, n.Data);
+ int prec = n.Precision;
+ int sc = n.Scale;
+ n = AdjustScale (n, scale-n.scale, true);
+ if ((n.Scale >= sc) && (precision < n.Precision))
+ throw new SqlTruncateException ();
+ else{
+ prec = precision;
+ return new SqlDecimal ((byte)prec, n.scale, n.IsPositive, n.Data);
+ }
}
public static SqlDecimal Divide (SqlDecimal x, SqlDecimal y)
{
if (!(value is SqlDecimal))
return false;
- else if (this.IsNull && ((SqlDecimal)value).IsNull)
- return true;
+ else if (this.IsNull)
+ return ((SqlDecimal)value).IsNull;
else if (((SqlDecimal)value).IsNull)
return false;
else
return AdjustScale (n, -(n.Scale), false);
}
+#if !TARGET_JVM
internal static SqlDecimal FromTdsBigDecimal (TdsBigDecimal x)
{
if (x == null)
else
return new SqlDecimal (x.Precision, x.Scale, !x.IsNegative, x.Data);
}
+#endif
public override int GetHashCode ()
{
result = 91 * result + this.Data[1];
result = 91 * result + this.Data[2];
result = 91 * result + this.Data[3];
- result = 91 * result + (int)this.Scale;
- result = 91 * result + (int)this.Precision;
+ result = 91 * result + (int) this.Scale;
+ result = 91 * result + (int) this.Precision;
return result;
}
{
if (s == null)
throw new ArgumentNullException (Locale.GetText ("string s"));
- else
+ else
return new SqlDecimal (Decimal.Parse (s));
}
public static SqlInt32 Sign (SqlDecimal n)
{
- SqlInt32 result = 0;
-
- if (n >= new SqlDecimal (0))
- result = 1;
- else
- result = -1;
-
- return result;
+ if (n.IsNull)
+ return SqlInt32.Null;
+ return (SqlInt32) (n.IsPositive ? 1 : -1);
}
public static SqlDecimal Subtract (SqlDecimal x, SqlDecimal y)
public SqlBoolean ToSqlBoolean ()
{
- return ((SqlBoolean)this);
+ return ((SqlBoolean) this);
}
public SqlByte ToSqlByte ()
{
- return ((SqlByte)this);
+ return ((SqlByte) this);
}
public SqlDouble ToSqlDouble ()
{
- return ((SqlDouble)this);
+ return ((SqlDouble) this);
}
public SqlInt16 ToSqlInt16 ()
{
- return ((SqlInt16)this);
+ return ((SqlInt16) this);
}
public SqlInt32 ToSqlInt32 ()
{
- return ((SqlInt32)this);
+ return ((SqlInt32) this);
}
public SqlInt64 ToSqlInt64 ()
{
- return ((SqlInt64)this);
+ return ((SqlInt64) this);
}
public SqlMoney ToSqlMoney ()
{
- return ((SqlMoney)this);
+ return ((SqlMoney) this);
}
public SqlSingle ToSqlSingle ()
{
- return ((SqlSingle)this);
+ return ((SqlSingle) this);
}
public SqlString ToSqlString ()
{
- return ((SqlString)this);
+ return ((SqlString) this);
}
public override string ToString ()
hi += (ulong)((ulong)this.Data [3] << 32);
uint rest = 0;
- String result = "";
StringBuilder Result = new StringBuilder ();
for (int i = 0; lo != 0 || hi != 0; i++) {
-
Div128By32 (ref hi, ref lo, 10, ref rest);
Result.Insert (0, rest.ToString ());
}
- while (Result.Length < this.Precision)
- Result.Append ("0");
-
while (Result.Length > this.Precision)
- Result.Remove (Result.Length - 1, 1);
+ Result.Remove (Result.Length - 1, 1);
if (this.Scale > 0)
- Result.Insert (Result.Length - this.Scale, ".");
+ Result.Insert (Result.Length - this.Scale, ".");
+
+ if (!positive)
+ Result.Insert (0, '-');
return Result.ToString ();
}
{
ulong a = 0;
ulong b = 0;
- ulong c = 0;
+ ulong c = 0;
a = (uint)(hi >> 32);
b = a / divider;
[MonoTODO("Find out what is the right way to set scale and precision")]
private static SqlDecimal DecimalDiv (SqlDecimal x, SqlDecimal y)
{
- ulong lo = 0;
- ulong hi = 0;
+ ulong lo = 0;
+ ulong hi = 0;
int sc = 0; // scale
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);
while (prec < sc) {
Div128By32(ref hi, ref lo, 10, ref r);
sc--;
- }
-
+ }
+
if (r >= 5)
lo++;
-
+
while ((((double)hi) * Math.Pow(2,64) + lo) - Math.Pow (10, prec) > 0)
prec++;
if (r >= 5)
lo++;
}
-
- int resultLo = (int)lo;
- int resultMi = (int)(lo >> 32);
- int resultMi2 = (int)(hi);
- int resultHi = (int)(hi >> 32);
- return new SqlDecimal (prec, (byte)sc, true, resultLo,
+ int resultLo = (int) lo;
+ int resultMi = (int) (lo >> 32);
+ int resultMi2 = (int) (hi);
+ int resultHi = (int) (hi >> 32);
+
+ return new SqlDecimal (prec, (byte) sc, positive, resultLo,
resultMi, resultMi2,
resultHi);
}
uint overhang = 0;
int sc = 0;
int i = 0;
- int rc = 0;
int roundBit = 0;
sc = scale;
if (texp > 0) {
-
- // reduce exp
+ // reduce exp
while (texp > 0 && sc <= maxScale) {
-
- overhang = (uint)(chi >> 64);
+ overhang = (uint)(chi >> 64);
while (texp > 0 && (((clo & 1) == 0) || overhang > 0)) {
-
if (--texp == 0)
roundBit = (int)(clo & 1);
RShift128 (ref clo, ref chi);
// 10^i/2^i=5^i
factor = constantsDecadeInt32Factors [i] >> i;
- System.Console.WriteLine ("***");
Mult128By32 (ref clo, ref chi, factor, 0);
- System.Console.WriteLine ((((double)chi) * Math.Pow (2,64) + clo));
-
}
while (texp > 0) {
private static void Normalize128(ref ulong clo, ref ulong chi, ref int scale, int roundFlag, int roundBit)
{
int sc = scale;
- int deltaScale;
scale = sc;
if ((roundFlag != 0) && (roundBit != 0))
int bshift = 0;
int extraBit = 0;
- xhi = (ulong)((ulong)x.Data [3] << 32) | (ulong)x.Data [2];
- xmi = (ulong)((ulong)x.Data [1] << 32) | (ulong)x.Data [0];
- xlo = (uint)0;
- ylo = (uint)y.Data [0];
- ymi = (uint)y.Data [1];
- ymi2 = (uint)y.Data [2];
- yhi = (uint)y.Data [3];
+ xhi = (ulong) ((ulong) x.Data [3] << 32) | (ulong) x.Data [2];
+ xmi = (ulong) ((ulong) x.Data [1] << 32) | (ulong) x.Data [0];
+ xlo = (uint) 0;
+ ylo = (uint) y.Data [0];
+ ymi = (uint) y.Data [1];
+ ymi2 = (uint) y.Data [2];
+ yhi = (uint) y.Data [3];
if (ylo == 0 && ymi == 0 && ymi2 == 0 && yhi == 0)
throw new DivideByZeroException ();
}
// enlarge dividend to get maximal precision
- for (ashift = 0; (xhi & LIT_GUINT64_HIGHBIT) == 0; ++ashift)
+ for (ashift = 0; (xhi & LIT_GUINT64_HIGHBIT) == 0; ++ashift)
LShift128 (ref xmi, ref xhi);
// ensure that divisor is at least 2^95
- for (bshift = 0; (yhi & LIT_GUINT32_HIGHBIT) == 0; ++bshift)
+ for (bshift = 0; (yhi & LIT_GUINT32_HIGHBIT) == 0; ++bshift)
LShift128 (ref ylo, ref ymi, ref ymi2, ref yhi);
thi = ((ulong)yhi) << 32 | (ulong)ymi2;
chi += LIT_GUINT64_HIGHBIT;
exp--;
}
-
+
// try loss free right shift
while (exp > 0 && (clo & 1) == 0) {
RShift128 (ref clo, ref chi);
exp--;
- }
+ }
}
// From decimal.c
+ /*
private static void RShift192(ref ulong lo, ref ulong mi, ref ulong hi)
{
-
lo >>= 1;
if ((mi & 1) != 0)
lo |= LIT_GUINT64_HIGHBIT;
hi >>= 1;
}
+ */
// From decimal.c
private static void RShift128(ref ulong lo, ref ulong hi)
mi <<= 1;
if ((lo & LIT_GUINT32_HIGHBIT) != 0)
- mi++;
+ mi++;
lo <<= 1;
}
private static void Div192By128To128 (ulong xlo, ulong xmi, ulong xhi,
uint ylo, uint ymi, uint ymi2,
uint yhi, ref ulong clo, ref ulong chi)
- {
+ {
ulong rlo, rmi, rhi; // remainders
uint h, c;
private static uint Div192By128To32WithRest(ref ulong xlo, ref ulong xmi,
ref ulong xhi, uint ylo,
uint ymi, uint ymi2, uint yhi)
- {
- ulong rlo, rmi, rhi; // remainder
+ {
+ ulong rlo, rmi, rhi; // remainder
ulong tlo = 0;
ulong thi = 0;
uint c;
xmi = rmi;
xhi = rhi;
- return c;
+ return c;
}
// From decimal.c
+ /*
private static void Mult192By32 (ref ulong clo, ref ulong cmi, ref ulong chi, ulong factor, int roundBit)
{
ulong a = 0;
uint h0 = 0;
uint h1 = 0;
- uint h2 = 0;
a = ((ulong)(uint)clo) * factor;
clo = ((ulong)h1) << 32 | h0;
a >>= 32;
- a += ((ulong)(uint)cmi) * factor;
+ a += ((ulong)(uint)cmi) * factor;
h0 = (uint)a;
a >>= 32;
cmi = ((ulong)h1) << 32 | h0;
a >>= 32;
- a += ((ulong)(uint)chi) * factor;
+ a += ((ulong)(uint)chi) * factor;
h0 = (uint)a;
a >>= 32;
h1 = (uint)a;
chi = ((ulong)h1) << 32 | h0;
}
+ */
// From decimal.c
private static void Mult128By32 (ref ulong clo, ref ulong chi, uint factor, int roundBit)
ulong a = 0;
uint h0 = 0;
uint h1 = 0;
- uint h2 = 0;
a = ((ulong)(uint)clo) * factor;
clo = ((ulong)h1) << 32 | h0;
a >>= 32;
- a += ((ulong)(uint)chi) * factor;
+ a += ((ulong)(uint)chi) * factor;
h0 = (uint)a;
a >>= 32;
a += (chi >> 32) * factor;
h1 = (uint)a;
-
+
chi = ((ulong)h1) << 32 | h0;
}
-
// From decimal.c
private static void Mult128By32To128(uint xlo, uint xmi, uint xmi2, uint xhi,
xhi += yhi;
clo = xlo;
cmi = xmi;
- chi = xhi;
+ chi = xhi;
}
// From decimal.c
public static SqlDecimal Truncate (SqlDecimal n, int position)
{
- int prec = n.Precision;// + (position - n.Scale);
- int sc = position;
- return new SqlDecimal ((byte)prec, (byte)sc,
- n.IsPositive, n.Data);
+ int diff = n.scale - position;
+ if (diff == 0)
+ return n;
+ int [] data = n.Data;
+ decimal d = new decimal (data [0], data [1], data [2], !n.positive, 0);
+ decimal x = 10;
+ for (int i = 0; i < diff; i++, x *= 10)
+ d = d - d % x;
+ data = Decimal.GetBits (d);
+ data [3] = 0;
+ return new SqlDecimal (n.precision, n.scale, n.positive, data);
}
public static SqlDecimal operator + (SqlDecimal x, SqlDecimal y)
{
- // 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);
+ if (x.IsNull || y.IsNull)
+ return SqlDecimal.Null;
+ //if one of them is negative, perform subtraction
+ if (x.IsPositive && !y.IsPositive){
+ y = new SqlDecimal (y.Precision, y.Scale, !y.IsPositive, y.Data);
+ return (x - y);
+ }
+ if (!x.IsPositive && y.IsPositive){
+ x = new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
+ return (y - x);
+ }
+ if (!x.IsPositive && !y.IsPositive){
+ x = new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
+ y = new SqlDecimal (y.Precision, y.Scale, !y.IsPositive, y.Data);
+ x = (x + y);
+ return new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
+ }
+ // adjust the scale to the larger of the two beforehand
+ if (x.scale > y.scale)
+ y = SqlDecimal.AdjustScale (y, x.scale - y.scale, false);
+ else if (y.scale > x.scale)
+ x = SqlDecimal.AdjustScale (x, y.scale - x.scale, false);
- // set the precision to the greater of the two
- byte resultPrecision;
- if (x.Precision > y.Precision)
- resultPrecision = x.Precision;
- else
- resultPrecision = y.Precision;
-
- int[] xData = x.Data;
- int[] yData = y.Data;
- int[] resultBits = new int[4];
+ byte resultPrecision = (byte)(Math.Max (x.Scale, y.Scale) +
+ Math.Max (x.Precision - x.Scale, y.Precision - y.Scale) + 1);
- ulong res;
+ if (resultPrecision > MaxPrecision)
+ resultPrecision = MaxPrecision;
+
+ int [] xData = x.Data;
+ int [] yData = y.Data;
+ int [] resultBits = new int[4];
ulong carry = 0;
-
- // add one at a time, and carry the results over to the next
- for (int i = 0; i < 4; i +=1)
- {
- carry = 0;
- res = (ulong)(xData[i]) + (ulong)(yData[i]) + carry;
- if (res > Int32.MaxValue)
- {
- carry = res - Int32.MaxValue;
- res = Int32.MaxValue;
- }
- resultBits [i] = (int)res;
+ ulong res = 0;
+ for (int i = 0; i < 4; i++){
+ res = (ulong)((uint)xData [i]) + (ulong)((uint)yData [i]) + carry;
+ resultBits [i] = (int) (res & (UInt32.MaxValue));
+ carry = res >> 32;
}
- // if we have carry left, then throw an exception
if (carry > 0)
throw new OverflowException ();
else
public static SqlDecimal operator / (SqlDecimal x, SqlDecimal y)
{
- // return new SqlDecimal (x.Value / y.Value);
- return DecimalDiv (x, y);
+ if (x.IsNull || y.IsNull)
+ return SqlDecimal.Null;
+
+ return DecimalDiv (x, y);
}
public static SqlBoolean operator == (SqlDecimal x, SqlDecimal y)
if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
+ if (x.IsPositive != y.IsPositive)
+ return SqlBoolean.False;
+
if (x.Scale > y.Scale)
y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, false);
else if (y.Scale > x.Scale)
x = SqlDecimal.AdjustScale(y, y.Scale - x.Scale, false);
for (int i = 0; i < 4; i += 1)
- {
if (x.Data[i] != y.Data[i])
- return new SqlBoolean (false);
- }
- return new SqlBoolean (true);
+ return SqlBoolean.False;
+
+ return SqlBoolean.True;
}
public static SqlBoolean operator > (SqlDecimal x, SqlDecimal y)
if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
+ if (x.IsPositive != y.IsPositive)
+ return new SqlBoolean (x.IsPositive);
+
if (x.Scale > y.Scale)
y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, false);
else if (y.Scale > x.Scale)
public static SqlBoolean operator >= (SqlDecimal x, SqlDecimal y)
{
- if (x.IsNull || y.IsNull)
+ if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
+ if (x.IsPositive != y.IsPositive)
+ return new SqlBoolean (x.IsPositive);
+
if (x.Scale > y.Scale)
y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
else if (y.Scale > x.Scale)
if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
+ if (x.IsPositive != y.IsPositive)
+ return SqlBoolean.True;
+
if (x.Scale > y.Scale)
x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
else if (y.Scale > x.Scale)
for (int i = 0; i < 4; i += 1)
{
if (x.Data[i] != y.Data[i])
- return new SqlBoolean (true);
+ return SqlBoolean.True;
}
- return new SqlBoolean (false);
+ return SqlBoolean.False;
}
public static SqlBoolean operator < (SqlDecimal x, SqlDecimal y)
{
-
if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
+ if (x.IsPositive != y.IsPositive)
+ return new SqlBoolean (y.IsPositive);
+
if (x.Scale > y.Scale)
y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
else if (y.Scale > x.Scale)
x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
- for (int i = 3; i >= 0; i -= 1)
- {
+ for (int i = 3; i >= 0; i -= 1) {
if (x.Data[i] == 0 && y.Data[i] == 0)
continue;
-
return new SqlBoolean (x.Data[i] < y.Data[i]);
}
return new SqlBoolean (false);
-
}
public static SqlBoolean operator <= (SqlDecimal x, SqlDecimal y)
{
- if (x.IsNull || y.IsNull)
+ if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
+ if (x.IsPositive != y.IsPositive)
+ return new SqlBoolean (y.IsPositive);
+
if (x.Scale > y.Scale)
y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
else if (y.Scale > x.Scale)
x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
- for (int i = 3; i >= 0; i -= 1)
- {
+ for (int i = 3; i >= 0; i -= 1) {
if (x.Data[i] == 0 && y.Data[i] == 0)
continue;
else
public static SqlDecimal operator * (SqlDecimal x, SqlDecimal y)
{
- // 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);
+ if (x.IsNull || y.IsNull)
+ return SqlDecimal.Null;
// set the precision to the greater of the two
- byte resultPrecision;
- if (x.Precision > y.Precision)
- resultPrecision = x.Precision;
- else
- resultPrecision = y.Precision;
-
+ byte resultPrecision = (byte)(x.Precision + y.Precision + 1);
+ byte resultScale = (byte)(x.Scale + y.Scale);
+ if (resultPrecision > MaxPrecision)
+ resultPrecision = MaxPrecision;
+
int[] xData = x.Data;
int[] yData = y.Data;
int[] resultBits = new int[4];
ulong res;
ulong carry = 0;
- // multiply one at a time, and carry the results over to the next
- for (int i = 0; i < 4; i +=1)
- {
- carry = 0;
- res = (ulong)(xData[i]) * (ulong)(yData[i]) + carry;
- if (res > Int32.MaxValue)
- {
- carry = res - Int32.MaxValue;
- res = Int32.MaxValue;
- }
- resultBits [i] = (int)res;
+ for (int i=0; i<4; ++i) {
+ res = 0;
+ for (int j=i; j<=i; ++j)
+ res += ((ulong)(uint) xData[j]) * ((ulong)(uint) yData[i-j]);
+ resultBits [i] = (int) ((res + carry) & UInt32.MaxValue);
+ carry = res >> 32;
}
-
+
// if we have carry left, then throw an exception
if (carry > 0)
throw new OverflowException ();
else
- return new SqlDecimal (resultPrecision, x.Scale, (x.IsPositive == y.IsPositive), resultBits);
-
+ return new SqlDecimal (resultPrecision, resultScale, (x.IsPositive == y.IsPositive), resultBits);
}
public static SqlDecimal operator - (SqlDecimal x, SqlDecimal y)
{
- if (x.IsPositive && !y.IsPositive) return x + y;
- if (!x.IsPositive && y.IsPositive) return -(x + y);
- if (!x.IsPositive && !y.IsPositive) return y - x;
+ if (x.IsNull || y.IsNull)
+ return SqlDecimal.Null;
- // otherwise, x is positive and y is positive
- bool resultPositive = (bool)(x > y);
- int[] yData = y.Data;
+ if (x.IsPositive && !y.IsPositive){
+ y = new SqlDecimal (y.Precision, y.Scale, !y.IsPositive, y.Data);
+ return x + y;
+ }
+ if (!x.IsPositive && y.IsPositive){
+ x = new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
+ x = (x + y);
+ return new SqlDecimal (x.Precision, x.Scale, false, x.Data);
+ }
+ if (!x.IsPositive && !y.IsPositive){
+ y = new SqlDecimal (y.Precision, y.Scale, !y.IsPositive, y.Data);
+ x = new SqlDecimal(x.Precision, x.Scale, !x.IsPositive, x.Data);
+ return (y - x);
+ }
+ // adjust the scale to the larger of the two beforehand
+ if (x.scale > y.scale)
+ y = SqlDecimal.AdjustScale (y, x.scale - y.scale, false);
+ else if (y.scale > x.scale)
+ x = SqlDecimal.AdjustScale (x, y.scale - x.scale, false);
+
+ //calculation of the new Precision for the result
+ byte resultPrecision = (byte)(Math.Max (x.Scale, y.Scale) +
+ Math.Max (x.Precision - x.Scale, y.Precision - y.Scale));
+
+ int[] op1_Data;
+ int[] op2_Data;
+ if (x >= y) {
+ op1_Data = x.Data;
+ op2_Data = y.Data;
+ } else {
+ op1_Data = y.Data;
+ op2_Data = x.Data;
+ }
- for (int i = 0; i < 4; i += 1) yData[i] = -yData[i];
+ ulong res = 0;
+ int carry = 0;
+ int[] resultBits = new int[4];
- SqlDecimal yInverse = new SqlDecimal (y.Precision, y.Scale, y.IsPositive, yData);
- if (resultPositive)
- return x + yInverse;
+ /*
+ if ((uint)op2_Data [i] > (uint)op1_Data [i]) {
+ carry = UInt32.MaxValue;
+ op2_Data [i] = op2_Data [i] >> 1;
+ } else
+ carr = 0;
+ res = (uint)carry; +(ulong)((uint)op1_Data [i]) - (ulong)((uint)op2_Data [i])
+ */
+
+ for (int i = 0; i < 4; i += 1) {
+ res = (ulong)((uint)op1_Data [i]) - (ulong)((uint)op2_Data [i]) + (ulong)carry;
+ carry = 0;
+ if ((uint)op2_Data [i] > (uint)op1_Data [i])
+ carry = -1;
+ resultBits [i] = (int)res;
+ }
+
+ if (carry > 0)
+ throw new OverflowException ();
else
- return -(x + yInverse);
+ return new SqlDecimal (resultPrecision, x.Scale, (x>=y).Value, resultBits);
}
- public static SqlDecimal operator - (SqlDecimal n)
+ public static SqlDecimal operator - (SqlDecimal x)
{
- return new SqlDecimal (n.Precision, n.Scale, !n.IsPositive, n.Data);
+ return new SqlDecimal (x.Precision, x.Scale, !x.IsPositive, x.Data);
}
public static explicit operator SqlDecimal (SqlBoolean x)
{
- if (x.IsNull)
+ if (x.IsNull)
return Null;
else
return new SqlDecimal ((decimal)x.ByteValue);
}
- public static explicit operator Decimal (SqlDecimal n)
+ public static explicit operator Decimal (SqlDecimal x)
{
- return n.Value;
+ return x.Value;
}
public static explicit operator SqlDecimal (SqlDouble x)
}
}
+#if NET_2_0
+ public static explicit operator SqlDecimal (double x)
+ {
+ return new SqlDecimal (x);
+ }
+
+ public static implicit operator SqlDecimal (long x)
+ {
+ return new SqlDecimal (x);
+ }
+#endif
+
public static implicit operator SqlDecimal (decimal x)
{
return new SqlDecimal (x);
public static implicit operator SqlDecimal (SqlByte x)
{
- if (x.IsNull)
+ if (x.IsNull)
return Null;
else
- return new SqlDecimal ((decimal)x.Value);
+ return new SqlDecimal ((decimal) x.Value);
}
public static implicit operator SqlDecimal (SqlInt16 x)
{
- if (x.IsNull)
+ if (x.IsNull)
return Null;
else
- return new SqlDecimal ((decimal)x.Value);
+ return new SqlDecimal ((decimal) x.Value);
}
public static implicit operator SqlDecimal (SqlInt32 x)
{
- if (x.IsNull)
+ if (x.IsNull)
return Null;
else
- return new SqlDecimal ((decimal)x.Value);
+ return new SqlDecimal ((decimal) x.Value);
}
public static implicit operator SqlDecimal (SqlInt64 x)
{
- if (x.IsNull)
+ if (x.IsNull)
return Null;
else
- return new SqlDecimal ((decimal)x.Value);
+ return new SqlDecimal ((decimal) x.Value);
}
public static implicit operator SqlDecimal (SqlMoney x)
{
- if (x.IsNull)
+ if (x.IsNull)
return Null;
else
- return new SqlDecimal ((decimal)x.Value);
+ return new SqlDecimal ((decimal) x.Value);
+ }
+
+#if NET_2_0
+ public static XmlQualifiedName GetXsdType (XmlSchemaSet schemaSet)
+ {
+ if (schemaSet != null && schemaSet.Count == 0) {
+ XmlSchema xs = new XmlSchema ();
+ XmlSchemaComplexType ct = new XmlSchemaComplexType ();
+ ct.Name = "decimal";
+ xs.Items.Add (ct);
+ schemaSet.Add (xs);
+ }
+ return new XmlQualifiedName ("decimal", "http://www.w3.org/2001/XMLSchema");
+ }
+
+ XmlSchema IXmlSerializable.GetSchema ()
+ {
+ return null;
+ }
+
+ void IXmlSerializable.ReadXml (XmlReader reader)
+ {
+ SqlDecimal retval;
+
+ if (reader == null)
+ return;
+
+ switch (reader.ReadState) {
+ case ReadState.EndOfFile:
+ case ReadState.Error:
+ case ReadState.Closed:
+ return;
+ }
+
+ // Skip XML declaration and prolog
+ // or do I need to validate for the <SqlInt32> tag?
+ reader.MoveToContent ();
+ if (reader.EOF)
+ return;
+
+ reader.Read ();
+ if (reader.NodeType == XmlNodeType.EndElement)
+ return;
+
+ if (reader.Value.Length > 0) {
+ if (String.Compare ("Null", reader.Value) == 0) {
+ // means a null reference/invalid value
+ notNull = false;
+ return;
+ }
+ // FIXME: do we need to handle the FormatException?
+ retval = new SqlDecimal (Decimal.Parse (reader.Value));
+
+ // SqlDecimal.Data returns a clone'd array
+ this.value = retval.Data;
+ this.notNull = true;
+ this.scale = retval.Scale;
+ this.precision = retval.Precision;
+ this.positive = retval.IsPositive;
+ }
+ }
+
+ void IXmlSerializable.WriteXml (XmlWriter writer)
+ {
+ writer.WriteString (this.Value.ToString ());
}
+#endif
#endregion
}