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

Generated by: LCOV version 1.13