~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mystrings/decimal.cc

Replace MAX_(DATE|TIME).*_WIDTH defines in definitions.h with real (and correct) static const members to Temporal types.

This fixes the buffer overflow in https://bugs.launchpad.net/drizzle/+bug/373468

It also removes a handwritten snprintf in field/datetime.cc
However... this caused us to have to change Temporal to have a way to not
"convert" the int64_t value (so 20090101 becomes 20090101000000 etc) as it
has already been converted and we just want the Temporal type to do the
to_string conversion.

This still causes a failure in 'metadata' test due to size of timestamp type. I need feedback from Jay on when the usecond code comes into play to know the correct fix for this.

Show diffs side-by-side

added added

removed removed

Lines of Context:
97
97
      implementation-defined.
98
98
*/
99
99
 
100
 
#include "config.h"
 
100
#include <drizzled/global.h>
101
101
 
102
 
#include "drizzled/definitions.h"
103
 
#include "drizzled/internal/m_string.h"
104
 
#include "drizzled/charset_info.h"
105
 
#include "drizzled/decimal.h"
 
102
#include "m_string.h"
 
103
#include "m_ctype.h"
 
104
#include "decimal.h"
106
105
 
107
106
#include <plugin/myisam/myisampack.h>
108
107
#include <drizzled/util/test.h>
109
108
 
110
 
#ifdef HAVE_ALLOCA_H
111
109
#include <alloca.h>
112
 
#endif
113
 
 
114
 
#include <algorithm>
115
 
#include <time.h>
116
 
#include "drizzled/current_session.h"
117
 
#include "drizzled/error.h"
118
 
#include "drizzled/field.h"
119
 
#include "drizzled/internal/my_sys.h"
120
 
 
121
 
using namespace std;
122
 
 
123
 
namespace drizzled
124
 
{
125
 
/**
126
 
  report result of decimal operation.
127
 
 
128
 
  @param result  decimal library return code (E_DEC_* see include/decimal.h)
129
 
 
130
 
  @todo
131
 
    Fix error messages
132
 
 
133
 
  @return
134
 
    result
135
 
*/
136
 
 
137
 
int decimal_operation_results(int result)
138
 
{
139
 
  switch (result) {
140
 
  case E_DEC_OK:
141
 
    break;
142
 
  case E_DEC_TRUNCATED:
143
 
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
144
 
                        ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED),
145
 
                        "", (long)-1);
146
 
    break;
147
 
  case E_DEC_OVERFLOW:
148
 
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
149
 
                        ER_TRUNCATED_WRONG_VALUE,
150
 
                        ER(ER_TRUNCATED_WRONG_VALUE),
151
 
                        "DECIMAL", "");
152
 
    break;
153
 
  case E_DEC_DIV_ZERO:
154
 
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
155
 
                        ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO));
156
 
    break;
157
 
  case E_DEC_BAD_NUM:
158
 
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
159
 
                        ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
160
 
                        ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
161
 
                        "decimal", "", "", (long)-1);
162
 
    break;
163
 
  case E_DEC_OOM:
164
 
    my_error(ER_OUT_OF_RESOURCES, MYF(0));
165
 
    break;
166
 
  default:
167
 
    assert(0);
168
 
  }
169
 
  return result;
170
 
}
171
 
 
172
 
 
173
 
/**
174
 
  @brief Converting decimal to string
175
 
 
176
 
  @details Convert given my_decimal to String; allocate buffer as needed.
177
 
 
178
 
  @param[in]   mask        what problems to warn on (mask of E_DEC_* values)
179
 
  @param[in]   d           the decimal to print
180
 
  @param[in]   fixed_prec  overall number of digits if ZEROFILL, 0 otherwise
181
 
  @param[in]   fixed_dec   number of decimal places (if fixed_prec != 0)
182
 
  @param[in]   filler      what char to pad with (ZEROFILL et al.)
183
 
  @param[out]  *str        where to store the resulting string
184
 
 
185
 
  @return error coce
186
 
    @retval E_DEC_OK
187
 
    @retval E_DEC_TRUNCATED
188
 
    @retval E_DEC_OVERFLOW
189
 
    @retval E_DEC_OOM
190
 
*/
191
 
 
192
 
int my_decimal2string(uint32_t mask, const my_decimal *d,
193
 
                      uint32_t fixed_prec, uint32_t fixed_dec,
194
 
                      char filler, String *str)
195
 
{
196
 
  /*
197
 
    Calculate the size of the string: For DECIMAL(a,b), fixed_prec==a
198
 
    holds true iff the type is also ZEROFILL, which in turn implies
199
 
    UNSIGNED. Hence the buffer for a ZEROFILLed value is the length
200
 
    the user requested, plus one for a possible decimal point, plus
201
 
    one if the user only wanted decimal places, but we force a leading
202
 
    zero on them. Because the type is implicitly UNSIGNED, we do not
203
 
    need to reserve a character for the sign. For all other cases,
204
 
    fixed_prec will be 0, and my_decimal_string_length() will be called
205
 
    instead to calculate the required size of the buffer.
206
 
  */
207
 
  int length= (fixed_prec
208
 
               ? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1)
209
 
               : my_decimal_string_length(d));
210
 
  int result;
211
 
  if (str->alloc(length))
212
 
    return check_result(mask, E_DEC_OOM);
213
 
  result= decimal2string((decimal_t*) d, (char*) str->ptr(),
214
 
                         &length, (int)fixed_prec, fixed_dec,
215
 
                         filler);
216
 
  str->length(length);
217
 
  return check_result(mask, result);
218
 
}
219
 
 
220
 
 
221
 
/*
222
 
  Convert from decimal to binary representation
223
 
 
224
 
  SYNOPSIS
225
 
    my_decimal2binary()
226
 
    mask        error processing mask
227
 
    d           number for conversion
228
 
    bin         pointer to buffer where to write result
229
 
    prec        overall number of decimal digits
230
 
    scale       number of decimal digits after decimal point
231
 
 
232
 
  NOTE
233
 
    Before conversion we round number if it need but produce truncation
234
 
    error in this case
235
 
 
236
 
  RETURN
237
 
    E_DEC_OK
238
 
    E_DEC_TRUNCATED
239
 
    E_DEC_OVERFLOW
240
 
*/
241
 
 
242
 
int my_decimal2binary(uint32_t mask, const my_decimal *d, unsigned char *bin, int prec,
243
 
                      int scale)
244
 
{
245
 
  int err1= E_DEC_OK, err2;
246
 
  my_decimal rounded;
247
 
  my_decimal2decimal(d, &rounded);
248
 
  rounded.frac= decimal_actual_fraction(&rounded);
249
 
  if (scale < rounded.frac)
250
 
  {
251
 
    err1= E_DEC_TRUNCATED;
252
 
    /* decimal_round can return only E_DEC_TRUNCATED */
253
 
    decimal_round(&rounded, &rounded, scale, HALF_UP);
254
 
  }
255
 
  err2= decimal2bin(&rounded, bin, prec, scale);
256
 
  if (!err2)
257
 
    err2= err1;
258
 
  return check_result(mask, err2);
259
 
}
260
 
 
261
 
 
262
 
/*
263
 
  Convert string for decimal when string can be in some multibyte charset
264
 
 
265
 
  SYNOPSIS
266
 
    str2my_decimal()
267
 
    mask            error processing mask
268
 
    from            string to process
269
 
    length          length of given string
270
 
    charset         charset of given string
271
 
    decimal_value   buffer for result storing
272
 
 
273
 
  RESULT
274
 
    E_DEC_OK
275
 
    E_DEC_TRUNCATED
276
 
    E_DEC_OVERFLOW
277
 
    E_DEC_BAD_NUM
278
 
    E_DEC_OOM
279
 
*/
280
 
 
281
 
int str2my_decimal(uint32_t mask, const char *from, uint32_t length,
282
 
                   const CHARSET_INFO * charset, my_decimal *decimal_value)
283
 
{
284
 
  char *end, *from_end;
285
 
  int err;
286
 
  char buff[STRING_BUFFER_USUAL_SIZE];
287
 
  String tmp(buff, sizeof(buff), &my_charset_bin);
288
 
  if (charset->mbminlen > 1)
289
 
  {
290
 
    uint32_t dummy_errors;
291
 
    tmp.copy(from, length, charset, &my_charset_utf8_general_ci, &dummy_errors);
292
 
    from= tmp.ptr();
293
 
    length=  tmp.length();
294
 
    charset= &my_charset_bin;
295
 
  }
296
 
  from_end= end= (char*) from+length;
297
 
  err= string2decimal((char *)from, (decimal_t*) decimal_value, &end);
298
 
  if (end != from_end && !err)
299
 
  {
300
 
    /* Give warning if there is something other than end space */
301
 
    for ( ; end < from_end; end++)
302
 
    {
303
 
      if (!my_isspace(&my_charset_utf8_general_ci, *end))
304
 
      {
305
 
        err= E_DEC_TRUNCATED;
306
 
        break;
307
 
      }
308
 
    }
309
 
  }
310
 
  check_result_and_overflow(mask, err, decimal_value);
311
 
  return err;
312
 
}
313
 
 
314
 
 
315
 
my_decimal *date2my_decimal(DRIZZLE_TIME *ltime, my_decimal *dec)
316
 
{
317
 
  int64_t date;
318
 
  date = (ltime->year*100L + ltime->month)*100L + ltime->day;
319
 
  if (ltime->time_type > DRIZZLE_TIMESTAMP_DATE)
320
 
    date= ((date*100L + ltime->hour)*100L+ ltime->minute)*100L + ltime->second;
321
 
  if (int2my_decimal(E_DEC_FATAL_ERROR, date, false, dec))
322
 
    return dec;
323
 
  if (ltime->second_part)
324
 
  {
325
 
    dec->buf[(dec->intg-1) / 9 + 1]= ltime->second_part * 1000;
326
 
    dec->frac= 6;
327
 
  }
328
 
  return dec;
329
 
}
330
 
 
331
 
 
332
 
void my_decimal_trim(uint32_t *precision, uint32_t *scale)
333
 
{
334
 
  if (!(*precision) && !(*scale))
335
 
  {
336
 
    *precision= 10;
337
 
    *scale= 0;
338
 
    return;
339
 
  }
340
 
}
341
 
 
342
 
 
343
110
/*
344
111
  Internally decimal numbers are stored base 10^9 (see DIG_BASE below)
345
112
  So one variable of type decimal_digit_t is limited:
458
225
  } while (0)
459
226
 
460
227
 
461
 
 
462
228
/*
463
229
  Get maximum value for given precision and scale
464
230
 
496
262
}
497
263
 
498
264
 
499
 
static dec1 *remove_leading_zeroes(const decimal_t *from, int *intg_result)
 
265
static dec1 *remove_leading_zeroes(decimal_t *from, int *intg_result)
500
266
{
501
267
  int intg= from->intg, i;
502
268
  dec1 *buf0= from->buf;
572
338
    E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
573
339
*/
574
340
 
575
 
int decimal2string(const decimal_t *from, char *to, int *to_len,
 
341
int decimal2string(decimal_t *from, char *to, int *to_len,
576
342
                   int fixed_precision, int fixed_decimals,
577
343
                   char filler)
578
344
{
641
407
    for (; frac>0; frac-=DIG_PER_DEC1)
642
408
    {
643
409
      dec1 x=*buf++;
644
 
      for (i=min(frac, DIG_PER_DEC1); i; i--)
 
410
      for (i=cmin(frac, DIG_PER_DEC1); i; i--)
645
411
      {
646
412
        dec1 y=x/DIG_MASK;
647
413
        *s1++='0'+(unsigned char)y;
664
430
    for (buf=buf0+ROUND_UP(intg); intg>0; intg-=DIG_PER_DEC1)
665
431
    {
666
432
      dec1 x=*--buf;
667
 
      for (i=min(intg, DIG_PER_DEC1); i; i--)
 
433
      for (i=cmin(intg, DIG_PER_DEC1); i; i--)
668
434
      {
669
435
        dec1 y=x/10;
670
436
        *--s='0'+(unsigned char)(x-y*10);
1145
911
  if (endp+1 < end_of_string && (*endp == 'e' || *endp == 'E'))
1146
912
  {
1147
913
    int str_error;
1148
 
    const int64_t exponent= internal::my_strtoll10(endp+1, (char**) &end_of_string,
1149
 
                                                   &str_error);
 
914
    const int64_t exponent= my_strtoll10(endp+1, (char**) &end_of_string,
 
915
                                    &str_error);
1150
916
 
1151
917
    if (end_of_string != endp +1)               /* If at least one digit */
1152
918
    {
1190
956
    E_DEC_OK/E_DEC_OVERFLOW/E_DEC_TRUNCATED
1191
957
*/
1192
958
 
1193
 
int decimal2double(const decimal_t *from, double *to)
 
959
int decimal2double(decimal_t *from, double *to)
1194
960
{
1195
961
  char strbuf[FLOATING_POINT_BUFFER], *end;
1196
962
  int len= sizeof(strbuf);
1199
965
  rc = decimal2string(from, strbuf, &len, 0, 0, 0);
1200
966
  end= strbuf + len;
1201
967
 
1202
 
  *to= internal::my_strtod(strbuf, &end, &error);
 
968
  *to= my_strtod(strbuf, &end, &error);
1203
969
 
1204
970
  return (rc != E_DEC_OK) ? rc : (error ? E_DEC_OVERFLOW : E_DEC_OK);
1205
971
}
1216
982
    E_DEC_OK/E_DEC_OVERFLOW/E_DEC_TRUNCATED
1217
983
*/
1218
984
 
1219
 
int double2decimal(const double from, decimal_t *to)
 
985
int double2decimal(double from, decimal_t *to)
1220
986
{
1221
987
  char buff[FLOATING_POINT_BUFFER], *end;
1222
988
  int res;
1223
 
  end= buff + internal::my_gcvt(from,
1224
 
                                internal::MY_GCVT_ARG_DOUBLE,
1225
 
                                sizeof(buff) - 1, buff, NULL);
 
989
  end= buff + my_gcvt(from, MY_GCVT_ARG_DOUBLE, sizeof(buff) - 1, buff, NULL);
1226
990
  res= string2decimal(buff, to, &end);
1227
991
  return(res);
1228
992
}
1254
1018
  return error;
1255
1019
}
1256
1020
 
1257
 
int uint64_t2decimal(const uint64_t from, decimal_t *to)
 
1021
int uint64_t2decimal(uint64_t from, decimal_t *to)
1258
1022
{
1259
1023
  to->sign=0;
1260
1024
  return ull2dec(from, to);
1261
1025
}
1262
1026
 
1263
 
int int64_t2decimal(const int64_t from, decimal_t *to)
 
1027
int int64_t2decimal(int64_t from, decimal_t *to)
1264
1028
{
1265
1029
  if ((to->sign= from < 0))
1266
1030
    return ull2dec(-from, to);
1267
1031
  return ull2dec(from, to);
1268
1032
}
1269
1033
 
1270
 
int decimal2uint64_t(const decimal_t *from, uint64_t *to)
 
1034
int decimal2uint64_t(decimal_t *from, uint64_t *to)
1271
1035
{
1272
1036
  dec1 *buf=from->buf;
1273
1037
  uint64_t x=0;
1296
1060
  return E_DEC_OK;
1297
1061
}
1298
1062
 
1299
 
int decimal2int64_t(const decimal_t *from, int64_t *to)
 
1063
int decimal2int64_t(decimal_t *from, int64_t *to)
1300
1064
{
1301
1065
  dec1 *buf=from->buf;
1302
1066
  int64_t x=0;
1415
1179
 
1416
1180
                7E F2 04 37 2D FB 2D
1417
1181
*/
1418
 
int decimal2bin(const decimal_t *from, unsigned char *to, int precision, int frac)
 
1182
int decimal2bin(decimal_t *from, unsigned char *to, int precision, int frac)
1419
1183
{
1420
1184
  dec1 mask=from->sign ? -1 : 0, *buf1=from->buf, *stop1;
1421
1185
  int error=E_DEC_OK, intg=precision-frac,
1653
1417
}
1654
1418
 
1655
1419
/*
 
1420
  Returns the size of array to hold a decimal with given precision and scale
 
1421
 
 
1422
  RETURN VALUE
 
1423
    size in dec1
 
1424
    (multiply by sizeof(dec1) to get the size if bytes)
 
1425
*/
 
1426
 
 
1427
int decimal_size(int precision, int scale)
 
1428
{
 
1429
  assert(scale >= 0 && precision > 0 && scale <= precision);
 
1430
  return ROUND_UP(precision-scale)+ROUND_UP(scale);
 
1431
}
 
1432
 
 
1433
/*
1656
1434
  Returns the size of array to hold a binary representation of a decimal
1657
1435
 
1658
1436
  RETURN VALUE
1689
1467
*/
1690
1468
 
1691
1469
int
1692
 
decimal_round(const decimal_t *from, decimal_t *to, int scale,
 
1470
decimal_round(decimal_t *from, decimal_t *to, int scale,
1693
1471
              decimal_round_mode mode)
1694
1472
{
1695
1473
  int frac0=scale>0 ? ROUND_UP(scale) : scale/DIG_PER_DEC1,
1726
1504
 
1727
1505
  if (to != from || intg1>intg0)
1728
1506
  {
1729
 
    dec1 *p0= buf0+intg0+max(frac1, frac0);
1730
 
    dec1 *p1= buf1+intg1+max(frac1, frac0);
 
1507
    dec1 *p0= buf0+intg0+cmax(frac1, frac0);
 
1508
    dec1 *p1= buf1+intg1+cmax(frac1, frac0);
1731
1509
 
1732
1510
    while (buf0 < p0)
1733
1511
      *(--p1) = *(--p0);
1738
1516
    buf0=to->buf;
1739
1517
    buf1=to->buf;
1740
1518
    to->sign=from->sign;
1741
 
    to->intg=min(intg0, len)*DIG_PER_DEC1;
 
1519
    to->intg=cmin(intg0, len)*DIG_PER_DEC1;
1742
1520
  }
1743
1521
 
1744
1522
  if (frac0 > frac1)
1840
1618
        scale=frac0*DIG_PER_DEC1;
1841
1619
        error=E_DEC_TRUNCATED; /* XXX */
1842
1620
      }
1843
 
      for (buf1=to->buf+intg0+max(frac0,0); buf1 > to->buf; buf1--)
 
1621
      for (buf1=to->buf+intg0+cmax(frac0,0); buf1 > to->buf; buf1--)
1844
1622
      {
1845
1623
        buf1[0]=buf1[-1];
1846
1624
      }
1859
1637
        /* making 'zero' with the proper scale */
1860
1638
        dec1 *p0= to->buf + frac0 + 1;
1861
1639
        to->intg=1;
1862
 
        to->frac= max(scale, 0);
 
1640
        to->frac= cmax(scale, 0);
1863
1641
        to->sign= 0;
1864
1642
        for (buf1= to->buf; buf1<p0; buf1++)
1865
1643
          *buf1= 0;
1881
1659
  return error;
1882
1660
}
1883
1661
 
1884
 
static int do_add(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
 
1662
/*
 
1663
  Returns the size of the result of the operation
 
1664
 
 
1665
  SYNOPSIS
 
1666
    decimal_result_size()
 
1667
      from1   - operand of the unary operation or first operand of the
 
1668
                binary operation
 
1669
      from2   - second operand of the binary operation
 
1670
      op      - operation. one char '+', '-', '*', '/' are allowed
 
1671
                others may be added later
 
1672
      param   - extra param to the operation. unused for '+', '-', '*'
 
1673
                scale increment for '/'
 
1674
 
 
1675
  NOTE
 
1676
    returned valued may be larger than the actual buffer requred
 
1677
    in the operation, as decimal_result_size, by design, operates on
 
1678
    precision/scale values only and not on the actual decimal number
 
1679
 
 
1680
  RETURN VALUE
 
1681
    size of to->buf array in dec1 elements. to get size in bytes
 
1682
    multiply by sizeof(dec1)
 
1683
*/
 
1684
 
 
1685
int decimal_result_size(decimal_t *from1, decimal_t *from2, char op, int param)
 
1686
{
 
1687
  switch (op) {
 
1688
  case '-':
 
1689
    return ROUND_UP(cmax(from1->intg, from2->intg)) +
 
1690
           ROUND_UP(cmax(from1->frac, from2->frac));
 
1691
  case '+':
 
1692
    return ROUND_UP(cmax(from1->intg, from2->intg)+1) +
 
1693
           ROUND_UP(cmax(from1->frac, from2->frac));
 
1694
  case '*':
 
1695
    return ROUND_UP(from1->intg+from2->intg)+
 
1696
           ROUND_UP(from1->frac)+ROUND_UP(from2->frac);
 
1697
  case '/':
 
1698
    return ROUND_UP(from1->intg+from2->intg+1+from1->frac+from2->frac+param);
 
1699
  default: assert(0);
 
1700
  }
 
1701
  return -1; /* shut up the warning */
 
1702
}
 
1703
 
 
1704
static int do_add(decimal_t *from1, decimal_t *from2, decimal_t *to)
1885
1705
{
1886
1706
  int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg),
1887
1707
      frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac),
1888
 
      frac0=max(frac1, frac2), intg0=max(intg1, intg2), error;
 
1708
      frac0=cmax(frac1, frac2), intg0=cmax(intg1, intg2), error;
1889
1709
  dec1 *buf1, *buf2, *buf0, *stop, *stop2, x, carry;
1890
1710
 
1891
1711
  sanity(to);
1910
1730
  buf0=to->buf+intg0+frac0;
1911
1731
 
1912
1732
  to->sign=from1->sign;
1913
 
  to->frac=max(from1->frac, from2->frac);
 
1733
  to->frac=cmax(from1->frac, from2->frac);
1914
1734
  to->intg=intg0*DIG_PER_DEC1;
1915
1735
  if (unlikely(error))
1916
1736
  {
1963
1783
 
1964
1784
/* to=from1-from2.
1965
1785
   if to==0, return -1/0/+1 - the result of the comparison */
1966
 
static int do_sub(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
 
1786
static int do_sub(decimal_t *from1, decimal_t *from2, decimal_t *to)
1967
1787
{
1968
1788
  int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg),
1969
1789
      frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac);
1970
 
  int frac0=max(frac1, frac2), error;
 
1790
  int frac0=cmax(frac1, frac2), error;
1971
1791
  dec1 *buf1, *buf2, *buf0, *stop1, *stop2, *start1, *start2, carry=0;
1972
1792
 
1973
1793
  /* let carry:=1 if from2 > from1 */
2032
1852
  /* ensure that always from1 > from2 (and intg1 >= intg2) */
2033
1853
  if (carry)
2034
1854
  {
2035
 
    swap_variables(const decimal_t *,from1, from2);
 
1855
    swap_variables(decimal_t *,from1,from1);
2036
1856
    swap_variables(dec1 *,start1, start2);
2037
1857
    swap_variables(int,intg1,intg2);
2038
1858
    swap_variables(int,frac1,frac2);
2042
1862
  FIX_INTG_FRAC_ERROR(to->len, intg1, frac0, error);
2043
1863
  buf0=to->buf+intg1+frac0;
2044
1864
 
2045
 
  to->frac=max(from1->frac, from2->frac);
 
1865
  to->frac=cmax(from1->frac, from2->frac);
2046
1866
  to->intg=intg1*DIG_PER_DEC1;
2047
1867
  if (unlikely(error))
2048
1868
  {
2098
1918
  return error;
2099
1919
}
2100
1920
 
2101
 
int decimal_intg(const decimal_t *from)
 
1921
int decimal_intg(decimal_t *from)
2102
1922
{
2103
1923
  int res;
2104
1924
  dec1 *tmp_res;
2106
1926
  return res;
2107
1927
}
2108
1928
 
2109
 
int decimal_add(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
 
1929
int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to)
2110
1930
{
2111
1931
  if (likely(from1->sign == from2->sign))
2112
1932
    return do_add(from1, from2, to);
2113
1933
  return do_sub(from1, from2, to);
2114
1934
}
2115
1935
 
2116
 
int decimal_sub(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
 
1936
int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to)
2117
1937
{
2118
1938
  if (likely(from1->sign == from2->sign))
2119
1939
    return do_sub(from1, from2, to);
2120
1940
  return do_add(from1, from2, to);
2121
1941
}
2122
1942
 
2123
 
int decimal_cmp(const decimal_t *from1, const decimal_t *from2)
 
1943
int decimal_cmp(decimal_t *from1, decimal_t *from2)
2124
1944
{
2125
1945
  if (likely(from1->sign == from2->sign))
2126
1946
    return do_sub(from1, from2, 0);
2127
1947
  return from1->sign > from2->sign ? -1 : 1;
2128
1948
}
2129
1949
 
2130
 
int decimal_is_zero(const decimal_t *from)
 
1950
int decimal_is_zero(decimal_t *from)
2131
1951
{
2132
1952
  dec1 *buf1=from->buf,
2133
1953
       *end=buf1+ROUND_UP(from->intg)+ROUND_UP(from->frac);
2158
1978
    XXX if this library is to be used with huge numbers of thousands of
2159
1979
    digits, fast multiplication must be implemented.
2160
1980
*/
2161
 
int decimal_mul(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
 
1981
int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to)
2162
1982
{
2163
1983
  int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg),
2164
1984
      frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac),
2274
2094
  changed to malloc (or at least fallback to malloc if alloca() fails)
2275
2095
  but then, decimal_mul() should be rewritten too :(
2276
2096
*/
2277
 
static int do_div_mod(const decimal_t *from1, const decimal_t *from2,
 
2097
static int do_div_mod(decimal_t *from1, decimal_t *from2,
2278
2098
                       decimal_t *to, decimal_t *mod, int scale_incr)
2279
2099
{
2280
2100
  int frac1=ROUND_UP(from1->frac)*DIG_PER_DEC1, prec1=from1->intg+frac1,
2337
2157
         intg=intg2
2338
2158
    */
2339
2159
    to->sign=from1->sign;
2340
 
    to->frac=max(from1->frac, from2->frac);
 
2160
    to->frac=cmax(from1->frac, from2->frac);
2341
2161
    frac0=0;
2342
2162
  }
2343
2163
  else
2499
2319
      }
2500
2320
      assert(intg0 <= ROUND_UP(from2->intg));
2501
2321
      stop1=start1+frac0+intg0;
2502
 
      to->intg=min(intg0*DIG_PER_DEC1, from2->intg);
 
2322
      to->intg=cmin(intg0*DIG_PER_DEC1, from2->intg);
2503
2323
    }
2504
2324
    if (unlikely(intg0+frac0 > to->len))
2505
2325
    {
2533
2353
*/
2534
2354
 
2535
2355
int
2536
 
decimal_div(const decimal_t *from1, const decimal_t *from2, decimal_t *to, int scale_incr)
 
2356
decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to, int scale_incr)
2537
2357
{
2538
2358
  return do_div_mod(from1, from2, to, 0, scale_incr);
2539
2359
}
2565
2385
   thus, there's no requirement for M or N to be integers
2566
2386
*/
2567
2387
 
2568
 
int decimal_mod(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
 
2388
int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to)
2569
2389
{
2570
2390
  return do_div_mod(from1, from2, 0, to, 0);
2571
2391
}
2572
2392
 
2573
 
} /* namespace drizzled */
2574
 
 
2575
2393
#ifdef MAIN
2576
2394
 
2577
2395
int full= 0;
2654
2472
{
2655
2473
  char s1[100], *end;
2656
2474
  int res;
2657
 
  snprintf(s1, sizeof(s1), "'%s'", s);
 
2475
  sprintf(s1, "'%s'", s);
2658
2476
  end= strend(s);
2659
2477
  printf("len=%2d %-30s => res=%d    ", a.len, s1,
2660
2478
         (res= string2decimal(s, &a, &end)));
2668
2486
  double x;
2669
2487
  int res;
2670
2488
 
2671
 
  snprintf(s1, sizeof(s1), "'%s'", s);
 
2489
  sprintf(s1, "'%s'", s);
2672
2490
  end= strend(s);
2673
2491
  string2decimal(s, &a, &end);
2674
2492
  res=decimal2double(&a, &x);
2682
2500
  char s1[100], buf[100], *end;
2683
2501
  int res, i, size=decimal_bin_size(p, s);
2684
2502
 
2685
 
  snprintf(s1, sizeof(s1), "'%s'", str);
 
2503
  sprintf(s1, "'%s'", str);
2686
2504
  end= strend(str);
2687
2505
  string2decimal(str, &a, &end);
2688
2506
  res=decimal2bin(&a, buf, p, s);
2715
2533
  int res;
2716
2534
 
2717
2535
  res=uint64_t2decimal(from, &a);
2718
 
  internal::int64_t10_to_str(from,s,10);
 
2536
  int64_t10_to_str(from,s,10);
2719
2537
  printf("%-40s => res=%d    ", s, res);
2720
2538
  print_decimal(&a, orig, res, ex);
2721
2539
  printf("\n");
2727
2545
  int res;
2728
2546
 
2729
2547
  res=int64_t2decimal(from, &a);
2730
 
  internal::int64_t10_to_str(from,s,-10);
 
2548
  int64_t10_to_str(from,s,-10);
2731
2549
  printf("%-40s => res=%d    ", s, res);
2732
2550
  print_decimal(&a, orig, res, ex);
2733
2551
  printf("\n");
2743
2561
  string2decimal(s, &a, &end);
2744
2562
  res=decimal2uint64_t(&a, &x);
2745
2563
  if (full) dump_decimal(&a);
2746
 
  internal::int64_t10_to_str(x,s1,10);
 
2564
  int64_t10_to_str(x,s1,10);
2747
2565
  printf("%-40s => res=%d    %s\n", s, res, s1);
2748
2566
  check_result_code(res, ex);
2749
2567
  if (orig && strcmp(orig, s1))
2763
2581
  string2decimal(s, &a, &end);
2764
2582
  res=decimal2int64_t(&a, &x);
2765
2583
  if (full) dump_decimal(&a);
2766
 
  internal::int64_t10_to_str(x,s1,-10);
 
2584
  int64_t10_to_str(x,s1,-10);
2767
2585
  printf("%-40s => res=%d    %s\n", s, res, s1);
2768
2586
  check_result_code(res, ex);
2769
2587
  if (orig && strcmp(orig, s1))
2777
2595
{
2778
2596
  char s[100], *end;
2779
2597
  int res;
2780
 
  snprintf(s, sizeof(s), "'%s' + '%s'", s1, s2);
 
2598
  sprintf(s, "'%s' + '%s'", s1, s2);
2781
2599
  end= strend(s1);
2782
2600
  string2decimal(s1, &a, &end);
2783
2601
  end= strend(s2);
2792
2610
{
2793
2611
  char s[100], *end;
2794
2612
  int res;
2795
 
  snprintf(s, sizeof(s), "'%s' - '%s'", s1, s2);
 
2613
  sprintf(s, "'%s' - '%s'", s1, s2);
2796
2614
  end= strend(s1);
2797
2615
  string2decimal(s1, &a, &end);
2798
2616
  end= strend(s2);
2807
2625
{
2808
2626
  char s[100], *end;
2809
2627
  int res;
2810
 
  snprintf(s, sizeof(s), "'%s' <=> '%s'", s1, s2);
 
2628
  sprintf(s, "'%s' <=> '%s'", s1, s2);
2811
2629
  end= strend(s1);
2812
2630
  string2decimal(s1, &a, &end);
2813
2631
  end= strend(s2);
2825
2643
{
2826
2644
  char s[100], *end;
2827
2645
  int res;
2828
 
  snprintf(s, sizeof(s), "'%s' * '%s'", s1, s2);
 
2646
  sprintf(s, "'%s' * '%s'", s1, s2);
2829
2647
  end= strend(s1);
2830
2648
  string2decimal(s1, &a, &end);
2831
2649
  end= strend(s2);
2840
2658
{
2841
2659
  char s[100], *end;
2842
2660
  int res;
2843
 
  snprintf(s, sizeof(s), "'%s' / '%s'", s1, s2);
 
2661
  sprintf(s, "'%s' / '%s'", s1, s2);
2844
2662
  end= strend(s1);
2845
2663
  string2decimal(s1, &a, &end);
2846
2664
  end= strend(s2);
2859
2677
{
2860
2678
  char s[100], *end;
2861
2679
  int res;
2862
 
  snprintf(s, sizeof(s), "'%s' %% '%s'", s1, s2);
 
2680
  sprintf(s, "'%s' %% '%s'", s1, s2);
2863
2681
  end= strend(s1);
2864
2682
  string2decimal(s1, &a, &end);
2865
2683
  end= strend(s2);
2882
2700
{
2883
2701
  char s[100], *end;
2884
2702
  int res;
2885
 
  snprintf(s, sizeof(s), "'%s', %d, %s", s1, n, round_mode[mode]);
 
2703
  sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]);
2886
2704
  end= strend(s1);
2887
2705
  string2decimal(s1, &a, &end);
2888
2706
  res=decimal_round(&a, &b, n, mode);
2895
2713
void test_mx(int precision, int frac, const char *orig)
2896
2714
{
2897
2715
  char s[100];
2898
 
  snprintf(s, sizeof(s), "%d, %d", precision, frac);
 
2716
  sprintf(s, "%d, %d", precision, frac);
2899
2717
  max_decimal(precision, frac, &a);
2900
2718
  printf("%-40s =>          ", s);
2901
2719
  print_decimal(&a, orig, 0, 0);
2911
2729
  int slen= sizeof(s2);
2912
2730
  int res;
2913
2731
 
2914
 
  snprintf(s, sizeof(s), filler ? "'%s', %d, %d, '%c'" : "'%s', %d, %d, '\\0'",
 
2732
  sprintf(s, filler ? "'%s', %d, %d, '%c'" : "'%s', %d, %d, '\\0'",
2915
2733
          s1, prec, dec, filler);
2916
2734
  end= strend(s1);
2917
2735
  string2decimal(s1, &a, &end);
2931
2749
{
2932
2750
  char s[100], *end;
2933
2751
  int res;
2934
 
  snprintf(s, sizeof(s), "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift));
 
2752
  sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift));
2935
2753
  end= strend(s1);
2936
2754
  string2decimal(s1, &a, &end);
2937
2755
  res= decimal_shift(&a, shift);
2944
2762
void test_fr(const char *s1, const char *orig)
2945
2763
{
2946
2764
  char s[100], *end;
2947
 
  snprintf(s, sizeof(s), "'%s'", s1);
 
2765
  sprintf(s, "'%s'", s1);
2948
2766
  printf("%-40s =>          ", s);
2949
2767
  end= strend(s1);
2950
2768
  string2decimal(s1, &a, &end);