[Mono-list] SqlDecimal problems

Tim Coleman tim@timcoleman.com
Wed, 23 Oct 2002 19:16:21 -0400

On Wed, 23 Oct 2002 22:34:30 +0300
ville <vi64pa@koti.soon.fi> wrote:

> Weird! I made test suite for SqlDecimal and it didn't work correctly. For 
> example:
> // FIXME: windows: Conversion overflow
> AssertEquals  ("#B03", Decimal.MaxValue, SqlDecimal.MaxValue.Value);
> AssertEquals ("#B04", Decimal.MinValue, SqlDecimal.MinValue.Value);
> It is obvious that ms wont handle SqlDecimal internal value as a decimal,  but 
> ain't this bug or what?
> And another (much weirder):
> // FIXME: 6464.6464 --> 64646464 ??? with windows
> AssertEquals ("#N13a", (int)64646464, Test1.ToSqlInt32 ().Value);
> // FIXME: 12.12m --> 1212 ??? with windows
> AssertEquals ("#N13b", (int)1212, new SqlDecimal(12.12m).ToSqlInt32 ().Value);
> and with ToInt64 or ToInt16 everything went alright.
> somebody help me, please.


If you look back at the archives from April or May when I originally implemented these classes, you will see I had quite a bit of trouble with SqlDecimal.

You see, the problem is that SqlDecimal is 128 bits.  The decimal type is only 96 bits.

Here's the contents of the mail I wrote

-----Original Message-----
 From: Tim Coleman [mailto:tcoleman@opentext.com]
 Sent: Tuesday, May 07, 2002 8:48 PM
 To: mono-list@ximian.com
 Subject: System.Data.SqlTypes.SqlDecimal

 I have an issue with the System.Data.SqlTypes.SqlDecimal structure.
 It would seem that the appropriate internal representation would
 be to store the value as a decimal.  There's just one problem with
 this: decimals are 96 bit values while SqlDecimals can be 128 bit.

 Importantly, there are two constructors for SqlDecimal that take
 arrays of four integers representing the 128 bit value.  I've noticed,
 that even on .NET, if you pass in a value with the high 32 bits set
 to anything, you will get an OverflowException when you try to do
 things like get the Value of it.  However, what doesn't make sense
 is that you can actually write the value out to the console (!).
 What I would like to know is how this data is stored and displayed
 if you can't fit it into a decimal.  It's clear that MS does not 
 store it in a decimal, because you would get an overflow immediately.
 I could see that if the upper 32 bits are zero, then you could create
 the decimal cleanly using the first 96 bits.. but anyway, here's some
 code that I ran on CSC.  You can't run it on linux because I haven't
 got that part of the class library done yet (because of this problem).

 using System;
 using System.Data.SqlTypes;

 	class MainApp {
 		public static void Main ()
 			int[] bits = new int[4];
 			bits[0] = 1;
 			bits[1] = 1;
 			bits[2] = 1;
 			bits[3] = 1;
 			byte bPrecision = 38;
 			byte bScale = 10;
 			bool fPositive = true;

 			SqlDecimal x = new SqlDecimal (bPrecision, bScale, fPositive, bits);

 			// works correctly
 			System.Console.WriteLine (x);
 			// throws an exception
 			try {
 				System.Console.WriteLine (x.Value);
 			} catch (OverflowException e) {
 				System.Console.WriteLine (e.Message);

 			bits[0] = 1;
 			bits[1] = 1;
 			bits[2] = 1;
 			bits[3] = 0;

 			x = new SqlDecimal (bPrecision, bScale, fPositive, bits);
 			// works fine
 			System.Console.WriteLine (x.Value);

Tim Coleman <tim@timcoleman.com>                       [43.28 N 80.31 W]
BMath, Honours Combinatorics and Optimization, University of Waterloo
Software Developer, Global Services, Open Text Corporation
"Under capitalism, man exploits man.  Under communism, it's just the
 opposite." -- J.K. Galbraith