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-01-18 11:50:39 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        1592 : 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        1592 :         mymoney = (((TDS_INT8) money->tdsoldmoney.mnyhigh) << 32) | money->tdsoldmoney.mnylow;
      73             : 
      74        1592 :         p = s;
      75        1592 :         if (mymoney < 0) {
      76         360 :                 *p++ = '-';
      77             :                 /* we use unsigned cause this cause arithmetic problem for -2^63*/
      78         360 :                 n = -mymoney;
      79             :         } else {
      80        1232 :                 n = mymoney;
      81             :         }
      82             :         /* if machine is 64 bit you do not need to split n */
      83        1592 :         if (use_2_digits) {
      84           0 :                 n = (n+ 50) / 100;
      85           0 :                 sprintf(p, "%" PRIu64 ".%02u", n / 100u, (unsigned) (n % 100u));
      86             :         } else {
      87        1592 :                 sprintf(p, "%" PRIu64 ".%04u", n / 10000u, (unsigned) (n % 10000u));
      88             :         }
      89        1592 :         return s;
      90             : }
      91             : 
      92             : /**
      93             :  * @return <0 if error
      94             :  */
      95             : TDS_INT
      96       10444 : 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       10444 :         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       10444 :         memset(packet, 0x55, sizeof(packet));
     113       10444 :         memset(packet10k, 0x55, sizeof(packet10k));
     114             : #endif
     115             : 
     116       10444 :         if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
     117             :                 return TDS_CONVERT_FAIL;
     118             : 
     119             :         /* set sign */
     120       10444 :         if (numeric->array[0] == 1)
     121        4078 :                 *s++ = '-';
     122             : 
     123             :         /* put number in a 16bit array */
     124       10444 :         number = numeric->array;
     125       10444 :         num_bytes = tds_numeric_bytes_per_prec[numeric->precision];
     126             : 
     127       10444 :         n = num_bytes - 1;
     128       10444 :         pnum = packet_end;
     129       52678 :         for (; n > 1; n -= 2)
     130       42234 :                 *--pnum = TDS_GET_UA2BE(&number[n - 1]);
     131       10444 :         if (n == 1)
     132        9590 :                 *--pnum = number[n];
     133       39256 :         while (!*pnum) {
     134       28948 :                 ++pnum;
     135       28948 :                 if (pnum == packet_end) {
     136         136 :                         *s++ = '0';
     137         136 :                         if (numeric->scale) {
     138           8 :                                 *s++ = '.';
     139           8 :                                 i = numeric->scale;
     140             :                                 do {
     141          32 :                                         *s++ = '0';
     142          32 :                                 } while (--i);
     143             :                         }
     144         136 :                         *s = 0;
     145         136 :                         return 1;
     146             :                 }
     147             :         }
     148             :         packet_start = pnum;
     149             : 
     150             :         /* transform 2^16 base number in 10^4 base number */
     151       37366 :         for (p = packet10k + TDS_VECTOR_SIZE(packet10k); packet_start != packet_end;) {
     152       27058 :                 pnum = packet_start;
     153       27058 :                 n = *pnum;
     154       27058 :                 remainder = n % 10000u;
     155       27058 :                 if (!(*pnum++ = (n / 10000u)))
     156       22876 :                         packet_start = pnum;
     157       28370 :                 for (; pnum != packet_end; ++pnum) {
     158       28370 :                         n = remainder * (256u * 256u) + *pnum;
     159       28370 :                         remainder = n % 10000u;
     160       28370 :                         *pnum = n / 10000u;
     161             :                 }
     162       27058 :                 *--p = remainder;
     163             :         }
     164             : 
     165             :         /* transform to 10 base number and output */
     166       10308 :         i = 4 * (unsigned int)((packet10k + TDS_VECTOR_SIZE(packet10k)) - p);   /* current digit */
     167             :         /* skip leading zeroes */
     168       10308 :         n = 1000;
     169       10308 :         remainder = *p;
     170       37194 :         while (remainder < n)
     171       16578 :                 n /= 10, --i;
     172       10308 :         if (i <= numeric->scale) {
     173          32 :                 *s++ = '0';
     174          32 :                 *s++ = '.';
     175          32 :                 m = i;
     176         128 :                 while (m < numeric->scale)
     177          64 :                         *s++ = '0', ++m;
     178             :         }
     179             :         for (;;) {
     180       91654 :                 *s++ = (remainder / n) + '0';
     181       91654 :                 --i;
     182       91654 :                 remainder %= n;
     183       91654 :                 n /= 10;
     184       91654 :                 if (!n) {
     185       27058 :                         n = 1000;
     186       27058 :                         if (++p == packet10k + TDS_VECTOR_SIZE(packet10k))
     187             :                                 break;
     188       16750 :                         remainder = *p;
     189             :                 }
     190       81346 :                 if (i == numeric->scale)
     191        1150 :                         *s++ = '.';
     192             :         }
     193       10308 :         *s = 0;
     194             : 
     195       10308 :         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       35054 : tds_packet_check_overflow(TDS_WORD *packet, unsigned int packet_len, unsigned int prec)
     208             : {
     209             :         unsigned int i, len, stop;
     210       35054 :         const TDS_WORD *limit = &limits[limit_indexes[prec] + LIMIT_INDEXES_ADJUST * prec];
     211       35054 :         len = limit_indexes[prec+1] - limit_indexes[prec] + LIMIT_INDEXES_ADJUST;
     212       35054 :         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       35054 :         if (packet_len >= len + stop) {
     221             :                 /* higher packets must be zero */
     222       26794 :                 for (i = packet_len; --i >= len + stop; )
     223        7640 :                         if (packet[i] > 0)
     224             :                                 return TDS_CONVERT_OVERFLOW;
     225             :                 /* test limit */
     226           0 :                 for (;; --i, ++limit) {
     227       19154 :                         if (i <= stop) {
     228             :                                 /* last must be >= not > */
     229       16050 :                                 if (packet[i] >= *limit)
     230             :                                         return TDS_CONVERT_OVERFLOW;
     231             :                                 break;
     232             :                         }
     233        3104 :                         if (packet[i] > *limit)
     234             :                                 return TDS_CONVERT_OVERFLOW;
     235         928 :                         if (packet[i] < *limit)
     236             :                                 break;
     237             :                 }
     238             :         }
     239       18190 :         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       64298 : 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       64298 :         if (numeric->precision < 1 || numeric->precision > MAXPRECISION || numeric->scale > numeric->precision)
     313             :                 return TDS_CONVERT_FAIL;
     314             : 
     315       64298 :         if (new_prec < 1 || new_prec > MAXPRECISION || new_scale > new_prec)
     316             :                 return TDS_CONVERT_FAIL;
     317             : 
     318       64298 :         scale_diff = new_scale - numeric->scale;
     319       64298 :         if (scale_diff == 0 && new_prec >= numeric->precision) {
     320       23886 :                 i = tds_numeric_bytes_per_prec[new_prec] - tds_numeric_bytes_per_prec[numeric->precision];
     321       23886 :                 if (i > 0) {
     322        9824 :                         memmove(numeric->array + 1 + i, numeric->array + 1, sizeof(numeric->array) - 1 - i);
     323        9824 :                         memset(numeric->array + 1, 0, i);
     324             :                 }
     325       23886 :                 numeric->precision = new_prec;
     326       23886 :                 return sizeof(TDS_NUMERIC);
     327             :         }
     328             : 
     329             :         /* package number */
     330       40412 :         bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
     331       40412 :         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      117994 :                 packet[i] = TDS_GET_UA4BE(&numeric->array[bytes-3]);
     339      117994 :                 ++i;
     340      117994 :         } while ( (bytes -= sizeof(TDS_WORD)) > 0);
     341             :         /* fix last packet */
     342       40412 :         if (bytes < 0)
     343       39704 :                 packet[i-1] &= 0xffffffffu >> (8 * -bytes);
     344      104394 :         while (i > 1 && packet[i-1] == 0)
     345             :                 --i;
     346       40412 :         packet_len = i;
     347             : 
     348       40412 :         if (scale_diff >= 0) {
     349             :                 /* check overflow before multiply */
     350       34734 :                 if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
     351             :                         return TDS_CONVERT_OVERFLOW;
     352             : 
     353       18070 :                 if (scale_diff == 0) {
     354       12274 :                         i = tds_numeric_bytes_per_prec[numeric->precision] - tds_numeric_bytes_per_prec[new_prec];
     355       12274 :                         if (i > 0)
     356       12274 :                                 memmove(numeric->array + 1, numeric->array + 1 + i, sizeof(numeric->array) - 1 - i);
     357       12274 :                         numeric->precision = new_prec;
     358       12274 :                         return sizeof(TDS_NUMERIC);
     359             :                 }
     360             : 
     361             :                 /* multiply */
     362             :                 do {
     363             :                         /* multiply by at maximun TDS_WORD_DDIGIT */
     364        5812 :                         unsigned int n = scale_diff > TDS_WORD_DDIGIT ? TDS_WORD_DDIGIT : scale_diff;
     365        5812 :                         TDS_WORD factor = factors[n];
     366        5812 :                         TDS_WORD carry = 0;
     367        5812 :                         scale_diff -= n; 
     368       12240 :                         for (i = 0; i < packet_len; ++i) {
     369        6428 :                                 TDS_DWORD n = packet[i] * ((TDS_DWORD) factor) + carry;
     370        6428 :                                 packet[i] = (TDS_WORD) n;
     371        6428 :                                 carry = n >> TDS_WORD_BITS;
     372             :                         }
     373             :                         /* here we can expand number safely cause we know that it can't overflow */
     374        5812 :                         if (carry)
     375         680 :                                 packet[packet_len++] = carry;
     376        5812 :                 } while (scale_diff > 0);
     377             :         } else {
     378             :                 /* check overflow */
     379        5678 :                 if (new_prec - scale_diff < numeric->precision)
     380         320 :                         if (tds_packet_check_overflow(packet, packet_len, new_prec - scale_diff))
     381             :                                 return TDS_CONVERT_OVERFLOW;
     382             : 
     383             :                 /* divide */
     384        5478 :                 scale_diff = -scale_diff;
     385             :                 do {
     386        5558 :                         unsigned int n = scale_diff > TDS_WORD_DDIGIT ? TDS_WORD_DDIGIT : scale_diff;
     387        5558 :                         TDS_WORD factor = factors[n];
     388        5558 :                         TDS_WORD borrow = 0;
     389             : #if defined(USE_128_MULTIPLY)
     390        5558 :                         TDS_DWORD reverse_divider = reverse_dividers[n];
     391        5558 :                         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        5558 :                         scale_diff -= n;
     398       18066 :                         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        6950 :                                 TDS_DWORD n = (((TDS_DWORD) borrow) << TDS_WORD_BITS) + packet[--i];
     409             : #if defined(USE_128_MULTIPLY)
     410        6950 :                                 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        6950 :                                 quotient >>= shift;
     419        6950 :                                 packet[i] = (TDS_WORD) quotient;
     420        6950 :                                 borrow = (TDS_WORD) (n - quotient * factor);
     421             : #endif
     422             :                         }
     423        5558 :                 } while (scale_diff > 0);
     424             :         }
     425             : 
     426             :         /* back to our format */
     427       11274 :         numeric->precision = new_prec;
     428       11274 :         numeric->scale = new_scale;
     429       11274 :         bytes = tds_numeric_bytes_per_prec[numeric->precision] - 1;
     430       29320 :         for (i = bytes / sizeof(TDS_WORD); i >= packet_len; --i)
     431       18046 :                 packet[i] = 0;
     432       20558 :         for (i = 0; bytes >= (int) sizeof(TDS_WORD); bytes -= sizeof(TDS_WORD), ++i) {
     433       20558 :                 TDS_PUT_UA4BE(&numeric->array[bytes-3], packet[i]);
     434             :         }
     435             : 
     436       11274 :         if (bytes) {
     437       10746 :                 TDS_WORD remainder = packet[i];
     438             :                 do {
     439       11026 :                         numeric->array[bytes] = (TDS_UCHAR) remainder;
     440       11026 :                         remainder >>= 8;
     441       11026 :                 } while (--bytes);
     442             :         }
     443             : 
     444             :         return sizeof(TDS_NUMERIC);
     445             : }
     446             : 

Generated by: LCOV version 1.13