~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/decimal.cc

  • Committer: pawel
  • Date: 2010-03-29 20:16:08 UTC
  • mto: This revision was merged to the branch mainline in revision 1428.
  • Revision ID: pawel@paw-20100329201608-ndqnc736k47uvy3s
changed function-like defines into functions in some files

Show diffs side-by-side

added added

removed removed

Lines of Context:
112
112
#endif
113
113
 
114
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
115
 
121
116
using namespace std;
122
117
 
123
118
namespace drizzled
124
119
{
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
120
 
343
121
/*
344
122
  Internally decimal numbers are stored base 10^9 (see DIG_BASE below)
458
236
  } while (0)
459
237
 
460
238
 
461
 
 
462
239
/*
463
240
  Get maximum value for given precision and scale
464
241
 
2654
2431
{
2655
2432
  char s1[100], *end;
2656
2433
  int res;
2657
 
  snprintf(s1, sizeof(s1), "'%s'", s);
 
2434
  sprintf(s1, "'%s'", s);
2658
2435
  end= strend(s);
2659
2436
  printf("len=%2d %-30s => res=%d    ", a.len, s1,
2660
2437
         (res= string2decimal(s, &a, &end)));
2668
2445
  double x;
2669
2446
  int res;
2670
2447
 
2671
 
  snprintf(s1, sizeof(s1), "'%s'", s);
 
2448
  sprintf(s1, "'%s'", s);
2672
2449
  end= strend(s);
2673
2450
  string2decimal(s, &a, &end);
2674
2451
  res=decimal2double(&a, &x);
2682
2459
  char s1[100], buf[100], *end;
2683
2460
  int res, i, size=decimal_bin_size(p, s);
2684
2461
 
2685
 
  snprintf(s1, sizeof(s1), "'%s'", str);
 
2462
  sprintf(s1, "'%s'", str);
2686
2463
  end= strend(str);
2687
2464
  string2decimal(str, &a, &end);
2688
2465
  res=decimal2bin(&a, buf, p, s);
2777
2554
{
2778
2555
  char s[100], *end;
2779
2556
  int res;
2780
 
  snprintf(s, sizeof(s), "'%s' + '%s'", s1, s2);
 
2557
  sprintf(s, "'%s' + '%s'", s1, s2);
2781
2558
  end= strend(s1);
2782
2559
  string2decimal(s1, &a, &end);
2783
2560
  end= strend(s2);
2792
2569
{
2793
2570
  char s[100], *end;
2794
2571
  int res;
2795
 
  snprintf(s, sizeof(s), "'%s' - '%s'", s1, s2);
 
2572
  sprintf(s, "'%s' - '%s'", s1, s2);
2796
2573
  end= strend(s1);
2797
2574
  string2decimal(s1, &a, &end);
2798
2575
  end= strend(s2);
2807
2584
{
2808
2585
  char s[100], *end;
2809
2586
  int res;
2810
 
  snprintf(s, sizeof(s), "'%s' <=> '%s'", s1, s2);
 
2587
  sprintf(s, "'%s' <=> '%s'", s1, s2);
2811
2588
  end= strend(s1);
2812
2589
  string2decimal(s1, &a, &end);
2813
2590
  end= strend(s2);
2825
2602
{
2826
2603
  char s[100], *end;
2827
2604
  int res;
2828
 
  snprintf(s, sizeof(s), "'%s' * '%s'", s1, s2);
 
2605
  sprintf(s, "'%s' * '%s'", s1, s2);
2829
2606
  end= strend(s1);
2830
2607
  string2decimal(s1, &a, &end);
2831
2608
  end= strend(s2);
2840
2617
{
2841
2618
  char s[100], *end;
2842
2619
  int res;
2843
 
  snprintf(s, sizeof(s), "'%s' / '%s'", s1, s2);
 
2620
  sprintf(s, "'%s' / '%s'", s1, s2);
2844
2621
  end= strend(s1);
2845
2622
  string2decimal(s1, &a, &end);
2846
2623
  end= strend(s2);
2859
2636
{
2860
2637
  char s[100], *end;
2861
2638
  int res;
2862
 
  snprintf(s, sizeof(s), "'%s' %% '%s'", s1, s2);
 
2639
  sprintf(s, "'%s' %% '%s'", s1, s2);
2863
2640
  end= strend(s1);
2864
2641
  string2decimal(s1, &a, &end);
2865
2642
  end= strend(s2);
2882
2659
{
2883
2660
  char s[100], *end;
2884
2661
  int res;
2885
 
  snprintf(s, sizeof(s), "'%s', %d, %s", s1, n, round_mode[mode]);
 
2662
  sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]);
2886
2663
  end= strend(s1);
2887
2664
  string2decimal(s1, &a, &end);
2888
2665
  res=decimal_round(&a, &b, n, mode);
2895
2672
void test_mx(int precision, int frac, const char *orig)
2896
2673
{
2897
2674
  char s[100];
2898
 
  snprintf(s, sizeof(s), "%d, %d", precision, frac);
 
2675
  sprintf(s, "%d, %d", precision, frac);
2899
2676
  max_decimal(precision, frac, &a);
2900
2677
  printf("%-40s =>          ", s);
2901
2678
  print_decimal(&a, orig, 0, 0);
2911
2688
  int slen= sizeof(s2);
2912
2689
  int res;
2913
2690
 
2914
 
  snprintf(s, sizeof(s), filler ? "'%s', %d, %d, '%c'" : "'%s', %d, %d, '\\0'",
 
2691
  sprintf(s, filler ? "'%s', %d, %d, '%c'" : "'%s', %d, %d, '\\0'",
2915
2692
          s1, prec, dec, filler);
2916
2693
  end= strend(s1);
2917
2694
  string2decimal(s1, &a, &end);
2931
2708
{
2932
2709
  char s[100], *end;
2933
2710
  int res;
2934
 
  snprintf(s, sizeof(s), "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift));
 
2711
  sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift));
2935
2712
  end= strend(s1);
2936
2713
  string2decimal(s1, &a, &end);
2937
2714
  res= decimal_shift(&a, shift);
2944
2721
void test_fr(const char *s1, const char *orig)
2945
2722
{
2946
2723
  char s[100], *end;
2947
 
  snprintf(s, sizeof(s), "'%s'", s1);
 
2724
  sprintf(s, "'%s'", s1);
2948
2725
  printf("%-40s =>          ", s);
2949
2726
  end= strend(s1);
2950
2727
  string2decimal(s1, &a, &end);