1 /* Copyright (c) 2012, 2021, 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 also distributed 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 included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
22 
23 // First include (the generated) my_config.h, to get correct platform defines.
24 #include "my_config.h"
25 #include <gtest/gtest.h>
26 
27 #include "test_utils.h"
28 #include "fake_table.h"
29 
30 #include "field.h"
31 
32 namespace field_long_unittest {
33 
34 using my_testing::Server_initializer;
35 using my_testing::Mock_error_handler;
36 
37 class FieldLongTest : public ::testing::Test
38 {
39 protected:
SetUp()40   virtual void SetUp() { initializer.SetUp(); }
TearDown()41   virtual void TearDown() { initializer.TearDown(); }
42 
thd()43   THD *thd() { return initializer.thd(); }
44 
45   Server_initializer initializer;
46 
47   Field_set *create_field_set(TYPELIB *tl);
48 };
49 
50 class Mock_field_long : public Field_long
51 {
52   uchar buffer[PACK_LENGTH];
53   uchar null_byte;
initialize()54   void initialize()
55   {
56     ptr= buffer;
57     memset(buffer, 0, PACK_LENGTH);
58     null_byte= '\0';
59     set_null_ptr(&null_byte, 1);
60   }
61 public:
Mock_field_long()62   Mock_field_long()
63     : Field_long(0,                             // ptr_arg
64                  8,                             // len_arg
65                  NULL,                          // null_ptr_arg
66                  1,                             // null_bit_arg
67                  Field::NONE,                   // unireg_check_arg
68                  "field_name",                  // field_name_arg
69                  false,                         // zero_arg
70                  false)                         // unsigned_arg
71   {
72     initialize();
73   }
74 
make_writable()75   void make_writable() { bitmap_set_bit(table->write_set, field_index); }
make_readable()76   void make_readable() { bitmap_set_bit(table->read_set, field_index); }
77 
78 };
79 
test_store_long(Field_long * field,const longlong store_value,const longlong expected_result,const int expected_error_no,const type_conversion_status expected_status)80 void test_store_long(Field_long *field,
81                      const longlong store_value,
82                      const longlong expected_result,
83                      const int expected_error_no,
84                      const type_conversion_status expected_status)
85 {
86   Mock_error_handler error_handler(field->table->in_use, expected_error_no);
87   type_conversion_status err= field->store(store_value, false); // signed
88   EXPECT_EQ(expected_result, field->val_int());
89   EXPECT_FALSE(field->is_null());
90   EXPECT_EQ(expected_status, err);
91   EXPECT_EQ((expected_error_no == 0 ? 0 : 1), error_handler.handle_called());
92 }
93 
test_store_string(Field_long * field,const char * store_value,const int length,const longlong expected_result,const int expected_error_no,const type_conversion_status expected_status)94 void test_store_string(Field_long *field,
95                        const char *store_value, const int length,
96                        const longlong expected_result,
97                        const int expected_error_no,
98                        const type_conversion_status expected_status)
99 {
100   Mock_error_handler error_handler(field->table->in_use, expected_error_no);
101   type_conversion_status err= field->store(store_value, length,
102                                            &my_charset_latin1);
103   EXPECT_EQ(expected_result, field->val_int());
104   EXPECT_FALSE(field->is_null());
105   EXPECT_EQ(expected_status, err);
106   EXPECT_EQ((expected_error_no == 0 ? 0 : 1), error_handler.handle_called());
107 }
108 
109 
TEST_F(FieldLongTest,StoreLegalIntValues)110 TEST_F(FieldLongTest, StoreLegalIntValues)
111 {
112   Mock_field_long field_long;
113   Fake_TABLE table(&field_long);
114   table.in_use= thd();
115   field_long.make_writable();
116   field_long.make_readable();
117   thd()->count_cuted_fields= CHECK_FIELD_WARN;
118 
119   SCOPED_TRACE(""); test_store_long(&field_long, 0,   0, 0, TYPE_OK);
120   SCOPED_TRACE(""); test_store_long(&field_long, 5,   5, 0, TYPE_OK);
121   SCOPED_TRACE(""); test_store_long(&field_long, -1, -1, 0, TYPE_OK);
122 
123   {
124     SCOPED_TRACE("");
125     test_store_long(&field_long, INT_MIN32, INT_MIN32, 0, TYPE_OK);
126   }
127   {
128     SCOPED_TRACE("");
129     test_store_long(&field_long, INT_MAX32, INT_MAX32, 0, TYPE_OK);
130   }
131 
132   {
133     Mock_error_handler error_handler(thd(), 0);
134     type_conversion_status err;
135     err= set_field_to_null(&field_long);
136 
137     EXPECT_EQ(0, field_long.val_int());
138     EXPECT_TRUE(field_long.is_null());
139     EXPECT_EQ(TYPE_OK, err);
140 
141     field_long.set_notnull();
142     EXPECT_EQ(0, field_long.val_int());
143     EXPECT_FALSE(field_long.is_null());
144 
145     // None of the above should generate warnings
146     EXPECT_EQ(0, error_handler.handle_called());
147   }
148 }
149 
150 // Values higher and lower than valid range for the Field_long
TEST_F(FieldLongTest,StoreOutOfRangeIntValues)151 TEST_F(FieldLongTest, StoreOutOfRangeIntValues)
152 {
153   Mock_field_long field_long;
154   Fake_TABLE table(&field_long);
155   table.in_use= thd();
156   field_long.make_writable();
157   field_long.make_readable();
158   thd()->count_cuted_fields= CHECK_FIELD_WARN;
159 
160 
161   // Field_long is signed
162   {
163     SCOPED_TRACE("");
164     test_store_long(&field_long, INT_MAX32 + 1LL, INT_MAX32,
165                     ER_WARN_DATA_OUT_OF_RANGE,
166                     TYPE_WARN_OUT_OF_RANGE);
167   }
168   {
169     SCOPED_TRACE("");
170     test_store_long(&field_long, INT_MIN32 - 1LL, INT_MIN32,
171                     ER_WARN_DATA_OUT_OF_RANGE,
172                     TYPE_WARN_OUT_OF_RANGE);
173   }
174 
175   // Field_long is unsigned
176   {
177     SCOPED_TRACE("");
178     field_long.unsigned_flag= true;
179   }
180   {
181     SCOPED_TRACE("");
182     test_store_long(&field_long, -1LL, 0, ER_WARN_DATA_OUT_OF_RANGE,
183                     TYPE_WARN_OUT_OF_RANGE);
184   }
185   {
186     SCOPED_TRACE("");
187     test_store_long(&field_long, INT_MIN32, 0, ER_WARN_DATA_OUT_OF_RANGE,
188                     TYPE_WARN_OUT_OF_RANGE);
189   }
190 
191 }
192 
193 
TEST_F(FieldLongTest,StoreLegalStringValues)194 TEST_F(FieldLongTest, StoreLegalStringValues)
195 {
196   Mock_field_long field_long;
197 
198   Fake_TABLE table(&field_long);
199   table.in_use= thd();
200   field_long.make_writable();
201   field_long.make_readable();
202   thd()->count_cuted_fields= CHECK_FIELD_WARN;
203 
204   const char min_int[]= "-2147483648";
205   const char max_int[]= "2147483647";
206   const char max_int_plus1[]= "2147483648";
207   const char max_uint[]= "4294967295";
208 
209   // Field_long is signed
210   {
211     SCOPED_TRACE("");
212     test_store_string(&field_long, STRING_WITH_LEN("0"),   0, 0, TYPE_OK);
213   }
214   {
215     SCOPED_TRACE("");
216     test_store_string(&field_long, STRING_WITH_LEN("1"),   1, 0, TYPE_OK);
217   }
218   {
219     SCOPED_TRACE("");
220     test_store_string(&field_long, STRING_WITH_LEN("-1"), -1, 0, TYPE_OK);
221   }
222   {
223     SCOPED_TRACE("");
224     test_store_string(&field_long, STRING_WITH_LEN(max_int), INT_MAX32,
225                       0, TYPE_OK);
226   }
227   {
228     SCOPED_TRACE("");
229     test_store_string(&field_long, STRING_WITH_LEN(min_int), INT_MIN32,
230                       0, TYPE_OK);
231   }
232 
233   // Field_long is unsigned
234   field_long.unsigned_flag= true;
235   {
236     SCOPED_TRACE("");
237     test_store_string(&field_long, STRING_WITH_LEN(max_int_plus1),
238                       INT_MAX32 + 1LL,
239                       0, TYPE_OK);
240   }
241   {
242     SCOPED_TRACE("");
243     test_store_string(&field_long, STRING_WITH_LEN(max_uint), UINT_MAX32,
244                       0, TYPE_OK);
245   }
246 }
247 
248 
TEST_F(FieldLongTest,StoreIllegalStringValues)249 TEST_F(FieldLongTest, StoreIllegalStringValues)
250 {
251   Mock_field_long field_long;
252 
253   Fake_TABLE table(&field_long);
254   table.in_use= thd();
255   field_long.make_writable();
256   field_long.make_readable();
257   thd()->count_cuted_fields= CHECK_FIELD_WARN;
258 
259   const char max_int_plus1[]=  "2147483648";
260   const char min_int_minus1[]= "-2147483649";
261   const char very_high[]=      "999999999999999";
262   const char very_low[]=       "-999999999999999";
263 
264   // Field_long is signed - Stored value is INT_MIN32/INT_MAX32
265   //                        depending on sign of string to store
266   {
267     SCOPED_TRACE("");
268     test_store_string(&field_long, STRING_WITH_LEN(max_int_plus1), INT_MAX32,
269                       ER_WARN_DATA_OUT_OF_RANGE,
270                       TYPE_WARN_OUT_OF_RANGE);
271   }
272   {
273     SCOPED_TRACE("");
274     test_store_string(&field_long, STRING_WITH_LEN(very_high), INT_MAX32,
275                       ER_WARN_DATA_OUT_OF_RANGE,
276                       TYPE_WARN_OUT_OF_RANGE);
277 
278   }
279   {
280     SCOPED_TRACE("");
281     test_store_string(&field_long, STRING_WITH_LEN(min_int_minus1), INT_MIN32,
282                       ER_WARN_DATA_OUT_OF_RANGE,
283                       TYPE_WARN_OUT_OF_RANGE);
284   }
285   {
286     SCOPED_TRACE("");
287     test_store_string(&field_long, STRING_WITH_LEN(very_low), INT_MIN32,
288                       ER_WARN_DATA_OUT_OF_RANGE,
289                       TYPE_WARN_OUT_OF_RANGE);
290   }
291 
292   // Field_long is unsigned - Stored value is 0/UINT_MAX32
293   //                          depending on sign of string to store
294   const char min_int[]=        "-2147483648";
295   const char max_uint_plus1[]= "4294967296";
296   field_long.unsigned_flag= true;
297 
298   {
299     SCOPED_TRACE("");
300     test_store_string(&field_long, STRING_WITH_LEN(max_uint_plus1), UINT_MAX32,
301                       ER_WARN_DATA_OUT_OF_RANGE,
302                       TYPE_WARN_OUT_OF_RANGE);
303   }
304   {
305     SCOPED_TRACE("");
306     test_store_string(&field_long, STRING_WITH_LEN(very_high), UINT_MAX32,
307                       ER_WARN_DATA_OUT_OF_RANGE,
308                       TYPE_WARN_OUT_OF_RANGE);
309   }
310   {
311     SCOPED_TRACE("");
312     test_store_string(&field_long, STRING_WITH_LEN("-1"), 0,
313                       ER_WARN_DATA_OUT_OF_RANGE,
314                       TYPE_WARN_OUT_OF_RANGE);
315   }
316   {
317     SCOPED_TRACE("");
318     test_store_string(&field_long, STRING_WITH_LEN(min_int), 0,
319                       ER_WARN_DATA_OUT_OF_RANGE,
320                       TYPE_WARN_OUT_OF_RANGE);
321   }
322   {
323     SCOPED_TRACE("");
324     test_store_string(&field_long, STRING_WITH_LEN(very_low), 0,
325                       ER_WARN_DATA_OUT_OF_RANGE,
326                       TYPE_WARN_OUT_OF_RANGE);
327   }
328 
329   // Invalid value
330   {
331     SCOPED_TRACE("");
332     test_store_string(&field_long, STRING_WITH_LEN("foo"), 0,
333                       ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
334                       TYPE_ERR_BAD_VALUE);
335   }
336 }
337 
TEST_F(FieldLongTest,StoreNullValue)338 TEST_F(FieldLongTest, StoreNullValue)
339 {
340   Mock_field_long field_long;
341 
342   Fake_TABLE table(&field_long);
343   table.in_use= thd();
344   field_long.make_writable();
345   field_long.make_readable();
346   thd()->count_cuted_fields= CHECK_FIELD_WARN;
347 
348   type_conversion_status err;
349 
350   // Save NULL value in a field that can have NULL value
351   {
352     Mock_error_handler error_handler(thd(), 0);
353     err= set_field_to_null(&field_long);
354     EXPECT_EQ(0, field_long.val_int());
355     EXPECT_EQ(TYPE_OK, err);
356 
357     err= set_field_to_null_with_conversions(&field_long, true);
358     EXPECT_EQ(0, field_long.val_int());
359     EXPECT_EQ(TYPE_OK, err);
360 
361     err= set_field_to_null_with_conversions(&field_long, false);
362     EXPECT_EQ(0, field_long.val_int());
363     EXPECT_EQ(TYPE_OK, err);
364 
365     EXPECT_EQ(0, error_handler.handle_called());
366   }
367 
368   // Save NULL value in a field that can NOT have NULL value
369   field_long.set_null_ptr(NULL, 0);
370   {
371     Mock_error_handler error_handler(thd(), 0);
372     // Save NULL value in a field that can be set to NULL temporary
373     field_long.set_tmp_nullable();
374     err= set_field_to_null(&field_long);
375     EXPECT_EQ(0, field_long.val_int());
376     EXPECT_EQ(TYPE_OK, err);
377     EXPECT_EQ(0, error_handler.handle_called());
378     field_long.reset_tmp_nullable();
379   }
380 
381   {
382     Mock_error_handler error_handler(thd(), 0);
383     err= set_field_to_null_with_conversions(&field_long, true);
384     EXPECT_EQ(0, field_long.val_int());
385     EXPECT_EQ(TYPE_ERR_NULL_CONSTRAINT_VIOLATION, err);
386     EXPECT_EQ(0, error_handler.handle_called());
387   }
388 
389   {
390     Mock_error_handler error_handler(thd(), ER_BAD_NULL_ERROR);
391     err= set_field_to_null_with_conversions(&field_long, false);
392     EXPECT_EQ(0, field_long.val_int());
393     EXPECT_EQ(TYPE_OK, err);
394     EXPECT_EQ(1, error_handler.handle_called());
395   }
396 }
397 
398 }
399