MySQL 9.1.0
Source Code Documentation
my_decimal.h
Go to the documentation of this file.
1/* Copyright (c) 2005, 2024, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is designed to work with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have either included with
13 the program or referenced in the documentation.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23
24#ifndef MY_DECIMAL_INCLUDED
25#define MY_DECIMAL_INCLUDED
26
27/**
28 @file
29
30 It is interface module to fixed precision decimals library.
31
32 Most functions use 'uint mask' as parameter, if during operation error
33 which fit in this mask is detected then it will be processed automatically
34 here. (errors are E_DEC_* constants, see include/decimal.h)
35
36 Most function are just inline wrappers around library calls
37*/
38
39#include <assert.h>
40#include <stdlib.h>
41#include <sys/types.h>
42#include <algorithm>
43#include <array>
44
45#include "decimal.h"
46
47#include "my_inttypes.h"
48#include "my_macros.h"
49#include "my_time_t.h"
50#include "mysql/strings/dtoa.h"
52
53class String;
54struct MYSQL_TIME;
55
56static constexpr int DECIMAL_LONGLONG_DIGITS{22};
57
58/** maximum length of buffer in our big digits (uint32). */
59static constexpr int DECIMAL_BUFF_LENGTH{9};
60
61/** the number of digits that my_decimal can possibly contain */
63
64/**
65 maximum guaranteed precision of number in decimal digits (number of our
66 digits * number of decimal digits in one our big digit - number of decimal
67 digits in one our big digit decreased by 1 (because we always put decimal
68 point on the border of our big digits))
69*/
71 8 * 2};
72
73/**
74 maximum length of string representation (number of maximum decimal
75 digits + 1 position for sign + 1 position for decimal point, no terminator)
76*/
78
79/**
80 maximum size of packet length.
81*/
83
84inline int my_decimal_int_part(uint precision, uint decimals) {
85 return precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals);
86}
87
88/**
89 my_decimal class limits 'decimal_t' type to what we need in MySQL.
90
91 It contains internally all necessary space needed by the instance so
92 no extra memory is needed. Objects should be moved using copy CTOR
93 or assignment operator, rather than memcpy/memmove.
94*/
95
96class my_decimal : public decimal_t {
97 std::array<decimal_digit_t, DECIMAL_BUFF_LENGTH> buffer;
98
99 public:
100 my_decimal(const my_decimal &rhs) : decimal_t(rhs), buffer(rhs.buffer) {
101 rhs.sanity_check();
102 buf = buffer.data();
103 }
104
106 sanity_check();
107 rhs.sanity_check();
108 if (this == &rhs) return *this;
109 decimal_t::operator=(rhs);
110 buffer = rhs.buffer;
111 buf = buffer.data();
112 return *this;
113 }
114
115 void init() {
117 buf = buffer.data();
118 decimal_make_zero(this);
119 }
120
122
123#ifndef NDEBUG
125#endif // NDEBUG
126
127 void sanity_check() const { assert(buf == buffer.data()); }
128
129 bool sign() const { return decimal_t::sign; }
130 void sign(bool s) { decimal_t::sign = s; }
131 uint precision() const { return intg + frac; }
132
133 /** Swap two my_decimal values */
134 void swap(my_decimal &rhs) { std::swap(*this, rhs); }
135
136#ifndef MYSQL_SERVER
137 // Error reporting in server code only.
138 int check_result(uint, int result) const { return result; }
139#else
140 int check_result(uint, int result) const;
141#endif
142};
143
144#ifndef NDEBUG
145void print_decimal(const my_decimal *dec);
146void print_decimal_buff(const my_decimal *dec, const uchar *ptr, int length);
147const char *dbug_decimal_as_string(char *buff, const my_decimal *val);
148#else
149#define dbug_decimal_as_string(A) NULL
150#endif
151
152bool str_set_decimal(uint mask, const my_decimal *val, String *str,
153 const CHARSET_INFO *cs, uint decimals);
154
155inline void max_my_decimal(my_decimal *to, int precision, int frac) {
156 assert((precision <= DECIMAL_MAX_PRECISION) && (frac <= DECIMAL_MAX_SCALE));
157 max_decimal(precision, frac, to);
158}
159
162}
163
164inline int check_result_and_overflow(uint mask, int result, my_decimal *val) {
165 if (val->check_result(mask, result) & E_DEC_OVERFLOW) {
166 const bool sign = val->sign();
167 val->sanity_check();
169 val->sign(sign);
170 }
171 /*
172 Avoid returning negative zero, cfr. decimal_cmp()
173 For result == E_DEC_DIV_ZERO *val has not been assigned.
174 */
175 if (result != E_DEC_DIV_ZERO && val->sign() && decimal_is_zero(val))
176 val->sign(false);
177 return result;
178}
179
180inline uint my_decimal_length_to_precision(uint length, uint scale,
181 bool unsigned_flag) {
182 /* Precision can't be negative thus ignore unsigned_flag when length is 0. */
183 assert(length || !scale);
184 const uint retval =
185 (uint)(length - (scale > 0 ? 1 : 0) - (unsigned_flag || !length ? 0 : 1));
186 return retval;
187}
188
190 uint8 scale,
191 bool unsigned_flag) {
192 /*
193 When precision is 0 it means that original length was also 0. Thus
194 unsigned_flag is ignored in this case.
195 */
196 assert(precision || !scale);
197 const uint32 retval = (uint32)(precision + (scale > 0 ? 1 : 0) +
198 (unsigned_flag || !precision ? 0 : 1));
199 if (retval == 0) return 1;
200 return retval;
201}
202
203inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
204 bool unsigned_flag) {
205 /*
206 When precision is 0 it means that original length was also 0. Thus
207 unsigned_flag is ignored in this case.
208 */
209 assert(precision || !scale);
210 precision = std::min(precision, uint(DECIMAL_MAX_PRECISION));
211 return my_decimal_precision_to_length_no_truncation(precision, scale,
212 unsigned_flag);
213}
214
216 /* length of string representation including terminating '\0' */
217 return decimal_string_size(d);
218}
219
220inline int my_decimal_get_binary_size(uint precision, uint scale) {
221 return decimal_bin_size((int)precision, (int)scale);
222}
223
224inline void my_decimal2decimal(const my_decimal *from, my_decimal *to) {
225 *to = *from;
226}
227
228int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec,
229 int scale);
230
231inline int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d,
232 int prec, int scale) {
233 return d->check_result(mask, bin2decimal(bin, d, prec, scale, false));
234}
235
236/**
237 Decode DECIMAL from binary form
238
239 @param mask Error mask
240 @param bin Binary string to decode
241 @param d [out] DECIMAL buffer
242 @param prec Precision of stored value
243 @param scale Scale of stored value
244 @param keep_prec Whether to keep stored value's precision
245
246 @returns
247 conversion error
248*/
249
250inline int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d,
251 int prec, int scale, bool keep_prec) {
252 return d->check_result(mask, bin2decimal(bin, d, prec, scale, keep_prec));
253}
254
256 /*
257 We need the up-cast here, since my_decimal has sign() member functions,
258 which conflicts with decimal_t::size
259 (and decimal_make_zero is a macro, rather than a function).
260 */
261 decimal_make_zero(static_cast<decimal_t *>(d));
262 return 0;
263}
264
265inline bool my_decimal_is_zero(const my_decimal *decimal_value) {
266 return decimal_is_zero(decimal_value);
267}
268
269inline int my_decimal_round(uint mask, const my_decimal *from, int scale,
270 bool truncate, my_decimal *to) {
271 return from->check_result(
272 mask, decimal_round(from, to, scale, (truncate ? TRUNCATE : HALF_UP)));
273}
274
275inline int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to) {
276 return from->check_result(mask, decimal_round(from, to, 0, FLOOR));
277}
278
279inline int my_decimal_ceiling(uint mask, const my_decimal *from,
280 my_decimal *to) {
281 return from->check_result(mask, decimal_round(from, to, 0, CEILING));
282}
283
284int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec,
285 uint fixed_dec, String *str);
286
287inline int my_decimal2string(uint mask, const my_decimal *d, String *str) {
288 return my_decimal2string(mask, d, 0, 0, str);
289}
290
291inline int my_decimal2int(uint mask, const my_decimal *d, bool unsigned_flag,
292 longlong *l) {
293 my_decimal rounded;
294 /* decimal_round can return only E_DEC_TRUNCATED */
295 decimal_round(d, &rounded, 0, HALF_UP);
296 return d->check_result(
297 mask, (unsigned_flag ? decimal2ulonglong(&rounded, (ulonglong *)l)
298 : decimal2longlong(&rounded, l)));
299}
300
301inline int my_decimal2double(uint, const my_decimal *d, double *result) {
302 /* No need to call check_result as this will always succeed */
303 return decimal2double(d, result);
304}
305
306inline int my_decimal2lldiv_t(uint mask, const my_decimal *d, lldiv_t *to) {
307 return d->check_result(mask, decimal2lldiv_t(d, to));
308}
309
310inline int str2my_decimal(uint mask, const char *str, my_decimal *d,
311 const char **end) {
313}
314
315int str2my_decimal(uint mask, const char *from, size_t length,
316 const CHARSET_INFO *charset, my_decimal *decimal_value);
317
321
322inline int double2my_decimal(uint mask, double val, my_decimal *d) {
324}
325
326inline int int2my_decimal(uint mask, longlong i, bool unsigned_flag,
327 my_decimal *d) {
328 return d->check_result(mask,
329 (unsigned_flag ? ulonglong2decimal((ulonglong)i, d)
330 : longlong2decimal(i, d)));
331}
332
333inline void my_decimal_neg(decimal_t *arg) {
334 // Avoid returning negative zero, cfr. decimal_cmp()
335 if (decimal_is_zero(arg)) {
336 arg->sign = false;
337 return;
338 }
339 arg->sign ^= 1;
340}
341
342inline int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a,
343 const my_decimal *b) {
344 return check_result_and_overflow(mask, decimal_add(a, b, res), res);
345}
346
347inline int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a,
348 const my_decimal *b) {
349 return check_result_and_overflow(mask, decimal_sub(a, b, res), res);
350}
351
352inline int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a,
353 const my_decimal *b) {
354 return check_result_and_overflow(mask, decimal_mul(a, b, res), res);
355}
356
357inline int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a,
358 const my_decimal *b, int div_scale_inc) {
359 return check_result_and_overflow(mask, decimal_div(a, b, res, div_scale_inc),
360 res);
361}
362
363inline int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a,
364 const my_decimal *b) {
365 return check_result_and_overflow(mask, decimal_mod(a, b, res), res);
366}
367
368/**
369 @retval -1 if a @< b
370 @retval 1 if a @> b
371 @retval 0 if a == b
372*/
373inline int my_decimal_cmp(const my_decimal *a, const my_decimal *b) {
374 return decimal_cmp(a, b);
375}
376
377inline bool operator<(const my_decimal &lhs, const my_decimal &rhs) {
378 return my_decimal_cmp(&lhs, &rhs) < 0;
379}
380
381inline bool operator!=(const my_decimal &lhs, const my_decimal &rhs) {
382 return my_decimal_cmp(&lhs, &rhs) != 0;
383}
384
385inline int my_decimal_intg(const my_decimal *a) { return decimal_intg(a); }
386
387void my_decimal_trim(ulong *precision, uint *scale);
388
389#endif // MY_DECIMAL_INCLUDED
Using this class is fraught with peril, and you need to be very careful when doing so.
Definition: sql_string.h:167
my_decimal class limits 'decimal_t' type to what we need in MySQL.
Definition: my_decimal.h:96
int check_result(uint, int result) const
report result of decimal operation.
Definition: my_decimal.cc:61
void sign(bool s)
Definition: my_decimal.h:130
my_decimal()
Definition: my_decimal.h:121
void init()
Definition: my_decimal.h:115
my_decimal & operator=(const my_decimal &rhs)
Definition: my_decimal.h:105
void sanity_check() const
Definition: my_decimal.h:127
my_decimal(const my_decimal &rhs)
Definition: my_decimal.h:100
uint precision() const
Definition: my_decimal.h:131
~my_decimal()
Definition: my_decimal.h:124
bool sign() const
Definition: my_decimal.h:129
void swap(my_decimal &rhs)
Swap two my_decimal values.
Definition: my_decimal.h:134
std::array< decimal_digit_t, DECIMAL_BUFF_LENGTH > buffer
Definition: my_decimal.h:97
int decimal_round(const decimal_t *from, decimal_t *to, int new_scale, decimal_round_mode mode)
Definition: decimal.cc:1653
int decimal_bin_size(int precision, int scale)
Definition: decimal.cc:1631
int decimal2longlong(const decimal_t *from, longlong *to)
Definition: decimal.cc:1175
int ulonglong2decimal(ulonglong from, decimal_t *to)
Definition: decimal.cc:1139
int decimal_mul(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
Definition: decimal.cc:2083
static int decimal_string_size(const decimal_t *dec)
Returns the length of the buffer to hold string representation of the decimal (including decimal dot,...
Definition: decimal.h:135
int bin2decimal(const uchar *from, decimal_t *to, int precision, int scale, bool keep_prec=false)
Definition: decimal.cc:1486
int decimal_mod(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
Definition: decimal.cc:2510
@ CEILING
Definition: decimal.h:38
@ FLOOR
Definition: decimal.h:39
@ HALF_UP
Definition: decimal.h:37
@ TRUNCATE
Definition: decimal.h:35
int decimal_add(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
Definition: decimal.cc:2034
int decimal_is_zero(const decimal_t *from)
Definition: decimal.cc:2054
#define E_DEC_DIV_ZERO
Definition: decimal.h:151
int longlong2decimal(longlong from, decimal_t *to)
Definition: decimal.cc:1144
int decimal2lldiv_t(const decimal_t *from, lldiv_t *to)
Convert decimal to lldiv_t.
Definition: decimal.cc:1222
void max_decimal(int precision, int frac, decimal_t *to)
Definition: decimal.cc:432
int decimal2ulonglong(const decimal_t *from, ulonglong *to)
Definition: decimal.cc:1151
int decimal_div(const decimal_t *from1, const decimal_t *from2, decimal_t *to, int scale_incr)
Definition: decimal.cc:2478
int string2decimal(const char *from, decimal_t *to, const char **end)
Definition: decimal.cc:932
static void decimal_make_zero(decimal_t *dec)
Definition: decimal.h:124
int decimal2double(const decimal_t *from, double *to)
Definition: decimal.cc:1075
int decimal_cmp(const decimal_t *from1, const decimal_t *from2)
Definition: decimal.cc:2044
int decimal_intg(const decimal_t *from)
Returns the number of decimal digits before the decimal point in a decimal_t, with any insignificant ...
Definition: decimal.cc:2028
int double2decimal(double from, decimal_t *to)
Definition: decimal.cc:1100
int decimal_sub(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
Definition: decimal.cc:2039
#define E_DEC_OVERFLOW
Definition: decimal.h:150
static constexpr int DECIMAL_NOT_SPECIFIED
Definition: dtoa.h:54
static constexpr int DECIMAL_MAX_SCALE
Definition: dtoa.h:53
static const std::string dec("DECRYPTION")
A better implementation of the UNIX ctype(3) library.
static mi_bit_type mask[]
Definition: mi_packrec.cc:141
int my_decimal_int_part(uint precision, uint decimals)
Definition: my_decimal.h:84
int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec, int scale)
Definition: my_decimal.cc:223
void max_internal_decimal(my_decimal *to)
Definition: my_decimal.h:160
int check_result_and_overflow(uint mask, int result, my_decimal *val)
Definition: my_decimal.h:164
int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b)
Definition: my_decimal.h:347
int int2my_decimal(uint mask, longlong i, bool unsigned_flag, my_decimal *d)
Definition: my_decimal.h:326
void print_decimal_buff(const my_decimal *dec, const uchar *ptr, int length)
Definition: my_decimal.cc:370
my_decimal * timeval2my_decimal(const my_timeval *tm, my_decimal *dec)
Convert timeval value to my_decimal.
Definition: my_decimal.cc:335
int double2my_decimal(uint mask, double val, my_decimal *d)
Definition: my_decimal.h:322
bool operator!=(const my_decimal &lhs, const my_decimal &rhs)
Definition: my_decimal.h:381
void max_my_decimal(my_decimal *to, int precision, int frac)
Definition: my_decimal.h:155
int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec, uint fixed_dec, String *str)
Converting decimal to string.
Definition: my_decimal.cc:126
static constexpr int DECIMAL_MAX_FIELD_SIZE
maximum size of packet length.
Definition: my_decimal.h:82
int my_decimal_get_binary_size(uint precision, uint scale)
Definition: my_decimal.h:220
static constexpr int DECIMAL_LONGLONG_DIGITS
Definition: my_decimal.h:56
int my_decimal2lldiv_t(uint mask, const my_decimal *d, lldiv_t *to)
Definition: my_decimal.h:306
bool str_set_decimal(uint mask, const my_decimal *val, String *str, const CHARSET_INFO *cs, uint decimals)
Converting decimal to string with character set conversion.
Definition: my_decimal.cc:172
int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b)
Definition: my_decimal.h:342
static constexpr int DECIMAL_BUFF_LENGTH
maximum length of buffer in our big digits (uint32).
Definition: my_decimal.h:59
int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b)
Definition: my_decimal.h:363
void my_decimal_neg(decimal_t *arg)
Definition: my_decimal.h:333
int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to)
Definition: my_decimal.h:275
int my_decimal2double(uint, const my_decimal *d, double *result)
Definition: my_decimal.h:301
bool my_decimal_is_zero(const my_decimal *decimal_value)
Definition: my_decimal.h:265
void print_decimal(const my_decimal *dec)
Definition: my_decimal.cc:357
uint my_decimal_length_to_precision(uint length, uint scale, bool unsigned_flag)
Definition: my_decimal.h:180
int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec, int scale)
Definition: my_decimal.h:231
uint32 my_decimal_precision_to_length(uint precision, uint8 scale, bool unsigned_flag)
Definition: my_decimal.h:203
void my_decimal_trim(ulong *precision, uint *scale)
Definition: my_decimal.cc:342
int my_decimal_cmp(const my_decimal *a, const my_decimal *b)
Definition: my_decimal.h:373
my_decimal * date2my_decimal(const MYSQL_TIME *ltime, my_decimal *dec)
Convert datetime value to my_decimal in format YYYYMMDDhhmmss.ffffff.
Definition: my_decimal.cc:311
bool operator<(const my_decimal &lhs, const my_decimal &rhs)
Definition: my_decimal.h:377
int my_decimal_intg(const my_decimal *a)
Definition: my_decimal.h:385
int my_decimal_set_zero(my_decimal *d)
Definition: my_decimal.h:255
int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b, int div_scale_inc)
Definition: my_decimal.h:357
int my_decimal_round(uint mask, const my_decimal *from, int scale, bool truncate, my_decimal *to)
Definition: my_decimal.h:269
my_decimal * time2my_decimal(const MYSQL_TIME *ltime, my_decimal *dec)
Convert time value to my_decimal in format hhmmss.ffffff.
Definition: my_decimal.cc:325
void my_decimal2decimal(const my_decimal *from, my_decimal *to)
Definition: my_decimal.h:224
static constexpr int DECIMAL_MAX_PRECISION
maximum guaranteed precision of number in decimal digits (number of our digits * number of decimal di...
Definition: my_decimal.h:70
int my_decimal2int(uint mask, const my_decimal *d, bool unsigned_flag, longlong *l)
Definition: my_decimal.h:291
static constexpr int DECIMAL_MAX_STR_LENGTH
maximum length of string representation (number of maximum decimal digits + 1 position for sign + 1 p...
Definition: my_decimal.h:77
int my_decimal_string_length(const my_decimal *d)
Definition: my_decimal.h:215
int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to)
Definition: my_decimal.h:279
static constexpr int DECIMAL_MAX_POSSIBLE_PRECISION
the number of digits that my_decimal can possibly contain
Definition: my_decimal.h:62
int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b)
Definition: my_decimal.h:352
int str2my_decimal(uint mask, const char *str, my_decimal *d, const char **end)
Definition: my_decimal.h:310
const char * dbug_decimal_as_string(char *buff, const my_decimal *val)
Definition: my_decimal.cc:379
uint32 my_decimal_precision_to_length_no_truncation(uint precision, uint8 scale, bool unsigned_flag)
Definition: my_decimal.h:189
Some integer typedefs for easier portability.
unsigned long long int ulonglong
Definition: my_inttypes.h:56
uint8_t uint8
Definition: my_inttypes.h:63
unsigned char uchar
Definition: my_inttypes.h:52
long long int longlong
Definition: my_inttypes.h:55
uint32_t uint32
Definition: my_inttypes.h:67
Some common macros.
std::string str(const mysqlrouter::ConfigGenerator::Options::Endpoint &ep)
Definition: config_generator.cc:1105
Definition: buf0block_hint.cc:30
const std::string charset("charset")
Definition: commit_order_queue.h:34
bool length(const dd::Spatial_reference_system *srs, const Geometry *g1, double *length, bool *null) noexcept
Computes the length of linestrings and multilinestrings.
Definition: length.cc:76
Cursor end()
A past-the-end Cursor.
Definition: rules_table_service.cc:192
struct result result
Definition: result.h:34
static void swap(String &a, String &b) noexcept
Definition: sql_string.h:663
Definition: m_ctype.h:421
Definition: mysql_time.h:82
Base struct used to represent decimal data type.
Definition: decimal.h:49
int frac
The number of decimal digits after the point.
Definition: decimal.h:54
int intg
The number of decimal digits (NOT number of decimal_digit_t's !) before the point.
Definition: decimal.h:52
bool sign
False means positive, true means negative.
Definition: decimal.h:59
int len
The length of buf (length of allocated space) in decimal_digit_t's, not in bytes.
Definition: decimal.h:57
Replacement of system's struct timeval to ensure we can carry 64 bit values even on a platform which ...
Definition: my_time_t.h:45
Definition: result.h:30