LCOV - code coverage report
Current view: top level - src/tds - numeric.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 145 148 98.0 %
Date: 2025-01-18 12:13:41 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998-1999  Brian Bruns
       3             :  * Copyright (C) 2005-2015  Frediano Ziglio
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or
       6             :  * modify it under the terms of the GNU Library General Public
       7             :  * License as published by the Free Software Foundation; either
       8             :  * version 2 of the License, or (at your option) any later version.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * Library General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU Library General Public
      16             :  * License along with this library; if not, write to the
      17             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      18             :  * Boston, MA 02111-1307, USA.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : #include <stdarg.h>
      24             : #include <stdio.h>
      25             : 
      26             : #if HAVE_STRING_H
      27             : #include <string.h>
      28             : #endif /* HAVE_STRING_H */
      29             : 
      30             : #include <freetds/tds.h>
      31             : #include <freetds/convert.h>
      32             : #include <freetds/bytes.h>
      33             : #include <stdlib.h>
      34             : 
      35             : /**
      36             :  * tds_numeric_bytes_per_prec is indexed by precision and will
      37             :  * tell us the number of bytes required to store the specified
      38             :  * precision (with the sign).
      39             :  * Support precision up to 77 digits
      40             :  */
      41             : const int tds_numeric_bytes_per_prec[] = {
      42             :         /*
      43             :          * precision can't be 0 but using a value > 0 assure no
      44             :          * core if for some bug it's 0...
      45             :          */
      46             :         1, 
      47             :         2,  2,  3,  3,  4,  4,  4,  5,  5,
      48             :         6,  6,  6,  7,  7,  8,  8,  9,  9,  9,
      49             :         10, 10, 11, 11, 11, 12, 12, 13, 13, 14,
      50             :         14, 14, 15, 15, 16, 16, 16, 17, 17, 18,
      51             :         18, 19, 19, 19, 20, 20, 21, 21, 21, 22,
      52             :         22, 23, 23, 24, 24, 24, 25, 25, 26, 26,
      53             :         26, 27, 27, 28, 28, 28, 29, 29, 30, 30,
      54             :         31, 31, 31, 32, 32, 33, 33, 33
      55             : };
      56             : 
      57             : TDS_COMPILE_CHECK(maxprecision,
      58             :         MAXPRECISION < TDS_VECTOR_SIZE(tds_numeric_bytes_per_prec) );
      59             : 
      60             : /*
      61             :  * money is a special case of numeric really...that why its here
      62             :  */
      63             : char *
      64        1592 : tds_money_to_string(const TDS_MONEY * money, char *s, bool use_2_digits)
      65             : {
      66             :         TDS_INT8 mymoney;
      67             :         TDS_UINT8 n;
      68             :         char *p;
      69             : 
      70             :         /* sometimes money it's only 4-byte aligned so always compute 64-bit */
      71        1592 :         mymoney = (((TDS_INT8) money->tdsoldmoney.mnyhigh) << 32) | money->tdsoldmoney.mnylow;
      72             : 
      73        1592 :         p = s;
      74        1592 :         if (mymoney < 0) {
      75         360 :                 *p++ = '-';
      76             :                 /* we use unsigned cause this cause arithmetic problem for -2^63*/
      77         360 :                 n = -mymoney;
      78             :         } else {
      79        1232 :                 n = mymoney;
      80             :         }
      81             :         /* if machine is 64 bit you do not need to split n */
      82        1592 :         if (use_2_digits) {
      83           0 :                 n = (n+ 50) / 100;
      84           0 :                 sprintf(p, "%" PRIu64 ".%02u", n / 100u, (unsigned) (n % 100u));
      85             :         } else {
      86        1592 :                 sprintf(p, "%" PRIu64 ".%04u", n / 10000u, (unsigned) (n % 10000u));
      87             :         }
      88        1592 :         return s;
      89             : }
      90             : 
      91             : /**
      92             :  * @return <0 if error
      93             :  */
      94             : TDS_INT
      95       10172 : tds_numeric_to_string(const TDS_NUMERIC * numeric, char *s)
      96             : {
      97             :         const unsigned char *number;
      98             : 
      99             :         unsigned int packet[sizeof(numeric->array) / 2];
     100             :         unsigned int *pnum, *packet_start;
     101       10172 :         unsigned int *const packet_end = packet + TDS_VECTOR_SIZE(packet);
     102             : 
     103             :         unsigned int packet10k[(MAXPRECISION + 3) / 4];
     104             :         unsigned int *p;
     105             : 
     106             :         int num_bytes;
     107             :         unsigned int remainder, n, i, m;
     108             : 
     109             :         /* a bit of debug */
     110             : #if ENABLE_EXTRA_CHECKS
     111       10172 :         memset(packet, 0x55, sizeof(packet));
     112       10172 :         memset(packet10k, 0x55, sizeof(packet10k));
     113             : #endif
     114             : 
     115       10172 :         if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
     116             :                 return TDS_CONVERT_FAIL;
     117             : 
     118             :         /* set sign */
     119       10172 :         if (numeric->array[0] == 1)
     120        4078 :                 *s++ = '-';
     121             : 
     122             :         /* put number in a 16bit array */
     123       10172 :         number = numeric->array;
     124       10172 :         num_bytes = tds_numeric_bytes_per_prec[numeric->precision];
     125             : 
     126       10172 :         n = num_bytes - 1;
     127       10172 :         pnum = packet_end;
     128       50774 :         for (; n > 1; n -= 2)
     129       40602 :                 *--pnum = TDS_GET_UA2BE(&number[n - 1]);
     130       10172 :         if (n == 1)
     131        9318 :                 *--pnum = number[n];
     132       38224 :         while (!*pnum) {
     133       28188 :                 ++pnum;
     134       28188 :                 if (pnum == packet_end) {
     135         136 :                         *s++ = '0';
     136         136 :                         if (numeric->scale) {
     137           8 :                                 *s++ = '.';
     138           8 :                                 i = numeric->scale;
     139             :                                 do {
     140          32 :                                         *s++ = '0';
     141          32 :                                 } while (--i);
     142             :                         }
     143         136 :                         *s = 0;
     144         136 :                         return 1;
     145             :                 }
     146             :         }
     147             :         packet_start = pnum;
     148             : 
     149             :         /* transform 2^16 base number in 10^4 base number */
     150       35718 :         for (p = packet10k + TDS_VECTOR_SIZE(packet10k); packet_start != packet_end;) {
     151       25682 :                 pnum = packet_start;
     152       25682 :                 n = *pnum;
     153       25682 :                 remainder = n % 10000u;
     154       25682 :                 if (!(*pnum++ = (n / 10000u)))
     155       21732 :                         packet_start = pnum;
     156       25866 :                 for (; pnum != packet_end; ++pnum) {
     157       25866 :                         n = remainder * (256u * 256u) + *pnum;
     158       25866 :                         remainder = n % 10000u;
     159       25866 :                         *pnum = n / 10000u;
     160             :                 }
     161       25682 :                 *--p = remainder;
     162             :         }
     163             : 
     164             :         /* transform to 10 base number and output */
     165       10036 :         i = 4 * (unsigned int)((packet10k + TDS_VECTOR_SIZE(packet10k)) - p);   /* current digit */
     166             :         /* skip leading zeroes */
     167       10036 :         n = 1000;
     168       10036 :         remainder = *p;
     169       36450 :         while (remainder < n)
     170       16378 :                 n /= 10, --i;
     171       10036 :         if (i <= numeric->scale) {
     172          32 :                 *s++ = '0';
     173          32 :                 *s++ = '.';
     174          32 :                 m = i;
     175         128 :                 while (m < numeric->scale)
     176          64 :                         *s++ = '0', ++m;
     177             :         }
     178             :         for (;;) {
     179       86350 :                 *s++ = (remainder / n) + '0';
     180       86350 :                 --i;
     181       86350 :                 remainder %= n;
     182       86350 :                 n /= 10;
     183       86350 :                 if (!n) {
     184       25682 :                         n = 1000;
     185       25682 :                         if (++p == packet10k + TDS_VECTOR_SIZE(packet10k))
     186             :                                 break;
     187       15646 :                         remainder = *p;
     188             :                 }
     189       76314 :                 if (i == numeric->scale)
     190         878 :                         *s++ = '.';
     191             :         }
     192       10036 :         *s = 0;
     193             : 
     194       10036 :         return 1;
     195             : }
     196             : 
     197             : #define TDS_WORD  uint32_t
     198             : #define TDS_DWORD uint64_t
     199             : #define TDS_WORD_DDIGIT 9
     200             : 
     201             : /* include to check limits */
     202             : 
     203             : #include "num_limits.h"
     204             : 
     205             : static int
     206       31326 : tds_packet_check_overflow(TDS_WORD *packet, unsigned int packet_len, unsigned int prec)
     207             : {
     208             :         unsigned int i, len, stop;
     209       31326 :         const TDS_WORD *limit = &limits[limit_indexes[prec] + LIMIT_INDEXES_ADJUST * prec];
     210       31326 :         len = limit_indexes[prec+1] - limit_indexes[prec] + LIMIT_INDEXES_ADJUST;
     211       31326 :         stop = prec / (sizeof(TDS_WORD) * 8);
     212             :         /*
     213             :          * Now a number is
     214             :          * ... P[3] P[2] P[1] P[0]
     215             :          * while upper limit + 1 is
     216             :          * zeroes limit[0 .. len-1] 0[0 .. stop-1]
     217             :          * we must assure that number < upper limit + 1
     218             :          */
     219       31326 :         if (packet_len >= len + stop) {
     220             :                 /* higher packets must be zero */
     221       23066 :                 for (i = packet_len; --i >= len + stop; )
     222        6456 :                         if (packet[i] > 0)
     223             :                                 return TDS_CONVERT_OVERFLOW;
     224             :                 /* test limit */
     225           0 :                 for (;; --i, ++limit) {
     226       16610 :                         if (i <= stop) {
     227             :                                 /* last must be >= not > */
     228       13506 :                                 if (packet[i] >= *limit)
     229             :                                         return TDS_CONVERT_OVERFLOW;
     230             :                                 break;
     231             :                         }
     232        3104 :                         if (packet[i] > *limit)
     233             :                                 return TDS_CONVERT_OVERFLOW;
     234         928 :                         if (packet[i] < *limit)
     235             :                                 break;
     236             :                 }
     237             :         }
     238       17150 :         return 0;
     239             : }
     240             : 
     241             : TDS_INT
     242       60098 : tds_numeric_change_prec_scale(TDS_NUMERIC * numeric, unsigned char new_prec, unsigned char new_scale)
     243             : {
     244             :         static const TDS_WORD factors[] = {
     245             :                 1, 10, 100, 1000, 10000,
     246             :                 100000, 1000000, 10000000, 100000000, 1000000000
     247             :         };
     248             : 
     249             :         TDS_WORD packet[(sizeof(numeric->array) - 1) / sizeof(TDS_WORD)];
     250             : 
     251             :         unsigned int i, packet_len;
     252             :         int scale_diff, bytes;
     253             : 
     254       60098 :         if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
     255             :                 return TDS_CONVERT_FAIL;
     256             : 
     257       60098 :         if (new_prec < 1 || new_prec > MAXPRECISION || new_scale > new_prec)
     258             :                 return TDS_CONVERT_FAIL;
     259             : 
     260       60098 :         scale_diff = new_scale - numeric->scale;
     261       60098 :         if (scale_diff == 0 && new_prec >= numeric->precision) {
     262       23550 :                 i = tds_numeric_bytes_per_prec[new_prec] - tds_numeric_bytes_per_prec[numeric->precision];
     263       23550 :                 if (i > 0) {
     264        9488 :                         memmove(numeric->array + 1 + i, numeric->array + 1, sizeof(numeric->array) - 1 - i);
     265        9488 :                         memset(numeric->array + 1, 0, i);
     266             :                 }
     267       23550 :                 numeric->precision = new_prec;
     268       23550 :                 return sizeof(TDS_NUMERIC);
     269             :         }
     270             : 
     271             :         /* package number */
     272       36548 :         bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
     273       36548 :         i = 0;
     274             :         do {
     275             :                 /*
     276             :                  * note that if bytes are smaller we have a small buffer
     277             :                  * overflow in numeric->array however is not a problem
     278             :                  * cause overflow occurs in numeric and number is fixed below
     279             :                  */
     280      106314 :                 packet[i] = TDS_GET_UA4BE(&numeric->array[bytes-3]);
     281      106314 :                 ++i;
     282      106314 :         } while ( (bytes -= sizeof(TDS_WORD)) > 0);
     283             :         /* fix last packet */
     284       36548 :         if (bytes < 0)
     285       35856 :                 packet[i-1] &= 0xffffffffu >> (8 * -bytes);
     286       94346 :         while (i > 1 && packet[i-1] == 0)
     287             :                 --i;
     288       36548 :         packet_len = i;
     289             : 
     290       36548 :         if (scale_diff >= 0) {
     291             :                 /* check overflow before multiply */
     292       31022 :                 if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
     293             :                         return TDS_CONVERT_OVERFLOW;
     294             : 
     295       17046 :                 if (scale_diff == 0) {
     296       11266 :                         i = tds_numeric_bytes_per_prec[numeric->precision] - tds_numeric_bytes_per_prec[new_prec];
     297       11266 :                         if (i > 0)
     298       11266 :                                 memmove(numeric->array + 1, numeric->array + 1 + i, sizeof(numeric->array) - 1 - i);
     299       11266 :                         numeric->precision = new_prec;
     300       11266 :                         return sizeof(TDS_NUMERIC);
     301             :                 }
     302             : 
     303             :                 /* multiply */
     304             :                 do {
     305             :                         /* multiply by at maximun TDS_WORD_DDIGIT */
     306        5796 :                         unsigned int n = scale_diff > TDS_WORD_DDIGIT ? TDS_WORD_DDIGIT : scale_diff;
     307        5796 :                         TDS_WORD factor = factors[n];
     308        5796 :                         TDS_WORD carry = 0;
     309        5796 :                         scale_diff -= n; 
     310       12208 :                         for (i = 0; i < packet_len; ++i) {
     311        6412 :                                 TDS_DWORD n = packet[i] * ((TDS_DWORD) factor) + carry;
     312        6412 :                                 packet[i] = (TDS_WORD) n;
     313        6412 :                                 carry = n >> (8 * sizeof(TDS_WORD));
     314             :                         }
     315             :                         /* here we can expand number safely cause we know that it can't overflow */
     316        5796 :                         if (carry)
     317         680 :                                 packet[packet_len++] = carry;
     318        5796 :                 } while (scale_diff > 0);
     319             :         } else {
     320             :                 /* check overflow */
     321        5526 :                 if (new_prec - scale_diff < numeric->precision)
     322         304 :                         if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
     323             :                                 return TDS_CONVERT_OVERFLOW;
     324             : 
     325             :                 /* divide */
     326        5326 :                 scale_diff = -scale_diff;
     327             :                 do {
     328        5342 :                         unsigned int n = scale_diff > TDS_WORD_DDIGIT ? TDS_WORD_DDIGIT : scale_diff;
     329        5342 :                         TDS_WORD factor = factors[n];
     330        5342 :                         TDS_WORD borrow = 0;
     331        5342 :                         scale_diff -= n;
     332       17018 :                         for (i = packet_len; i > 0; ) {
     333             : #if defined(__GNUC__) && __GNUC__ >= 3 && defined(__i386__)
     334             :                                 --i;
     335             :                                 __asm__ ("divl %4": "=a"(packet[i]), "=d"(borrow): "0"(packet[i]), "1"(borrow), "r"(factor));
     336             : #elif defined(__WATCOMC__) && defined(DOS32X)
     337             :                                 TDS_WORD Int64div32(TDS_WORD* low,TDS_WORD high,TDS_WORD factor);
     338             :                                 #pragma aux Int64div32 = "mov eax, dword ptr[esi]" \
     339             :                                         "div ecx" \
     340             :                                         "mov dword ptr[esi], eax" \
     341             :                                         parm [ESI] [EDX] [ECX] value [EDX] modify [EAX EDX];
     342             :                                 borrow = Int64div32(&packet[i], borrow, factor);
     343             : #else
     344        6334 :                                 TDS_DWORD n = (((TDS_DWORD) borrow) << (8 * sizeof(TDS_WORD))) + packet[--i];
     345        6334 :                                 packet[i] = (TDS_WORD) (n / factor);
     346        6334 :                                 borrow = n % factor;
     347             : #endif
     348             :                         }
     349        5342 :                 } while (scale_diff > 0);
     350             :         }
     351             : 
     352             :         /* back to our format */
     353       11106 :         numeric->precision = new_prec;
     354       11106 :         numeric->scale = new_scale;
     355       11106 :         bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
     356       29000 :         for (i = bytes / sizeof(TDS_WORD); i >= packet_len; --i)
     357       17894 :                 packet[i] = 0;
     358       20134 :         for (i = 0; bytes >= sizeof(TDS_WORD); bytes -= sizeof(TDS_WORD), ++i) {
     359       20134 :                 TDS_PUT_UA4BE(&numeric->array[bytes-3], packet[i]);
     360             :         }
     361             : 
     362       11106 :         if (bytes) {
     363       10594 :                 TDS_WORD remainder = packet[i];
     364             :                 do {
     365       10858 :                         numeric->array[bytes] = (TDS_UCHAR) remainder;
     366       10858 :                         remainder >>= 8;
     367       10858 :                 } while (--bytes);
     368             :         }
     369             : 
     370             :         return sizeof(TDS_NUMERIC);
     371             : }
     372             : 

Generated by: LCOV version 1.13