LCOV - code coverage report
Current view: top level - sql/server - sql_decimal.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 84 87 96.6 %
Date: 2024-04-25 20:03:45 Functions: 3 3 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        9510 : decimal_from_str(const char *dec, int* digits, int* scale, int* has_errors)
      20             : {
      21             : 
      22             : #ifdef HAVE_HGE
      23        9510 :     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        9510 :         assert(digits);
      29        9510 :         assert(scale);
      30        9510 :         assert(has_errors);
      31             : 
      32        9510 :         DEC_TPE res = 0;
      33        9510 :         *has_errors = 0;
      34             : 
      35        9510 :         int _digits     = 0;
      36        9510 :         int _scale      = 0;
      37             : 
      38             : // preceding whitespace:
      39        9510 :         int neg = 0;
      40        9552 :         while(isspace((unsigned char) *dec))
      41          42 :                 dec++;
      42             : 
      43             : // optional sign:
      44        9510 :         if (*dec == '-') {
      45         175 :                 neg = 1;
      46         175 :                 dec++;
      47        9335 :         } else if (*dec == '+') {
      48           8 :                 dec++;
      49             :         }
      50             : 
      51             : // optional fractional separator first opportunity
      52        9510 :         if (*dec == '.') {  // case: (+|-).456
      53          46 : fractional_sep_first_opp:
      54        3630 :                 dec++;
      55        3630 :                 goto trailing_digits;
      56             :         }
      57             : 
      58             : // preceding_digits:
      59        9464 :         if (!isdigit((unsigned char) *dec)) {
      60          66 :                 *has_errors = 1;
      61          66 :                 goto end_state;
      62             :         }
      63        9435 :         while (*dec == '0'){
      64             :                 // skip leading zeros in preceding digits, e.g. '0004563.1234' => '4563.1234'
      65        3621 :                 dec++;
      66        3621 :                 if (*dec == '.') {
      67        3584 :                         _digits = 1; // case: 0.xyz the zero. the single preceding zero counts for one digit by convention.
      68        3584 :                         goto fractional_sep_first_opp;
      69             :                 }
      70             :         }
      71       24851 :         for (; *dec && (isdigit((unsigned char) *dec)); dec++) {
      72       19037 :                 if (res > max0 || (res == max0 && *dec - '0' > max1)) {
      73           0 :                         *has_errors = 1;
      74           0 :                         return 0;
      75             :                 }
      76       19037 :                 res *= 10;
      77       19037 :                 res += *dec - '0';
      78       19037 :                 _digits++;
      79             :         }
      80             : 
      81             : // optional fractional separator second opportunity
      82        5814 :         if (*dec == '.')        // case: (+|-)123.(456)
      83        5696 :                 dec++;
      84             :         else                                    // case:  (+|-)123
      85         118 :                 goto trailing_whitespace;
      86             : 
      87        9326 : trailing_digits:
      88        9326 :         if (!isdigit((unsigned char) *dec))
      89           7 :                 goto trailing_whitespace;
      90       40471 :         for (; *dec && (isdigit((unsigned char) *dec)); dec++) {
      91       31295 :                 if (res > max0 || (res == max0 && *dec - '0' > max1)) {
      92         143 :                         *has_errors = 1;
      93         143 :                         return 0;
      94             :                 }
      95       31152 :                 res *= 10;
      96       31152 :                 res += *dec - '0';
      97       31152 :                 _scale++;
      98             :         }
      99        9176 :         _digits += _scale;
     100             : 
     101        9301 : trailing_whitespace:
     102        9315 :         while(isspace((unsigned char) *dec))
     103          14 :                 dec++;
     104             : 
     105        9301 : 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        9367 :         if (*dec != 0)
     109          73 :                 *has_errors = 1;
     110             : 
     111        9367 :         *digits = _digits;
     112        9367 :         *scale = _scale;
     113             : 
     114        9367 :         if (neg)
     115         175 :                 return -res;
     116             :         else
     117             :                 return res;
     118             : }
     119             : 
     120             : char *
     121             : #ifdef HAVE_HGE
     122          24 : decimal_to_str(sql_allocator *sa, hge v, sql_subtype *t)
     123             : #else
     124             : decimal_to_str(sql_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             : #ifdef HAVE_HGE
     155             : extern hge
     156             : #else
     157             : extern lng
     158             : #endif
     159          22 : scale2value(int scale)
     160             : {
     161             : #ifdef HAVE_HGE
     162          22 :         hge val = 1;
     163             : #else
     164             :         lng val = 1;
     165             : #endif
     166             : 
     167          22 :         if (scale < 0)
     168             :                 scale = -scale;
     169          62 :         for (; scale; scale--) {
     170          40 :                 val = val * 10;
     171             :         }
     172          22 :         return val;
     173             : }

Generated by: LCOV version 1.14