MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
field_newdecimal-t.cc
1 /* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15 
16 // First include (the generated) my_config.h, to get correct platform defines.
17 #include "my_config.h"
18 #include <gtest/gtest.h>
19 
20 #include "test_utils.h"
21 #include "fake_table.h"
22 
23 #include "field.h"
24 
25 type_conversion_status
26 store_internal_with_error_check(Field_new_decimal *field,
27  int conversion_err, my_decimal *value);
28 namespace field_newdecimal_unittest {
29 
30 using my_testing::chars_2_decimal;
33 
34 class FieldNewDecimalTest : public ::testing::Test
35 {
36 protected:
37  virtual void SetUp() { initializer.SetUp(); }
38  virtual void TearDown() { initializer.TearDown(); }
39 
40  THD *thd() { return initializer.thd(); }
41 
42  Server_initializer initializer;
43 
44  Field_set *create_field_set(TYPELIB *tl);
45 };
46 
47 
49 {
50  uchar buffer[MAX_FIELD_WIDTH];
51  uchar null_byte;
52  void initialize()
53  {
54  ptr= buffer;
55  null_ptr= &null_byte;
56  memset(buffer, 0, MAX_FIELD_WIDTH);
57  null_byte= '\0';
58  }
59 
60 public:
61  Mock_field_new_decimal(int decimals)
62  : Field_new_decimal(0, // ptr_arg
63  8, // len_arg
64  NULL, // null_ptr_arg
65  1, // null_bit_arg
66  Field::NONE, // unireg_check_arg
67  "field_name", // field_name_arg
68  decimals, // dec_arg
69  false, // zero_arg
70  false) // unsigned_arg
71  {
72  initialize();
73  }
74 
75  void make_writable() { bitmap_set_bit(table->write_set, field_index); }
76 
77  void test_store_string(const char *store_value, const int length,
78  const char *expected_string_result,
79  const longlong expected_int_result,
80  const double expected_real_result,
81  const int expected_error_no,
82  const type_conversion_status expected_status)
83  {
84  char buff[MAX_FIELD_WIDTH];
85  String str(buff, sizeof(buff), &my_charset_bin);
86  String unused;
87 
88  Mock_error_handler error_handler(table->in_use, expected_error_no);
89  type_conversion_status err= store(store_value, length, &my_charset_latin1);
90  val_str(&str, &unused);
91  EXPECT_STREQ(expected_string_result, str.ptr());
92  EXPECT_EQ(expected_int_result, val_int());
93  EXPECT_EQ(expected_real_result, val_real());
94 
95  EXPECT_FALSE(is_null());
96  EXPECT_EQ(expected_status, err);
97  EXPECT_EQ((expected_error_no == 0 ? 0 : 1), error_handler.handle_called());
98  }
99 
100 };
101 
102 
103 TEST_F(FieldNewDecimalTest, StoreLegalStringValues)
104 {
105  // Alows storing this range [-999.999, 999.999]
106  Mock_field_new_decimal field_dec(3);
107  Fake_TABLE table(&field_dec);
108  table.in_use= thd();
109  field_dec.make_writable();
110  thd()->count_cuted_fields= CHECK_FIELD_WARN;
111 
112  {
113  SCOPED_TRACE("");
114  field_dec.test_store_string(STRING_WITH_LEN("10.01"), "10.010", 10, 10.01,
115  0, TYPE_OK);
116  }
117  {
118  SCOPED_TRACE("");
119  field_dec.test_store_string(STRING_WITH_LEN("0"), "0.000", 0, 0,
120  0, TYPE_OK);
121  }
122 }
123 
124 
125 TEST_F(FieldNewDecimalTest, StoreIllegalStringValues)
126 {
127  // Alows storing this range [-999.999, 999.999]
128  Mock_field_new_decimal field_dec(3);
129  Fake_TABLE table(&field_dec);
130  table.in_use= thd();
131  field_dec.make_writable();
132  thd()->count_cuted_fields= CHECK_FIELD_WARN;
133 
134  // Truncated (precision beyond 3 decimals is lost)
135  {
136  SCOPED_TRACE("");
137  field_dec.test_store_string(STRING_WITH_LEN("10.0101"), "10.010",
138  10, 10.01,
139  WARN_DATA_TRUNCATED, TYPE_NOTE_TRUNCATED);
140  }
141  {
142  SCOPED_TRACE("");
143  field_dec.test_store_string(STRING_WITH_LEN("10.0109"), "10.011",
144  10, 10.011,
145  WARN_DATA_TRUNCATED, TYPE_NOTE_TRUNCATED);
146  }
147  // Values higher and lower than valid range for the decimal
148  {
149  SCOPED_TRACE("");
150  field_dec.test_store_string(STRING_WITH_LEN("10000"), "999.999",
151  1000, 999.999,
152  ER_WARN_DATA_OUT_OF_RANGE,
153  TYPE_WARN_OUT_OF_RANGE);
154  }
155 
156  // Values higher and lower than valid range for the decimal
157  {
158  SCOPED_TRACE("");
159  field_dec.test_store_string(STRING_WITH_LEN("-10000"), "-999.999",
160  -1000, -999.999,
161  ER_WARN_DATA_OUT_OF_RANGE,
162  TYPE_WARN_OUT_OF_RANGE);
163  }
164 }
165 
166 
167 static void test_store_internal(Field_new_decimal *field,
168  my_decimal *value,
169  const char *expected_string_result,
170  const longlong expected_int_result,
171  const double expected_real_result,
172  const int conversion_error,
173  const int expected_error_no,
174  const type_conversion_status expected_status)
175 {
176  char buff[MAX_FIELD_WIDTH];
177  String str(buff, sizeof(buff), &my_charset_bin);
178  String unused;
179 
180  Mock_error_handler error_handler(field->table->in_use, expected_error_no);
181  type_conversion_status err=
182  store_internal_with_error_check(field, conversion_error, value);
183  field->val_str(&str, &unused);
184  EXPECT_STREQ(expected_string_result, str.ptr());
185  EXPECT_EQ(expected_int_result, field->val_int());
186  EXPECT_EQ(expected_real_result, field->val_real());
187 
188  EXPECT_EQ(expected_status, err);
189 }
190 
191 
197 TEST_F(FieldNewDecimalTest, storeInternalWithErrorCheckLegalValues)
198 {
199  // Alows storing this range [-99.9999, 99.9999]
200  Mock_field_new_decimal field_dec(4);
201  Fake_TABLE table(&field_dec);
202  table.in_use= thd();
203  field_dec.make_writable();
204  thd()->count_cuted_fields= CHECK_FIELD_WARN;
205 
206  my_decimal d10_01;
207  my_decimal dMin10_01;
208  my_decimal d10_01001;
209  my_decimal d10_01009;
210  my_decimal dInsignificant;
211 
212  EXPECT_EQ(0, chars_2_decimal("10.01", &d10_01));
213  EXPECT_EQ(0, chars_2_decimal("-10.01", &dMin10_01));
214  EXPECT_EQ(0, chars_2_decimal("10.01001", &d10_01001));
215  EXPECT_EQ(0, chars_2_decimal("10.01009", &d10_01009));
216  EXPECT_EQ(0, chars_2_decimal("0.00000000001", &dInsignificant));
217 
218  // Legal values
219  {
220  SCOPED_TRACE("");
221  test_store_internal(&field_dec, &d10_01, "10.0100", 10, 10.01,
222  E_DEC_OK, 0, TYPE_OK);
223  }
224  {
225  SCOPED_TRACE("");
226  test_store_internal(&field_dec, &dMin10_01, "-10.0100", -10, -10.01,
227  E_DEC_OK, 0, TYPE_OK);
228  }
229 
230  // Legal values, but rounded
231  {
232  SCOPED_TRACE("");
233  test_store_internal(&field_dec, &d10_01001, "10.0100", 10, 10.01,
234  E_DEC_OK, WARN_DATA_TRUNCATED, TYPE_NOTE_TRUNCATED);
235  }
236  {
237  SCOPED_TRACE("");
238  test_store_internal(&field_dec, &d10_01009, "10.0101", 10, 10.0101,
239  E_DEC_OK, WARN_DATA_TRUNCATED, TYPE_NOTE_TRUNCATED);
240  }
241  {
242  SCOPED_TRACE("");
243  test_store_internal(&field_dec, &dInsignificant, "0.0000", 0, 0, E_DEC_OK,
244  WARN_DATA_TRUNCATED, TYPE_NOTE_TRUNCATED);
245  }
246 }
247 
248 
252 TEST_F(FieldNewDecimalTest, storeInternalWithErrorCheckOutOfRange)
253 {
254  // Alows storing this range [-99.9999, 99.9999]
255  Mock_field_new_decimal field_dec(4);
256  Fake_TABLE table(&field_dec);
257  table.in_use= thd();
258  field_dec.make_writable();
259  thd()->count_cuted_fields= CHECK_FIELD_WARN;
260 
261  my_decimal dTooHigh;
262  my_decimal dTooLow;
263 
264  EXPECT_EQ(0, chars_2_decimal("1000", &dTooHigh));
265  EXPECT_EQ(0, chars_2_decimal("-1000", &dTooLow));
266 
267  {
268  SCOPED_TRACE("");
269  test_store_internal(&field_dec, &dTooHigh, "99.9999", 100, 99.9999,
270  E_DEC_OK, ER_WARN_DATA_OUT_OF_RANGE,
271  TYPE_WARN_OUT_OF_RANGE);
272  }
273  {
274  SCOPED_TRACE("");
275  test_store_internal(&field_dec, &dTooLow, "-99.9999", -100, -99.9999,
276  E_DEC_OK, ER_WARN_DATA_OUT_OF_RANGE,
277  TYPE_WARN_OUT_OF_RANGE);
278  }
279 
280 }
281 
282 
291 TEST_F(FieldNewDecimalTest, storeInternalWithErrorCheckEDecOverflow)
292 {
293  // Alows storing this range [-99.9999, 99.9999]
294  Mock_field_new_decimal field_dec(4);
295  Fake_TABLE table(&field_dec);
296  table.in_use= thd();
297  field_dec.make_writable();
298  thd()->count_cuted_fields= CHECK_FIELD_WARN;
299 
300  my_decimal d10_01;
301  my_decimal dMin10_01;
302  my_decimal dInsignificant;
303  my_decimal dTooHigh;
304  my_decimal dTooLow;
305 
306  EXPECT_EQ(0, chars_2_decimal("10.01", &d10_01));
307  EXPECT_EQ(0, chars_2_decimal("-10.01", &dMin10_01));
308  EXPECT_EQ(0, chars_2_decimal("0.00000000001", &dInsignificant));
309  EXPECT_EQ(0, chars_2_decimal("1000", &dTooHigh));
310  EXPECT_EQ(0, chars_2_decimal("-1000", &dTooLow));
311 
312  // Positive number - the field's MAX value is used
313  {
314  SCOPED_TRACE("");
315  test_store_internal(&field_dec, &d10_01, "99.9999", 100, 99.9999,
316  E_DEC_OVERFLOW, ER_WARN_DATA_OUT_OF_RANGE,
317  TYPE_WARN_OUT_OF_RANGE);
318  }
319  {
320  SCOPED_TRACE("");
321  test_store_internal(&field_dec, &dInsignificant, "99.9999", 100, 99.9999,
322  E_DEC_OVERFLOW, ER_WARN_DATA_OUT_OF_RANGE,
323  TYPE_WARN_OUT_OF_RANGE);
324 
325  }
326  {
327  SCOPED_TRACE("");
328  test_store_internal(&field_dec, &dTooHigh, "99.9999", 100, 99.9999,
329  E_DEC_OVERFLOW, ER_WARN_DATA_OUT_OF_RANGE,
330  TYPE_WARN_OUT_OF_RANGE);
331  }
332 
333  // Negative number - the field's MIN value is used
334  {
335  SCOPED_TRACE("");
336  test_store_internal(&field_dec, &dMin10_01, "-99.9999", -100, -99.9999,
337  E_DEC_OVERFLOW, ER_WARN_DATA_OUT_OF_RANGE,
338  TYPE_WARN_OUT_OF_RANGE);
339 
340  }
341  {
342  SCOPED_TRACE("");
343  test_store_internal(&field_dec, &dTooLow, "-99.9999", -100, -99.9999,
344  E_DEC_OVERFLOW, ER_WARN_DATA_OUT_OF_RANGE,
345  TYPE_WARN_OUT_OF_RANGE);
346  }
347 }
348 
349 
361 TEST_F(FieldNewDecimalTest, storeInternalWithErrorCheckEDecTrunkated)
362 {
363  // Alows storing this range [-99.9999, 99.9999]
364  Mock_field_new_decimal field_dec(4);
365  Fake_TABLE table(&field_dec);
366  table.in_use= thd();
367  field_dec.make_writable();
368  thd()->count_cuted_fields= CHECK_FIELD_WARN;
369 
370  my_decimal d10_01;
371  my_decimal dMin10_01;
372  my_decimal dInsignificant;
373  my_decimal dTooHigh;
374  my_decimal dTooLow;
375 
376  EXPECT_EQ(0, chars_2_decimal("10.01", &d10_01));
377  EXPECT_EQ(0, chars_2_decimal("-10.01", &dMin10_01));
378  EXPECT_EQ(0, chars_2_decimal("0.00000000001", &dInsignificant));
379  EXPECT_EQ(0, chars_2_decimal("1000", &dTooHigh));
380  EXPECT_EQ(0, chars_2_decimal("-1000", &dTooLow));
381 
382 
383  // Conversion went fine
384  {
385  SCOPED_TRACE("");
386  test_store_internal(&field_dec, &d10_01, "10.0100", 10, 10.01,
387  E_DEC_TRUNCATED, WARN_DATA_TRUNCATED,
388  TYPE_NOTE_TRUNCATED);
389  }
390  {
391  SCOPED_TRACE("");
392  test_store_internal(&field_dec, &dMin10_01, "-10.0100", -10, -10.01,
393  E_DEC_TRUNCATED, WARN_DATA_TRUNCATED,
394  TYPE_NOTE_TRUNCATED);
395  }
396 
397  {
398  SCOPED_TRACE("");
399  test_store_internal(&field_dec, &dInsignificant, "0.0000", 0, 0,
400  E_DEC_TRUNCATED, WARN_DATA_TRUNCATED,
401  TYPE_NOTE_TRUNCATED);
402  }
403 
404  /*
405  In what follows, the values are out of range causing warning
406  ER_WARN_DATA_OUT_OF_RANGE instead of WARN_DATA_TRUNCATED.
407  */
408  {
409  SCOPED_TRACE("");
410  test_store_internal(&field_dec, &dTooHigh, "99.9999", 100, 99.9999,
411  E_DEC_TRUNCATED, ER_WARN_DATA_OUT_OF_RANGE,
412  TYPE_WARN_OUT_OF_RANGE);
413  }
414  {
415  SCOPED_TRACE("");
416  test_store_internal(&field_dec, &dTooLow, "-99.9999", -100, -99.9999,
417  E_DEC_TRUNCATED, ER_WARN_DATA_OUT_OF_RANGE,
418  TYPE_WARN_OUT_OF_RANGE);
419  }
420 }
421 
422 
429 TEST_F(FieldNewDecimalTest, storeInternalWithErrorCheckRestOfParams)
430 {
431  // Alows storing this range [-99.9999, 99.9999]
432  Mock_field_new_decimal field_dec(4);
433  Fake_TABLE table(&field_dec);
434  table.in_use= thd();
435  field_dec.make_writable();
436  thd()->count_cuted_fields= CHECK_FIELD_WARN;
437 
438  my_decimal d10_01;
439  EXPECT_EQ(0, chars_2_decimal("10.01", &d10_01));
440 
441  test_store_internal(&field_dec, &d10_01, "10.0100", 10, 10.01,
442  E_DEC_DIV_ZERO, 0, TYPE_OK);
443 
444  test_store_internal(&field_dec, &d10_01, "10.0100", 10, 10.01,
445  E_DEC_BAD_NUM, 0, TYPE_OK);
446 
447  test_store_internal(&field_dec, &d10_01, "10.0100", 10, 10.01,
448  E_DEC_OOM, 0, TYPE_OK);
449 }
450 
451 }