~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to drizzled/my_decimal.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2005-2006 MySQL AB
 
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 as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
#include "config.h"
 
17
#include <time.h>
 
18
#include "drizzled/current_session.h"
 
19
#include "drizzled/error.h"
 
20
#include "drizzled/field.h"
 
21
#include "drizzled/internal/my_sys.h"
 
22
 
 
23
namespace drizzled
 
24
{
 
25
 
 
26
/**
 
27
  report result of decimal operation.
 
28
 
 
29
  @param result  decimal library return code (E_DEC_* see include/decimal.h)
 
30
 
 
31
  @todo
 
32
    Fix error messages
 
33
 
 
34
  @return
 
35
    result
 
36
*/
 
37
 
 
38
int decimal_operation_results(int result)
 
39
{
 
40
  switch (result) {
 
41
  case E_DEC_OK:
 
42
    break;
 
43
  case E_DEC_TRUNCATED:
 
44
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
45
                        ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED),
 
46
                        "", (long)-1);
 
47
    break;
 
48
  case E_DEC_OVERFLOW:
 
49
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
50
                        ER_TRUNCATED_WRONG_VALUE,
 
51
                        ER(ER_TRUNCATED_WRONG_VALUE),
 
52
                        "DECIMAL", "");
 
53
    break;
 
54
  case E_DEC_DIV_ZERO:
 
55
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
56
                        ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO));
 
57
    break;
 
58
  case E_DEC_BAD_NUM:
 
59
    push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
60
                        ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
 
61
                        ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
 
62
                        "decimal", "", "", (long)-1);
 
63
    break;
 
64
  case E_DEC_OOM:
 
65
    my_error(ER_OUT_OF_RESOURCES, MYF(0));
 
66
    break;
 
67
  default:
 
68
    assert(0);
 
69
  }
 
70
  return result;
 
71
}
 
72
 
 
73
 
 
74
/**
 
75
  @brief Converting decimal to string
 
76
 
 
77
  @details Convert given my_decimal to String; allocate buffer as needed.
 
78
 
 
79
  @param[in]   mask        what problems to warn on (mask of E_DEC_* values)
 
80
  @param[in]   d           the decimal to print
 
81
  @param[in]   fixed_prec  overall number of digits if ZEROFILL, 0 otherwise
 
82
  @param[in]   fixed_dec   number of decimal places (if fixed_prec != 0)
 
83
  @param[in]   filler      what char to pad with (ZEROFILL et al.)
 
84
  @param[out]  *str        where to store the resulting string
 
85
 
 
86
  @return error coce
 
87
    @retval E_DEC_OK
 
88
    @retval E_DEC_TRUNCATED
 
89
    @retval E_DEC_OVERFLOW
 
90
    @retval E_DEC_OOM
 
91
*/
 
92
 
 
93
int my_decimal2string(uint32_t mask, const my_decimal *d,
 
94
                      uint32_t fixed_prec, uint32_t fixed_dec,
 
95
                      char filler, String *str)
 
96
{
 
97
  /*
 
98
    Calculate the size of the string: For DECIMAL(a,b), fixed_prec==a
 
99
    holds true iff the type is also ZEROFILL, which in turn implies
 
100
    UNSIGNED. Hence the buffer for a ZEROFILLed value is the length
 
101
    the user requested, plus one for a possible decimal point, plus
 
102
    one if the user only wanted decimal places, but we force a leading
 
103
    zero on them. Because the type is implicitly UNSIGNED, we do not
 
104
    need to reserve a character for the sign. For all other cases,
 
105
    fixed_prec will be 0, and my_decimal_string_length() will be called
 
106
    instead to calculate the required size of the buffer.
 
107
  */
 
108
  int length= (fixed_prec
 
109
               ? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1)
 
110
               : my_decimal_string_length(d));
 
111
  int result;
 
112
  if (str->alloc(length))
 
113
    return check_result(mask, E_DEC_OOM);
 
114
  result= decimal2string((decimal_t*) d, (char*) str->ptr(),
 
115
                         &length, (int)fixed_prec, fixed_dec,
 
116
                         filler);
 
117
  str->length(length);
 
118
  return check_result(mask, result);
 
119
}
 
120
 
 
121
 
 
122
/*
 
123
  Convert from decimal to binary representation
 
124
 
 
125
  SYNOPSIS
 
126
    my_decimal2binary()
 
127
    mask        error processing mask
 
128
    d           number for conversion
 
129
    bin         pointer to buffer where to write result
 
130
    prec        overall number of decimal digits
 
131
    scale       number of decimal digits after decimal point
 
132
 
 
133
  NOTE
 
134
    Before conversion we round number if it need but produce truncation
 
135
    error in this case
 
136
 
 
137
  RETURN
 
138
    E_DEC_OK
 
139
    E_DEC_TRUNCATED
 
140
    E_DEC_OVERFLOW
 
141
*/
 
142
 
 
143
int my_decimal2binary(uint32_t mask, const my_decimal *d, unsigned char *bin, int prec,
 
144
                      int scale)
 
145
{
 
146
  int err1= E_DEC_OK, err2;
 
147
  my_decimal rounded;
 
148
  my_decimal2decimal(d, &rounded);
 
149
  rounded.frac= decimal_actual_fraction(&rounded);
 
150
  if (scale < rounded.frac)
 
151
  {
 
152
    err1= E_DEC_TRUNCATED;
 
153
    /* decimal_round can return only E_DEC_TRUNCATED */
 
154
    decimal_round(&rounded, &rounded, scale, HALF_UP);
 
155
  }
 
156
  err2= decimal2bin(&rounded, bin, prec, scale);
 
157
  if (!err2)
 
158
    err2= err1;
 
159
  return check_result(mask, err2);
 
160
}
 
161
 
 
162
 
 
163
/*
 
164
  Convert string for decimal when string can be in some multibyte charset
 
165
 
 
166
  SYNOPSIS
 
167
    str2my_decimal()
 
168
    mask            error processing mask
 
169
    from            string to process
 
170
    length          length of given string
 
171
    charset         charset of given string
 
172
    decimal_value   buffer for result storing
 
173
 
 
174
  RESULT
 
175
    E_DEC_OK
 
176
    E_DEC_TRUNCATED
 
177
    E_DEC_OVERFLOW
 
178
    E_DEC_BAD_NUM
 
179
    E_DEC_OOM
 
180
*/
 
181
 
 
182
int str2my_decimal(uint32_t mask, const char *from, uint32_t length,
 
183
                   const CHARSET_INFO * charset, my_decimal *decimal_value)
 
184
{
 
185
  char *end, *from_end;
 
186
  int err;
 
187
  char buff[STRING_BUFFER_USUAL_SIZE];
 
188
  String tmp(buff, sizeof(buff), &my_charset_bin);
 
189
  if (charset->mbminlen > 1)
 
190
  {
 
191
    uint32_t dummy_errors;
 
192
    tmp.copy(from, length, charset, &my_charset_utf8_general_ci, &dummy_errors);
 
193
    from= tmp.ptr();
 
194
    length=  tmp.length();
 
195
    charset= &my_charset_bin;
 
196
  }
 
197
  from_end= end= (char*) from+length;
 
198
  err= string2decimal((char *)from, (decimal_t*) decimal_value, &end);
 
199
  if (end != from_end && !err)
 
200
  {
 
201
    /* Give warning if there is something other than end space */
 
202
    for ( ; end < from_end; end++)
 
203
    {
 
204
      if (!my_isspace(&my_charset_utf8_general_ci, *end))
 
205
      {
 
206
        err= E_DEC_TRUNCATED;
 
207
        break;
 
208
      }
 
209
    }
 
210
  }
 
211
  check_result_and_overflow(mask, err, decimal_value);
 
212
  return err;
 
213
}
 
214
 
 
215
 
 
216
my_decimal *date2my_decimal(DRIZZLE_TIME *ltime, my_decimal *dec)
 
217
{
 
218
  int64_t date;
 
219
  date = (ltime->year*100L + ltime->month)*100L + ltime->day;
 
220
  if (ltime->time_type > DRIZZLE_TIMESTAMP_DATE)
 
221
    date= ((date*100L + ltime->hour)*100L+ ltime->minute)*100L + ltime->second;
 
222
  if (int2my_decimal(E_DEC_FATAL_ERROR, date, false, dec))
 
223
    return dec;
 
224
  if (ltime->second_part)
 
225
  {
 
226
    dec->buf[(dec->intg-1) / 9 + 1]= ltime->second_part * 1000;
 
227
    dec->frac= 6;
 
228
  }
 
229
  return dec;
 
230
}
 
231
 
 
232
 
 
233
void my_decimal_trim(uint32_t *precision, uint32_t *scale)
 
234
{
 
235
  if (!(*precision) && !(*scale))
 
236
  {
 
237
    *precision= 10;
 
238
    *scale= 0;
 
239
    return;
 
240
  }
 
241
}
 
242
 
 
243
} /* namespace drizzled */