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 9571 : decimal_from_str(const char *dec, int* digits, int* scale, int* has_errors) 20 : { 21 : 22 : #ifdef HAVE_HGE 23 9571 : 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 9571 : assert(digits); 29 9571 : assert(scale); 30 9571 : assert(has_errors); 31 : 32 9571 : DEC_TPE res = 0; 33 9571 : *has_errors = 0; 34 : 35 9571 : int _digits = 0; 36 9571 : int _scale = 0; 37 : 38 : // preceding whitespace: 39 9571 : int neg = 0; 40 9613 : while(isspace((unsigned char) *dec)) 41 42 : dec++; 42 : 43 : // optional sign: 44 9571 : if (*dec == '-') { 45 175 : neg = 1; 46 175 : dec++; 47 9396 : } else if (*dec == '+') { 48 8 : dec++; 49 : } 50 : 51 : // optional fractional separator first opportunity 52 9571 : if (*dec == '.') { // case: (+|-).456 53 46 : fractional_sep_first_opp: 54 3646 : dec++; 55 3646 : goto trailing_digits; 56 : } 57 : 58 : // preceding_digits: 59 9525 : if (!isdigit((unsigned char) *dec)) { 60 66 : *has_errors = 1; 61 66 : goto end_state; 62 : } 63 9495 : while (*dec == '0'){ 64 : // skip leading zeros in preceding digits, e.g. '0004563.1234' => '4563.1234' 65 3636 : dec++; 66 3636 : if (*dec == '.') { 67 3600 : _digits = 1; // case: 0.xyz the zero. the single preceding zero counts for one digit by convention. 68 3600 : goto fractional_sep_first_opp; 69 : } 70 : } 71 24974 : for (; *dec && (isdigit((unsigned char) *dec)); dec++) { 72 19115 : if (res > max0 || (res == max0 && *dec - '0' > max1)) { 73 0 : *has_errors = 1; 74 0 : return 0; 75 : } 76 19115 : res *= 10; 77 19115 : res += *dec - '0'; 78 19115 : _digits++; 79 : } 80 : 81 : // optional fractional separator second opportunity 82 5859 : if (*dec == '.') // case: (+|-)123.(456) 83 5737 : dec++; 84 : else // case: (+|-)123 85 122 : goto trailing_whitespace; 86 : 87 9383 : trailing_digits: 88 9383 : if (!isdigit((unsigned char) *dec)) 89 7 : goto trailing_whitespace; 90 40523 : for (; *dec && (isdigit((unsigned char) *dec)); dec++) { 91 31290 : if (res > max0 || (res == max0 && *dec - '0' > max1)) { 92 143 : *has_errors = 1; 93 143 : return 0; 94 : } 95 31147 : res *= 10; 96 31147 : res += *dec - '0'; 97 31147 : _scale++; 98 : } 99 9233 : _digits += _scale; 100 : 101 9362 : trailing_whitespace: 102 9376 : while(isspace((unsigned char) *dec)) 103 14 : dec++; 104 : 105 9362 : 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 9428 : if (*dec != 0) 109 73 : *has_errors = 1; 110 : 111 9428 : *digits = _digits; 112 9428 : *scale = _scale; 113 : 114 9428 : 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 7819688 : number_bits(hge val) 196 : #else 197 : number_bits(lng val) 198 : #endif 199 : { 200 7819688 : if (val < 0) 201 : val = -val; 202 7819688 : unsigned bits = 0; 203 : #ifdef HAVE_HGE 204 7819688 : hge m = (hge)1 << bits; 205 43235542 : for( ; (val & ~m) > m; bits++) 206 35415854 : 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 7819688 : if (!bits) 213 : bits = 1; 214 7819688 : return bits; 215 : }