problem with dbconvert from float to money

"Stenuit, Pascal" <[email protected]>
Newsgroups gmane.comp.db.tds.freetds
Message-ID <[email protected]>
Hi,

We are happily using FreeTDS as a replacement for Sybase's dblib and
noticed a difference between the two implementations. 

It turns out that for the following code snippet:

    double            amt = 123456.78;

    dbconvert(0, SYBFLT8, (unsigned char *) &amt, (DBINT)-1,
              SYBMONEY, out, (DBINT)-1);  

Sybase will encode the SYBMONEY as 1234567800 (fixed point, 4 decimals)
while freetds will encode the value as 1234560000, in effect losing the
decimals. I believe Sybase is probably right (or at least consistent
with the reverse operation) but what do I know !

The following patch to src/tds/convert.c could be what's needed (I'm not
too sure about the bound checks).

Thanks for a great software,
pascal 


~> ident convert.c.orig
convert.c.orig:
     $Id: convert.c,v 1.192 2009/06/12 08:53:49 freddy77 Exp $
~> diff -u convert.c.orig  convert.c      
--- convert.c.orig      2009-09-29 07:41:00.670880900 +0200
+++ convert.c   2009-09-29 07:47:05.144408900 +0200
@@ -1428,7 +1428,7 @@
        case SYBMONEY:
                if (the_value > (TDS_REAL) (TDS_INT8_MAX / 10000) ||
the_value < (TDS_REAL) (TDS_INT8_MIN / 10000))
                        return TDS_CONVERT_OVERFLOW;
-               mymoney = ((TDS_INT8) the_value) * 10000;
+               mymoney = (TDS_INT8) (the_value * 10000);
                cr->m.mny = mymoney;
                return sizeof(TDS_MONEY);
                break;
@@ -1436,7 +1436,7 @@
        case SYBMONEY4:
                if (the_value > (TDS_REAL) (TDS_INT_MAX / 10000) ||
the_value < (TDS_REAL) (TDS_INT_MIN / 10000))
                        return TDS_CONVERT_OVERFLOW;
-               mymoney4 = ((TDS_INT) the_value) * 10000;
+               mymoney4 = (TDS_INT) (the_value * 10000);
                cr->m4.mny4 = mymoney4;
                return sizeof(TDS_MONEY4);
                break;
@@ -1512,14 +1512,14 @@
        case SYBMONEY:
                if (the_value > (TDS_FLOAT) (TDS_INT8_MAX / 10000) ||
the_value < (TDS_FLOAT) (TDS_INT8_MIN / 10000))
                        return TDS_CONVERT_OVERFLOW;
-               cr->m.mny = ((TDS_INT8) the_value) * 10000;
+               cr->m.mny = (TDS_INT8) (the_value * 10000);
 
                return sizeof(TDS_MONEY);
                break;
        case SYBMONEY4:
                if (the_value > (TDS_FLOAT) (TDS_INT_MAX / 10000) ||
the_value < (TDS_FLOAT) (TDS_INT_MIN / 10000))
                        return TDS_CONVERT_OVERFLOW;
-               cr->m4.mny4 = ((TDS_INT) the_value) * 10000;
+               cr->m4.mny4 = (TDS_INT) (the_value * 10000);
                return sizeof(TDS_MONEY4);
                break;
        case SYBREAL:

CONFIDENTIALITY NOTICE: The contents of this email are confidential
and for the exclusive use of the intended recipient. If you receive this
email in error, please delete it from your system immediately and 
notify us either by email, telephone or fax. You should not copy,
forward, or otherwise disclose the content of the email.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.