LCOV - code coverage report
Current view: top level - sql/server - sql_decimal.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 98 101 97.0 %
Date: 2024-10-07 21:21:43 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : 
      15             : #include "sql_decimal.h"
      16             : 
      17             : 
      18             : DEC_TPE
      19        9560 : decimal_from_str(const char *dec, int* digits, int* scale, int* has_errors)
      20             : {
      21             : 
      22             : #ifdef HAVE_HGE
      23        9560 :     const hge max0 = GDK_hge_max / 10, max1 = GDK_hge_max % 10;
      24             : #else
      25             :     const lng max0 = GDK_lng_max / 10, max1 = GDK_lng_max % 10;
      26             : #endif
      27             : 
      28        9560 :         assert(digits);
      29        9560 :         assert(scale);
      30        9560 :         assert(has_errors);
      31             : 
      32        9560 :         DEC_TPE res = 0;
      33        9560 :         *has_errors = 0;
      34             : 
      35        9560 :         int _digits     = 0;
      36        9560 :         int _scale      = 0;
      37             : 
      38             : // preceding whitespace:
      39        9560 :         int neg = 0;
      40        9602 :         while(isspace((unsigned char) *dec))
      41          42 :                 dec++;
      42             : 
      43             : // optional sign:
      44        9560 :         if (*dec == '-') {
      45         175 :                 neg = 1;
      46         175 :                 dec++;
      47        9385 :         } else if (*dec == '+') {
      48           8 :                 dec++;
      49             :         }
      50             : 
      51             : // optional fractional separator first opportunity
      52        9560 :         if (*dec == '.') {  // case: (+|-).456
      53          46 : fractional_sep_first_opp:
      54        3639 :                 dec++;
      55        3639 :                 goto trailing_digits;
      56             :         }
      57             : 
      58             : // preceding_digits:
      59        9514 :         if (!isdigit((unsigned char) *dec)) {
      60          66 :                 *has_errors = 1;
      61          66 :                 goto end_state;
      62             :         }
      63        9485 :         while (*dec == '0'){
      64             :                 // skip leading zeros in preceding digits, e.g. '0004563.1234' => '4563.1234'
      65        3630 :                 dec++;
      66        3630 :                 if (*dec == '.') {
      67        3593 :                         _digits = 1; // case: 0.xyz the zero. the single preceding zero counts for one digit by convention.
      68        3593 :                         goto fractional_sep_first_opp;
      69             :                 }
      70             :         }
      71       24958 :         for (; *dec && (isdigit((unsigned char) *dec)); dec++) {
      72       19103 :                 if (res > max0 || (res == max0 && *dec - '0' > max1)) {
      73           0 :                         *has_errors = 1;
      74           0 :                         return 0;
      75             :                 }
      76       19103 :                 res *= 10;
      77       19103 :                 res += *dec - '0';
      78       19103 :                 _digits++;
      79             :         }
      80             : 
      81             : // optional fractional separator second opportunity
      82        5855 :         if (*dec == '.')        // case: (+|-)123.(456)
      83        5734 :                 dec++;
      84             :         else                                    // case:  (+|-)123
      85         121 :                 goto trailing_whitespace;
      86             : 
      87        9373 : trailing_digits:
      88        9373 :         if (!isdigit((unsigned char) *dec))
      89           7 :                 goto trailing_whitespace;
      90       40503 :         for (; *dec && (isdigit((unsigned char) *dec)); dec++) {
      91       31280 :                 if (res > max0 || (res == max0 && *dec - '0' > max1)) {
      92         143 :                         *has_errors = 1;
      93         143 :                         return 0;
      94             :                 }
      95       31137 :                 res *= 10;
      96       31137 :                 res += *dec - '0';
      97       31137 :                 _scale++;
      98             :         }
      99        9223 :         _digits += _scale;
     100             : 
     101        9351 : trailing_whitespace:
     102        9365 :         while(isspace((unsigned char) *dec))
     103          14 :                 dec++;
     104             : 
     105        9351 : end_state:
     106             :         /* When the string cannot be parsed up to and including the null terminator,
     107             :          * the string is an invalid decimal representation. */
     108        9417 :         if (*dec != 0)
     109          73 :                 *has_errors = 1;
     110             : 
     111        9417 :         *digits = _digits;
     112        9417 :         *scale = _scale;
     113             : 
     114        9417 :         if (neg)
     115         175 :                 return -res;
     116             :         else
     117             :                 return res;
     118             : }
     119             : 
     120             : char *
     121             : #ifdef HAVE_HGE
     122          24 : decimal_to_str(allocator *sa, hge v, sql_subtype *t)
     123             : #else
     124             : decimal_to_str(allocator *sa, lng v, sql_subtype *t)
     125             : #endif
     126             : {
     127          24 :         char buf[64];
     128          24 :         unsigned int scale = t->scale, i;
     129          24 :         int cur = 63, neg = (v<0), done = 0;
     130             : 
     131          24 :         if (v<0) v = -v;
     132             : 
     133          24 :         buf[cur--] = 0;
     134          24 :         if (scale){
     135         138 :                 for (i=0; i<scale; i++) {
     136         114 :                         buf[cur--] = (char) (v%10 + '0');
     137         114 :                         v /= 10;
     138             :                 }
     139          24 :                 buf[cur--] = '.';
     140             :         }
     141          44 :         while (v) {
     142          20 :                 buf[cur--] = (char ) (v%10 + '0');
     143          20 :                 v /= 10;
     144          20 :                 done = 1;
     145             :         }
     146          24 :         if (!done)
     147          10 :                 buf[cur--] = '0';
     148          24 :         if (neg)
     149           0 :                 buf[cur--] = '-';
     150          24 :         assert(cur >= -1);
     151          24 :         return sa_strdup(sa, buf+cur+1);
     152             : }
     153             : 
     154             : unsigned int
     155             : #ifdef HAVE_HGE
     156        3482 : decimal_digits(hge val)
     157             : #else
     158             : decimal_digits(lng val)
     159             : #endif
     160             : 
     161             : {
     162        3482 :         if (val < 0)
     163             :                 val = -val;
     164             :         unsigned int digits = 1;
     165       42738 :         while (val >= 10) {
     166       39256 :                 val /= 10;
     167       39256 :                 digits++;
     168             :         }
     169        3482 :         return digits;
     170             : }
     171             : 
     172             : #ifdef HAVE_HGE
     173             : extern hge
     174             : #else
     175             : extern lng
     176             : #endif
     177          17 : scale2value(int scale)
     178             : {
     179             : #ifdef HAVE_HGE
     180          17 :         hge val = 1;
     181             : #else
     182             :         lng val = 1;
     183             : #endif
     184             : 
     185          17 :         if (scale < 0)
     186             :                 scale = -scale;
     187          37 :         for (; scale; scale--) {
     188          20 :                 val = val * 10;
     189             :         }
     190          17 :         return val;
     191             : }
     192             : 
     193             : unsigned int
     194             : #ifdef HAVE_HGE
     195     7786846 : number_bits(hge val)
     196             : #else
     197             : number_bits(lng val)
     198             : #endif
     199             : {
     200     7786846 :         if (val < 0)
     201             :                 val = -val;
     202     7786846 :         unsigned bits = 0;
     203             : #ifdef HAVE_HGE
     204     7786846 :         hge m = (hge)1 << bits;
     205    43073382 :         for( ; (val & ~m) > m; bits++)
     206    35286536 :                 m = (hge)1 << bits;
     207             : #else
     208             :         lng m = (lng)1 << bits;
     209             :         for( ; (val & ~m) > m; bits++)
     210             :                 m = ((lng)1) << bits;
     211             : #endif
     212     7786846 :         if (!bits)
     213             :                 bits = 1;
     214     7786846 :         return bits;
     215             : }

Generated by: LCOV version 1.14