LCOV - code coverage report
Current view: top level - src/tds - numeric.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 149 152 98.0 %
Date: 2025-02-21 09:36:06 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 <freetds/windows.h>
      34             : #include <stdlib.h>
      35             : 
      36             : /**
      37             :  * tds_numeric_bytes_per_prec is indexed by precision and will
      38             :  * tell us the number of bytes required to store the specified
      39             :  * precision (with the sign).
      40             :  * Support precision up to 77 digits
      41             :  */
      42             : const int tds_numeric_bytes_per_prec[] = {
      43             :         /*
      44             :          * precision can't be 0 but using a value > 0 assure no
      45             :          * core if for some bug it's 0...
      46             :          */
      47             :         1, 
      48             :         2,  2,  3,  3,  4,  4,  4,  5,  5,
      49             :         6,  6,  6,  7,  7,  8,  8,  9,  9,  9,
      50             :         10, 10, 11, 11, 11, 12, 12, 13, 13, 14,
      51             :         14, 14, 15, 15, 16, 16, 16, 17, 17, 18,
      52             :         18, 19, 19, 19, 20, 20, 21, 21, 21, 22,
      53             :         22, 23, 23, 24, 24, 24, 25, 25, 26, 26,
      54             :         26, 27, 27, 28, 28, 28, 29, 29, 30, 30,
      55             :         31, 31, 31, 32, 32, 33, 33, 33
      56             : };
      57             : 
      58             : TDS_COMPILE_CHECK(maxprecision,
      59             :         MAXPRECISION < TDS_VECTOR_SIZE(tds_numeric_bytes_per_prec) );
      60             : 
      61             : /*
      62             :  * money is a special case of numeric really...that why its here
      63             :  */
      64             : char *
      65        2004 : tds_money_to_string(const TDS_MONEY * money, char *s, bool use_2_digits)
      66             : {
      67             :         TDS_INT8 mymoney;
      68             :         TDS_UINT8 n;
      69             :         char *p;
      70             : 
      71             :         /* sometimes money it's only 4-byte aligned so always compute 64-bit */
      72        2004 :         mymoney = (((TDS_INT8) money->tdsoldmoney.mnyhigh) << 32) | money->tdsoldmoney.mnylow;
      73             : 
      74        2004 :         p = s;
      75        2004 :         if (mymoney < 0) {
      76         450 :                 *p++ = '-';
      77             :                 /* we use unsigned cause this cause arithmetic problem for -2^63*/
      78         450 :                 n = -mymoney;
      79             :         } else {
      80        1554 :                 n = mymoney;
      81             :         }
      82             :         /* if machine is 64 bit you do not need to split n */
      83        2004 :         if (use_2_digits) {
      84           0 :                 n = (n+ 50) / 100;
      85           0 :                 sprintf(p, "%" PRIu64 ".%02u", n / 100u, (unsigned) (n % 100u));
      86             :         } else {
      87        2004 :                 sprintf(p, "%" PRIu64 ".%04u", n / 10000u, (unsigned) (n % 10000u));
      88             :         }
      89        2004 :         return s;
      90             : }
      91             : 
      92             : /**
      93             :  * @return <0 if error
      94             :  */
      95             : TDS_INT
      96       13082 : tds_numeric_to_string(const TDS_NUMERIC * numeric, char *s)
      97             : {
      98             :         const unsigned char *number;
      99             : 
     100             :         unsigned int packet[sizeof(numeric->array) / 2];
     101             :         unsigned int *pnum, *packet_start;
     102       13082 :         unsigned int *const packet_end = packet + TDS_VECTOR_SIZE(packet);
     103             : 
     104             :         unsigned int packet10k[(MAXPRECISION + 3) / 4];
     105             :         unsigned int *p;
     106             : 
     107             :         int num_bytes;
     108             :         unsigned int remainder, n, i, m;
     109             : 
     110             :         /* a bit of debug */
     111             : #if ENABLE_EXTRA_CHECKS
     112       13082 :         memset(packet, 0x55, sizeof(packet));
     113       13082 :         memset(packet10k, 0x55, sizeof(packet10k));
     114             : #endif
     115             : 
     116       13082 :         if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
     117             :                 return TDS_CONVERT_FAIL;
     118             : 
     119             :         /* set sign */
     120       13082 :         if (numeric->array[0] == 1)
     121        5098 :                 *s++ = '-';
     122             : 
     123             :         /* put number in a 16bit array */
     124       13082 :         number = numeric->array;
     125       13082 :         num_bytes = tds_numeric_bytes_per_prec[numeric->precision];
     126             : 
     127       13082 :         n = num_bytes - 1;
     128       13082 :         pnum = packet_end;
     129       65934 :         for (; n > 1; n -= 2)
     130       52852 :                 *--pnum = TDS_GET_UA2BE(&number[n - 1]);
     131       13082 :         if (n == 1)
     132       12008 :                 *--pnum = number[n];
     133       49144 :         while (!*pnum) {
     134       36232 :                 ++pnum;
     135       36232 :                 if (pnum == packet_end) {
     136         170 :                         *s++ = '0';
     137         170 :                         if (numeric->scale) {
     138          10 :                                 *s++ = '.';
     139          10 :                                 i = numeric->scale;
     140             :                                 do {
     141          40 :                                         *s++ = '0';
     142          40 :                                 } while (--i);
     143             :                         }
     144         170 :                         *s = 0;
     145         170 :                         return 1;
     146             :                 }
     147             :         }
     148             :         packet_start = pnum;
     149             : 
     150             :         /* transform 2^16 base number in 10^4 base number */
     151       46770 :         for (p = packet10k + TDS_VECTOR_SIZE(packet10k); packet_start != packet_end;) {
     152       33858 :                 pnum = packet_start;
     153       33858 :                 n = *pnum;
     154       33858 :                 remainder = n % 10000u;
     155       33858 :                 if (!(*pnum++ = (n / 10000u)))
     156       28628 :                         packet_start = pnum;
     157       35470 :                 for (; pnum != packet_end; ++pnum) {
     158       35470 :                         n = remainder * (256u * 256u) + *pnum;
     159       35470 :                         remainder = n % 10000u;
     160       35470 :                         *pnum = n / 10000u;
     161             :                 }
     162       33858 :                 *--p = remainder;
     163             :         }
     164             : 
     165             :         /* transform to 10 base number and output */
     166       12912 :         i = 4 * (unsigned int)((packet10k + TDS_VECTOR_SIZE(packet10k)) - p);   /* current digit */
     167             :         /* skip leading zeroes */
     168       12912 :         n = 1000;
     169       12912 :         remainder = *p;
     170       46560 :         while (remainder < n)
     171       20736 :                 n /= 10, --i;
     172       12912 :         if (i <= numeric->scale) {
     173          40 :                 *s++ = '0';
     174          40 :                 *s++ = '.';
     175          40 :                 m = i;
     176         160 :                 while (m < numeric->scale)
     177          80 :                         *s++ = '0', ++m;
     178             :         }
     179             :         for (;;) {
     180      114696 :                 *s++ = (remainder / n) + '0';
     181      114696 :                 --i;
     182      114696 :                 remainder %= n;
     183      114696 :                 n /= 10;
     184      114696 :                 if (!n) {
     185       33858 :                         n = 1000;
     186       33858 :                         if (++p == packet10k + TDS_VECTOR_SIZE(packet10k))
     187             :                                 break;
     188       20946 :                         remainder = *p;
     189             :                 }
     190      101784 :                 if (i == numeric->scale)
     191        1462 :                         *s++ = '.';
     192             :         }
     193       12912 :         *s = 0;
     194             : 
     195       12912 :         return 1;
     196             : }
     197             : 
     198             : #define TDS_WORD  uint32_t
     199             : #define TDS_DWORD uint64_t
     200             : #define TDS_WORD_DDIGIT 9
     201             : 
     202             : /* include to check limits */
     203             : 
     204             : #include "num_limits.h"
     205             : 
     206             : static int
     207       43828 : tds_packet_check_overflow(TDS_WORD *packet, unsigned int packet_len, unsigned int prec)
     208             : {
     209             :         unsigned int i, len, stop;
     210       43828 :         const TDS_WORD *limit = &limits[limit_indexes[prec] + LIMIT_INDEXES_ADJUST * prec];
     211       43828 :         len = limit_indexes[prec+1] - limit_indexes[prec] + LIMIT_INDEXES_ADJUST;
     212       43828 :         stop = prec / (sizeof(TDS_WORD) * 8);
     213             :         /*
     214             :          * Now a number is
     215             :          * ... P[3] P[2] P[1] P[0]
     216             :          * while upper limit + 1 is
     217             :          * zeroes limit[0 .. len-1] 0[0 .. stop-1]
     218             :          * we must assure that number < upper limit + 1
     219             :          */
     220       43828 :         if (packet_len >= len + stop) {
     221             :                 /* higher packets must be zero */
     222       33500 :                 for (i = packet_len; --i >= len + stop; )
     223        9550 :                         if (packet[i] > 0)
     224             :                                 return TDS_CONVERT_OVERFLOW;
     225             :                 /* test limit */
     226           0 :                 for (;; --i, ++limit) {
     227       23950 :                         if (i <= stop) {
     228             :                                 /* last must be >= not > */
     229       20070 :                                 if (packet[i] >= *limit)
     230             :                                         return TDS_CONVERT_OVERFLOW;
     231             :                                 break;
     232             :                         }
     233        3880 :                         if (packet[i] > *limit)
     234             :                                 return TDS_CONVERT_OVERFLOW;
     235        1160 :                         if (packet[i] < *limit)
     236             :                                 break;
     237             :                 }
     238             :         }
     239       22748 :         return 0;
     240             : }
     241             : 
     242             : #undef USE_128_MULTIPLY
     243             : #if defined(__GNUC__) && SIZEOF___INT128 > 0
     244             : #define USE_128_MULTIPLY 1
     245             : #undef __umulh
     246             : #define __umulh(multiplier, multiplicand) \
     247             :         ((uint64_t) ((((unsigned __int128) (multiplier)) * (multiplicand)) >> 64))
     248             : #endif
     249             : #if defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_X64) || defined(_M_ARM64))
     250             : #include <intrin.h>
     251             : #define USE_128_MULTIPLY 1
     252             : #endif
     253             : 
     254             : #undef USE_I386_DIVIDE
     255             : #undef USE_64_MULTIPLY
     256             : #ifndef USE_128_MULTIPLY
     257             : # if defined(__GNUC__) && __GNUC__ >= 3 && defined(__i386__)
     258             : #  define USE_I386_DIVIDE 1
     259             : # else
     260             : #  define USE_64_MULTIPLY
     261             : # endif
     262             : #endif
     263             : 
     264             : TDS_INT
     265       80392 : tds_numeric_change_prec_scale(TDS_NUMERIC * numeric, unsigned char new_prec, unsigned char new_scale)
     266             : {
     267             : #define TDS_WORD_BITS (8 * sizeof(TDS_WORD))
     268             :         static const TDS_WORD factors[] = {
     269             :                 1, 10, 100, 1000, 10000,
     270             :                 100000, 1000000, 10000000, 100000000, 1000000000
     271             :         };
     272             : #ifndef USE_I386_DIVIDE
     273             :         /* These numbers are computed as
     274             :          * (2 ** (reverse_dividers_shift[i] + 64)) / (10 ** i) + 1
     275             :          * (** is power).
     276             :          * The shifts are computed to make sure the multiplication error
     277             :          * does not cause a wrong result.
     278             :          *
     279             :          * See also misc/reverse_divisor script.
     280             :          */
     281             :         static const TDS_DWORD reverse_dividers[] = {
     282             :                 1 /* not used */,
     283             :                 UINT64_C(1844674407370955162),
     284             :                 UINT64_C(184467440737095517),
     285             :                 UINT64_C(18446744073709552),
     286             :                 UINT64_C(1844674407370956),
     287             :                 UINT64_C(737869762948383),
     288             :                 UINT64_C(2361183241434823),
     289             :                 UINT64_C(15111572745182865),
     290             :                 UINT64_C(48357032784585167),
     291             :                 UINT64_C(1237940039285380275),
     292             :         };
     293             :         static const uint8_t reverse_dividers_shift[] = {
     294             :                 0 /* not used */,
     295             :                 0,
     296             :                 0,
     297             :                 0,
     298             :                 0,
     299             :                 2,
     300             :                 7,
     301             :                 13,
     302             :                 18,
     303             :                 26,
     304             :         };
     305             : #endif
     306             : 
     307             :         TDS_WORD packet[(sizeof(numeric->array) - 1) / sizeof(TDS_WORD)];
     308             : 
     309             :         unsigned int i, packet_len;
     310             :         int scale_diff, bytes;
     311             : 
     312       80392 :         if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
     313             :                 return TDS_CONVERT_FAIL;
     314             : 
     315       80392 :         if (new_prec < 1 || new_prec > MAXPRECISION || new_scale > new_prec)
     316             :                 return TDS_CONVERT_FAIL;
     317             : 
     318       80392 :         scale_diff = new_scale - numeric->scale;
     319       80392 :         if (scale_diff == 0 && new_prec >= numeric->precision) {
     320       29862 :                 i = tds_numeric_bytes_per_prec[new_prec] - tds_numeric_bytes_per_prec[numeric->precision];
     321       29862 :                 if (i > 0) {
     322       12280 :                         memmove(numeric->array + 1 + i, numeric->array + 1, sizeof(numeric->array) - 1 - i);
     323       12280 :                         memset(numeric->array + 1, 0, i);
     324             :                 }
     325       29862 :                 numeric->precision = new_prec;
     326       29862 :                 return sizeof(TDS_NUMERIC);
     327             :         }
     328             : 
     329             :         /* package number */
     330       50530 :         bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
     331       50530 :         i = 0;
     332             :         do {
     333             :                 /*
     334             :                  * note that if bytes are smaller we have a small buffer
     335             :                  * overflow in numeric->array however is not a problem
     336             :                  * cause overflow occurs in numeric and number is fixed below
     337             :                  */
     338      147530 :                 packet[i] = TDS_GET_UA4BE(&numeric->array[bytes-3]);
     339      147530 :                 ++i;
     340      147530 :         } while ( (bytes -= sizeof(TDS_WORD)) > 0);
     341             :         /* fix last packet */
     342       50530 :         if (bytes < 0)
     343       49642 :                 packet[i-1] &= 0xffffffffu >> (8 * -bytes);
     344      130530 :         while (i > 1 && packet[i-1] == 0)
     345             :                 --i;
     346       50530 :         packet_len = i;
     347             : 
     348       50530 :         if (scale_diff >= 0) {
     349             :                 /* check overflow before multiply */
     350       43428 :                 if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
     351             :                         return TDS_CONVERT_OVERFLOW;
     352             : 
     353       22598 :                 if (scale_diff == 0) {
     354       15344 :                         i = tds_numeric_bytes_per_prec[numeric->precision] - tds_numeric_bytes_per_prec[new_prec];
     355       15344 :                         if (i > 0)
     356       15344 :                                 memmove(numeric->array + 1, numeric->array + 1 + i, sizeof(numeric->array) - 1 - i);
     357       15344 :                         numeric->precision = new_prec;
     358       15344 :                         return sizeof(TDS_NUMERIC);
     359             :                 }
     360             : 
     361             :                 /* multiply */
     362             :                 do {
     363             :                         /* multiply by at maximun TDS_WORD_DDIGIT */
     364        7274 :                         unsigned int n = scale_diff > TDS_WORD_DDIGIT ? TDS_WORD_DDIGIT : scale_diff;
     365        7274 :                         TDS_WORD factor = factors[n];
     366        7274 :                         TDS_WORD carry = 0;
     367        7274 :                         scale_diff -= n; 
     368       15318 :                         for (i = 0; i < packet_len; ++i) {
     369        8044 :                                 TDS_DWORD n = packet[i] * ((TDS_DWORD) factor) + carry;
     370        8044 :                                 packet[i] = (TDS_WORD) n;
     371        8044 :                                 carry = n >> TDS_WORD_BITS;
     372             :                         }
     373             :                         /* here we can expand number safely cause we know that it can't overflow */
     374        7274 :                         if (carry)
     375         850 :                                 packet[packet_len++] = carry;
     376        7274 :                 } while (scale_diff > 0);
     377             :         } else {
     378             :                 /* check overflow */
     379        7102 :                 if (new_prec - scale_diff < numeric->precision)
     380         400 :                         if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
     381             :                                 return TDS_CONVERT_OVERFLOW;
     382             : 
     383             :                 /* divide */
     384        6852 :                 scale_diff = -scale_diff;
     385             :                 do {
     386        6952 :                         unsigned int n = scale_diff > TDS_WORD_DDIGIT ? TDS_WORD_DDIGIT : scale_diff;
     387        6952 :                         TDS_WORD factor = factors[n];
     388        6952 :                         TDS_WORD borrow = 0;
     389             : #if defined(USE_128_MULTIPLY)
     390        6952 :                         TDS_DWORD reverse_divider = reverse_dividers[n];
     391        6952 :                         uint8_t shift = reverse_dividers_shift[n];
     392             : #elif defined(USE_64_MULTIPLY)
     393             :                         TDS_WORD reverse_divider_low = (TDS_WORD) reverse_dividers[n];
     394             :                         TDS_WORD reverse_divider_high = (TDS_WORD) (reverse_dividers[n] >> TDS_WORD_BITS);
     395             :                         uint8_t shift = reverse_dividers_shift[n];
     396             : #endif
     397        6952 :                         scale_diff -= n;
     398       22596 :                         for (i = packet_len; i > 0; ) {
     399             : #ifdef USE_I386_DIVIDE
     400             :                                 --i;
     401             :                                 /* For different reasons this code is still here.
     402             :                                  * But mainly because although compilers do wonderful things this is hard to get.
     403             :                                  * One of the reason is that it's hard to understand that the double-precision division
     404             :                                  * result will fit into 32-bit.
     405             :                                  */
     406             :                                 __asm__ ("divl %4": "=a"(packet[i]), "=d"(borrow): "0"(packet[i]), "1"(borrow), "r"(factor));
     407             : #else
     408        8692 :                                 TDS_DWORD n = (((TDS_DWORD) borrow) << TDS_WORD_BITS) + packet[--i];
     409             : #if defined(USE_128_MULTIPLY)
     410        8692 :                                 TDS_DWORD quotient = __umulh(n, reverse_divider);
     411             : #else
     412             :                                 TDS_DWORD mul1 = (TDS_DWORD) packet[i] * reverse_divider_low;
     413             :                                 TDS_DWORD mul2 = (TDS_DWORD) borrow * reverse_divider_low + (mul1 >> TDS_WORD_BITS);
     414             :                                 TDS_DWORD mul3 = (TDS_DWORD) packet[i] * reverse_divider_high;
     415             :                                 TDS_DWORD quotient = (TDS_DWORD) borrow * reverse_divider_high + (mul3 >> TDS_WORD_BITS);
     416             :                                 quotient += (mul2 + (mul3 & 0xffffffffu)) >> TDS_WORD_BITS;
     417             : #endif
     418        8692 :                                 quotient >>= shift;
     419        8692 :                                 packet[i] = (TDS_WORD) quotient;
     420        8692 :                                 borrow = (TDS_WORD) (n - quotient * factor);
     421             : #endif
     422             :                         }
     423        6952 :                 } while (scale_diff > 0);
     424             :         }
     425             : 
     426             :         /* back to our format */
     427       14106 :         numeric->precision = new_prec;
     428       14106 :         numeric->scale = new_scale;
     429       14106 :         bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
     430       36692 :         for (i = bytes / sizeof(TDS_WORD); i >= packet_len; --i)
     431       22586 :                 packet[i] = 0;
     432       25726 :         for (i = 0; bytes >= (int) sizeof(TDS_WORD); bytes -= sizeof(TDS_WORD), ++i) {
     433       25726 :                 TDS_PUT_UA4BE(&numeric->array[bytes-3], packet[i]);
     434             :         }
     435             : 
     436       14106 :         if (bytes) {
     437       13440 :                 TDS_WORD remainder = packet[i];
     438             :                 do {
     439       13790 :                         numeric->array[bytes] = (TDS_UCHAR) remainder;
     440       13790 :                         remainder >>= 8;
     441       13790 :                 } while (--bytes);
     442             :         }
     443             : 
     444             :         return sizeof(TDS_NUMERIC);
     445             : }
     446             : 

Generated by: LCOV version 1.13