1 /* Copyright (c) 2011, 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 #include "sql_time.h"
32 #include <my_decimal.h>
33
34 namespace field_unittests {
35
36 using my_testing::Server_initializer;
37 using my_testing::Mock_error_handler;
38
39 class FieldTest : public ::testing::Test
40 {
41 protected:
SetUp()42 virtual void SetUp() { initializer.SetUp(); }
TearDown()43 virtual void TearDown() { initializer.TearDown(); }
44
thd()45 THD *thd() { return initializer.thd(); }
46
47 Server_initializer initializer;
48
49 Field_set *create_field_set(TYPELIB *tl);
50 };
51
52
compareMysqlTime(const MYSQL_TIME & first,const MYSQL_TIME & second)53 static void compareMysqlTime(const MYSQL_TIME& first, const MYSQL_TIME& second)
54 {
55 EXPECT_EQ(first.year, second.year);
56 EXPECT_EQ(first.month, second.month);
57 EXPECT_EQ(first.day, second.day);
58 EXPECT_EQ(first.hour, second.hour);
59 EXPECT_EQ(first.minute, second.minute);
60 EXPECT_EQ(first.second, second.second);
61 EXPECT_EQ(first.second_part, second.second_part);
62 EXPECT_EQ(first.neg, second.neg);
63 EXPECT_EQ(first.time_type, second.time_type);
64 }
65
66 class Mock_table : public TABLE
67 {
68 public:
Mock_table(THD * thd)69 Mock_table(THD *thd)
70 {
71 null_row= false;
72 read_set= 0;
73 in_use= thd;
74 }
75 };
76
77 // A mock Protocol class to be able to test Field::send_binary
78 // It just verifies that store_time has been passed what is expected
79 class Mock_protocol : public Protocol
80 {
81 private:
82 MYSQL_TIME t;
83 uint p;
84 public:
Mock_protocol(THD * thd)85 Mock_protocol(THD *thd) {}
86
store_time(MYSQL_TIME * time,uint precision)87 virtual bool store_time(MYSQL_TIME *time, uint precision)
88 {
89 t= *time;
90 p= precision;
91 return false;
92 }
93
verify_time(MYSQL_TIME * time,uint precision)94 void verify_time(MYSQL_TIME *time, uint precision)
95 {
96 compareMysqlTime(*time, t);
97 EXPECT_EQ(precision, p);
98 }
99
100 // Lots of functions that require implementation
read_packet()101 int read_packet() { return 0; }
get_client_capabilities()102 ulong get_client_capabilities() { return 0; }
has_client_capability(unsigned long client_capability)103 bool has_client_capability(unsigned long client_capability) {return false;}
end_partial_result_set()104 void end_partial_result_set() {}
shutdown(bool server_shutdown=false)105 int shutdown(bool server_shutdown= false) { return 0; }
get_ssl()106 void *get_ssl() { return 0; }
start_row()107 void start_row() {}
end_row()108 bool end_row() { return false; }
connection_alive()109 bool connection_alive() { return false; }
abort_row()110 void abort_row() {}
get_rw_status()111 uint get_rw_status() { return 0; }
get_compression()112 bool get_compression() { return false; }
start_result_metadata(uint num_cols,uint flags,const CHARSET_INFO * resultcs)113 bool start_result_metadata(uint num_cols, uint flags,
114 const CHARSET_INFO *resultcs)
115 { return false; }
send_num_fields(uint)116 void send_num_fields(uint) {}
send_num_rows(uint)117 void send_num_rows(uint) {}
send_field_metadata(Send_field * field,const CHARSET_INFO * charset)118 bool send_field_metadata(Send_field *field,
119 const CHARSET_INFO *charset) { return false; }
send_ok(uint server_status,uint statement_warn_count,ulonglong affected_rows,ulonglong last_insert_id,const char * message)120 virtual bool send_ok(uint server_status, uint statement_warn_count,
121 ulonglong affected_rows, ulonglong last_insert_id,
122 const char *message) { return false; }
123
send_eof(uint server_status,uint statement_warn_count)124 virtual bool send_eof(uint server_status,
125 uint statement_warn_count) { return false; }
send_error(uint sql_errno,const char * err_msg,const char * sql_state)126 virtual bool send_error(uint sql_errno, const char *err_msg,
127 const char *sql_state) { return false; }
end_result_metadata()128 bool end_result_metadata() { return false; }
129
store_null()130 virtual bool store_null() { return false; }
store_tiny(longlong from)131 virtual bool store_tiny(longlong from) { return false; }
store_short(longlong from)132 virtual bool store_short(longlong from) { return false; }
store_long(longlong from)133 virtual bool store_long(longlong from) { return false; }
store_longlong(longlong from,bool unsigned_flag)134 virtual bool store_longlong(longlong from, bool unsigned_flag)
135 { return false; }
store_decimal(const my_decimal *,uint,uint)136 virtual bool store_decimal(const my_decimal *, uint, uint) { return false; }
store(const char * from,size_t length,const CHARSET_INFO * fromcs)137 virtual bool store(const char *from, size_t length,
138 const CHARSET_INFO *fromcs) { return false; }
store(float from,uint32 decimals,String * buffer)139 virtual bool store(float from, uint32 decimals, String *buffer)
140 { return false; }
store(double from,uint32 decimals,String * buffer)141 virtual bool store(double from, uint32 decimals, String *buffer)
142 { return false; }
store(MYSQL_TIME * time,uint precision)143 virtual bool store(MYSQL_TIME *time, uint precision) { return false; }
store_date(MYSQL_TIME * time)144 virtual bool store_date(MYSQL_TIME *time) { return false; }
store(Proto_field * field)145 virtual bool store(Proto_field *field) { return false; }
type()146 virtual enum enum_protocol_type type() { return PROTOCOL_LOCAL; };
connection_type()147 virtual enum enum_vio_type connection_type() { return NO_VIO_TYPE; }
get_command(COM_DATA * com_data,enum_server_command * cmd)148 virtual int get_command(COM_DATA *com_data, enum_server_command *cmd)
149 { return -1; }
150 };
151
152
TEST_F(FieldTest,FieldTimef)153 TEST_F(FieldTest, FieldTimef)
154 {
155 uchar fieldBuf[6];
156 uchar nullPtr[1]= {0};
157 MYSQL_TIME time= {0, 0, 0, 12, 23, 12, 123400, false, MYSQL_TIMESTAMP_TIME};
158
159 Field_timef* field= new Field_timef(fieldBuf, nullPtr, false, Field::NONE,
160 "f1", 4);
161 // Test public member functions
162 EXPECT_EQ(4UL, field->decimals()); //TS-TODO
163 EXPECT_EQ(MYSQL_TYPE_TIME, field->type());
164 EXPECT_EQ(MYSQL_TYPE_TIME2, field->binlog_type());
165
166 longlong packed= TIME_to_longlong_packed(&time);
167
168 EXPECT_EQ(0, field->store_packed(packed));
169 EXPECT_DOUBLE_EQ(122312.1234, field->val_real());
170 EXPECT_EQ(122312, field->val_int());
171 EXPECT_EQ(packed, field->val_time_temporal());
172
173 my_decimal decval;
174 my_decimal* dec= field->val_decimal(&decval);
175 double res;
176 my_decimal2double(0, dec, &res);
177 EXPECT_DOUBLE_EQ(122312.1234, res);
178
179 EXPECT_EQ(5UL, field->pack_length());
180 EXPECT_EQ(5UL, field->pack_length_from_metadata(4));
181 EXPECT_EQ(5UL, field->row_pack_length());
182
183 String str(7);
184 field->sql_type(str);
185 EXPECT_STREQ("time(4)", str.c_ptr_safe());
186
187 EXPECT_EQ(1, field->zero_pack());
188 EXPECT_EQ(&my_charset_bin, field->sort_charset());
189
190 // Test clone
191 Field* copy= field->clone();
192 EXPECT_EQ(field->decimals(), copy->decimals());
193 EXPECT_EQ(field->type(), copy->type());
194 EXPECT_DOUBLE_EQ(field->val_real(), copy->val_real());
195 EXPECT_EQ(field->val_int(), copy->val_int());
196 EXPECT_EQ(field->val_time_temporal(), copy->val_time_temporal());
197 EXPECT_EQ(0, field->cmp(field->ptr, copy->ptr));
198
199 // Test reset
200 EXPECT_EQ(0, field->reset());
201 EXPECT_DOUBLE_EQ(0.0, field->val_real());
202 EXPECT_EQ(0, field->val_int());
203
204 // Test inherited member functions
205 // Functions inherited from Field_time_common
206 field->store_time(&time, 4);
207 EXPECT_EQ(4UL, field->decimals());
208 EXPECT_EQ(MYSQL_TYPE_TIME, field->type());
209 EXPECT_DOUBLE_EQ(122312.1234, field->val_real());
210 EXPECT_EQ(122312, field->val_int());
211 EXPECT_EQ(packed, field->val_time_temporal());
212
213 String timeStr(15);
214 EXPECT_STREQ("12:23:12.1234", field->val_str(&timeStr, &timeStr)->c_ptr());
215
216 field->store_time(&time, 0);
217 EXPECT_DOUBLE_EQ(122312.1234, field->val_real()); // Correct?
218
219 MYSQL_TIME dateTime;
220 MYSQL_TIME bigTime= {0, 0, 0, 123, 45, 45, 555500, false, MYSQL_TIMESTAMP_TIME};
221 EXPECT_EQ(0, field->store_time(&bigTime, 4));
222 EXPECT_FALSE(field->get_date(&dateTime, 0));
223
224 make_datetime((Date_time_format *)0, &dateTime, &timeStr, 6);
225 // Skip 'yyyy-mm-dd ' since that will depend on current time zone.
226 EXPECT_STREQ("03:45:45.555500", timeStr.c_ptr() + 11);
227
228 MYSQL_TIME t;
229 EXPECT_FALSE(field->get_time(&t));
230 compareMysqlTime(bigTime, t);
231
232 Mock_protocol protocol(thd());
233 EXPECT_EQ(protocol.connection_type(), NO_VIO_TYPE);
234 EXPECT_FALSE(field->send_binary(&protocol));
235 // The verification below fails because send_binary move hours to days
236 // protocol.verify_time(&bigTime, 0); // Why 0?
237
238 // Function inherited from Field_temporal
239 EXPECT_TRUE(field->is_temporal());
240 EXPECT_EQ(STRING_RESULT, field->result_type());
241 EXPECT_EQ(15UL, field->max_display_length());
242 EXPECT_TRUE(field->str_needs_quotes());
243
244 // Not testing is_equal() yet, will require a mock TABLE object
245 // Create_field cf(field, field);
246 // EXPECT_TRUE(field->is_equal(&cf));
247
248 EXPECT_EQ(DECIMAL_RESULT, field->numeric_context_result_type());
249 EXPECT_EQ(INT_RESULT, field->cmp_type());
250 EXPECT_EQ(INT_RESULT, field->cmp_type());
251 EXPECT_EQ(DERIVATION_NUMERIC, field->derivation());
252 EXPECT_EQ(&my_charset_numeric, field->charset());
253 EXPECT_TRUE(field->can_be_compared_as_longlong());
254 EXPECT_TRUE(field->binary());
255 // Below is not tested, because of ASSERT
256 // EXPECT_EQ(TIMESTAMP_NO_AUTO_SET, field->get_auto_set_type());
257
258 // Not testing make_field, it also needs a mock TABLE object
259
260 EXPECT_EQ(TYPE_OK, field->store("12:23:12.123456", 15, &my_charset_numeric));
261 EXPECT_DOUBLE_EQ(122312.1235, field->val_real());
262
263 EXPECT_EQ(TYPE_OK, field->store_decimal(dec));
264 EXPECT_DOUBLE_EQ(122312.1234, field->val_real());
265
266 EXPECT_EQ(TYPE_OK, field->store(-234545, false));
267 EXPECT_DOUBLE_EQ(-234545.0, field->val_real());
268
269 {
270 // Test that store() with a to big number gives right error
271 Mock_error_handler error_handler(thd(), ER_TRUNCATED_WRONG_VALUE);
272 EXPECT_EQ(TYPE_WARN_OUT_OF_RANGE, field->store(0x80000000, true));
273 // Test that error handler was actually called
274 EXPECT_EQ(1, error_handler.handle_called());
275 // Test that field contains expecte max time value
276 EXPECT_DOUBLE_EQ(8385959, field->val_real()); // Max time value
277 }
278
279 EXPECT_EQ(TYPE_OK, field->store(1234545.555555));
280 EXPECT_DOUBLE_EQ(1234545.5556, field->val_real());
281
282 // Some of the functions inherited from Field
283 Field *f= field;
284 EXPECT_EQ(TYPE_OK, f->store_time(&time, MYSQL_TIMESTAMP_TIME));
285 EXPECT_DOUBLE_EQ(122312.1234, f->val_real()); // Why decimals here?
286 EXPECT_STREQ("12:23:12.1234", f->val_str(&timeStr)->c_ptr());
287 EXPECT_STREQ("122312", f->val_int_as_str(&timeStr, false)->c_ptr());
288 EXPECT_TRUE(f->eq(copy));
289 EXPECT_TRUE(f->eq_def(copy));
290
291 // Not testing store(const char, uint, const CHARSET_INFO *, enum_check_fields)
292 // it requires a mock table
293
294 Mock_table m_table(thd());
295 f->table= &m_table;
296 struct timeval tv;
297 int warnings= 0;
298 EXPECT_FALSE(f->get_timestamp(&tv, &warnings));
299 EXPECT_EQ(123400, tv.tv_usec);
300
301 delete field;
302
303 }
304
TEST_F(FieldTest,FieldTimefCompare)305 TEST_F(FieldTest, FieldTimefCompare)
306 {
307 const int nFields= 7;
308 uchar fieldBufs[nFields][6];
309 uchar nullPtrs[nFields];
310
311 MYSQL_TIME times[nFields]= {
312 {0, 0, 0, 12, 23, 12, 100000, true, MYSQL_TIMESTAMP_TIME},
313 {0, 0, 0, 0, 0, 0, 10000, true, MYSQL_TIMESTAMP_TIME},
314 {0, 0, 0, 0, 0, 0, 0, false, MYSQL_TIMESTAMP_TIME},
315 {0, 0, 0, 0, 0, 0, 999900, false, MYSQL_TIMESTAMP_TIME},
316 {0, 0, 0, 0, 0, 0, 999990, false, MYSQL_TIMESTAMP_TIME},
317 {0, 0, 0, 11, 59, 59, 999999, false, MYSQL_TIMESTAMP_TIME},
318 {0, 0, 0, 12, 00, 00, 100000, false, MYSQL_TIMESTAMP_TIME}};
319
320 Field* fields[nFields];
321 uchar sortStrings[nFields][6];
322 for (int i=0; i < nFields; ++i)
323 {
324 char fieldName[3];
325 sprintf(fieldName, "f%c", i);
326 fields[i]= new Field_timef(fieldBufs[i], nullPtrs+i, false, Field::NONE,
327 fieldName, 6);
328
329 longlong packed= TIME_to_longlong_packed(×[i]);
330 EXPECT_EQ(0, fields[i]->store_packed(packed));
331 fields[i]->make_sort_key(sortStrings[i], fields[i]->pack_length());
332 }
333
334 for (int i=0; i < nFields; ++i)
335 for (int j=0; j < nFields; ++j)
336 {
337 String tmp;
338 if (i < j)
339 {
340 EXPECT_GT(0, memcmp(sortStrings[i], sortStrings[j],
341 fields[i]->pack_length()))
342 << fields[i]->val_str(&tmp)->c_ptr() << " < "
343 << fields[j]->val_str(&tmp)->c_ptr();
344 EXPECT_GT(0, fields[i]->cmp(fields[i]->ptr, fields[j]->ptr))
345 << fields[i]->val_str(&tmp)->c_ptr() << " < "
346 << fields[j]->val_str(&tmp)->c_ptr();
347 }
348 else if (i > j)
349 {
350 EXPECT_LT(0, memcmp(sortStrings[i], sortStrings[j],
351 fields[i]->pack_length()))
352 << fields[i]->val_str(&tmp)->c_ptr() << " > "
353 << fields[j]->val_str(&tmp)->c_ptr();
354 EXPECT_LT(0, fields[i]->cmp(fields[i]->ptr, fields[j]->ptr))
355 << fields[i]->val_str(&tmp)->c_ptr() << " > "
356 << fields[j]->val_str(&tmp)->c_ptr();
357 }
358 else
359 {
360 EXPECT_EQ(0, memcmp(sortStrings[i], sortStrings[j],
361 fields[i]->pack_length()))
362 << fields[i]->val_str(&tmp)->c_ptr() << " = "
363 << fields[j]->val_str(&tmp)->c_ptr();
364 EXPECT_EQ(0, fields[i]->cmp(fields[i]->ptr, fields[j]->ptr))
365 << fields[i]->val_str(&tmp)->c_ptr() << " = "
366 << fields[j]->val_str(&tmp)->c_ptr();
367 }
368 }
369 }
370
371
TEST_F(FieldTest,FieldTime)372 TEST_F(FieldTest, FieldTime)
373 {
374 uchar fieldBuf[6];
375 uchar nullPtr[1]= {0};
376 MYSQL_TIME bigTime= {0, 0, 0, 123, 45, 45, 555500, false, MYSQL_TIMESTAMP_TIME};
377
378 Field_time* field= new Field_time(fieldBuf, nullPtr, false, Field::NONE,
379 "f1");
380 EXPECT_EQ(0, field->store_time(&bigTime, 4));
381 MYSQL_TIME t;
382 EXPECT_FALSE(field->get_time(&t));
383 compareMysqlTime(bigTime, t);
384 }
385
386
387 const char *type_names3[]= { "one", "two", "three", NULL };
388 unsigned int type_lengths3[]= { 3U, 3U, 5U, 0U };
389 TYPELIB tl3= { 3, "tl3", type_names3, type_lengths3 };
390
391 const char *type_names4[]= { "one", "two", "three", "four", NULL };
392 unsigned int type_lengths4[]= { 3U, 3U, 5U, 4U, 0U };
393 TYPELIB tl4= { 4, "tl4", type_names4, type_lengths4 };
394
395
create_field_set(TYPELIB * tl)396 Field_set *FieldTest::create_field_set(TYPELIB *tl)
397 {
398 Field_set *f= new (thd()->mem_root)
399 Field_set(NULL, // ptr_arg
400 42, // len_arg
401 NULL, // null_ptr_arg
402 '\0', // null_bit_arg
403 Field::NONE, // unireg_check_arg
404 "f1", // field_name_arg
405 1, // packlength_arg
406 tl, // typelib_arg
407 &my_charset_latin1); // charset_arg
408 f->table= new Fake_TABLE(f);
409 return f;
410 }
411
412
413 // Bug#13871079 RQG_MYISAM_DML_ALTER_VALGRIND FAILS ON VALGRIND PN PB2
TEST_F(FieldTest,CopyFieldSet)414 TEST_F(FieldTest, CopyFieldSet)
415 {
416 int err;
417 char fields[]= "one,two";
418 my_ulonglong typeset= find_typeset(fields, &tl3, &err);
419 EXPECT_EQ(0, err);
420
421 // Using two different TYPELIBs will set cf->do_copy to do_field_string().
422 Field_set *f_to= create_field_set(&tl3);
423 bitmap_set_all(f_to->table->write_set);
424 uchar to_fieldval= 0;
425 f_to->ptr= &to_fieldval;
426
427 Field_set *f_from= create_field_set(&tl4);
428 bitmap_set_all(f_from->table->write_set);
429 bitmap_set_all(f_from->table->read_set);
430 uchar from_fieldval= static_cast<uchar>(typeset);
431 f_from->ptr= &from_fieldval;
432
433 Copy_field *cf= new (thd()->mem_root) Copy_field;
434 cf->set(f_to, f_from, false);
435 cf->invoke_do_copy(cf);
436
437 // Copy_field DTOR is not invoked in all contexts, so we may leak memory.
438 EXPECT_FALSE(cf->tmp.is_alloced());
439
440 delete f_to->table;
441 delete f_from->table;
442 }
443
444
445 /*
446 Tests that make_sort_key() is well behaved and does not cause buffer
447 overruns nor writes a too short key. We stop at the first error seen.
448
449 - field - The field whose make_sort_key() method we test.
450
451 - from - A buffer of size field->pack_length() that we will trick
452 the field into using as its record buffer.
453
454 - expected - A buffer of size field->pack_length() + 1, the first n
455 bytes of which make_sort_key() is expected to fill out. The n + 1:th
456 byte is expected to be untouched. We try all possible values of n.
457
458 - min_key_length - Some Field classes assert on a certain minimum
459 key length. To avoid that, pass the minimum length here.
460 */
test_make_sort_key(Field * field,uchar * from,const uchar * expected,int min_key_length)461 void test_make_sort_key(Field *field, uchar *from, const uchar *expected,
462 int min_key_length)
463 {
464 const uint pack_length= field->pack_length();
465 Fake_TABLE table(field);
466 table.s->db_low_byte_first= false;
467 field->ptr= from;
468
469 for (uint key_length= min_key_length; key_length <= pack_length; ++key_length)
470 {
471 uchar buff[MAX_FIELD_WIDTH + 1];
472 memset(buff, 'a', pack_length + 1);
473 field->make_sort_key(buff, key_length);
474
475 // Check for a too short key.
476 for (uint i= 0; i < key_length; ++i)
477 ASSERT_FALSE(buff[i] == 'a')
478 << "Too few bytes written at " << i
479 << " with buffer size " << key_length << ".";
480
481 // Check for wrong result
482 for (uint i= 0; i < key_length; ++i)
483 ASSERT_EQ(expected[i], buff[i])
484 << "Wrong output at " << i
485 << " with buffer size " << key_length
486 << " and pack length " << pack_length << ".";
487
488 EXPECT_EQ('a', buff[key_length])
489 << "Buffer overrun" << " with buffer size " << key_length << ".";
490 }
491
492 // Try key_length == pack_length
493 uchar buff[MAX_FIELD_WIDTH];
494 memset(buff, 'a', pack_length + 1);
495 field->make_sort_key(buff, pack_length);
496 EXPECT_EQ('a', buff[pack_length]) << "Buffer overrun";
497 }
498
499
500 // Convenience function for large values.
test_make_sort_key(Field * field)501 void test_make_sort_key(Field *field)
502 {
503 const int pack_length= field->pack_length();
504
505 uchar from[MAX_FIELD_WIDTH];
506 memset(from, 'b', pack_length);
507
508 uchar to[MAX_FIELD_WIDTH + 1];
509 memset(to, 'b', pack_length + 1);
510
511 test_make_sort_key(field, from, to, 1);
512 }
513
514
515 extern "C"
516 {
517 static size_t mock_strnxfrm(const CHARSET_INFO *, uchar *, size_t,
518 uint, const uchar *, size_t, uint);
519 }
520
521 class Mock_collation : public MY_COLLATION_HANDLER
522 {
523 public:
Mock_collation()524 Mock_collation() { strnxfrm= mock_strnxfrm; }
525 };
526
527
528 class Mock_charset : public CHARSET_INFO
529 {
530 Mock_collation mock_collation;
531 public:
532 mutable bool strnxfrm_called;
Mock_charset()533 Mock_charset() { strnxfrm_called= false; coll= &mock_collation; mbmaxlen= 1; }
~Mock_charset()534 ~Mock_charset() { EXPECT_TRUE(strnxfrm_called); }
535 };
536
537
mock_strnxfrm(const CHARSET_INFO * charset,uchar *,size_t dstlen,uint,const uchar *,size_t,uint)538 size_t mock_strnxfrm(const CHARSET_INFO *charset, uchar *, size_t dstlen, uint,
539 const uchar *, size_t, uint)
540 {
541 // CHARSET_INFO is not polymorphic, hence the abomination.
542 static_cast<const Mock_charset*>(charset)->strnxfrm_called= true;
543 return dstlen;
544 };
545
546
test_integer_field(Field * field)547 void test_integer_field(Field *field)
548 {
549 uchar from[MAX_FIELD_WIDTH], expected[MAX_FIELD_WIDTH];
550 const int pack_length= field->pack_length();
551 for (int i= 0; i < pack_length; ++i)
552 {
553 from[i]= '0' + i;
554 #ifdef WORDS_BIGENDIAN
555 expected[i]= '0' + i;
556 #else
557 expected[pack_length - 1 - i]= '0' + i;
558 #endif
559 }
560 test_make_sort_key(field, from, expected, pack_length);
561 }
562
563 // Tests all make_sort_key() implementations.
564
565 // We keep the same order of classes here as in field.h in order to make it
566 // easy to manually verify that all field types have been tested.
567
TEST_F(FieldTest,MakeSortKey)568 TEST_F(FieldTest, MakeSortKey)
569 {
570 {
571 SCOPED_TRACE("Field_decimal");
572 Field_decimal fd(NULL, 64, NULL, '\0', Field::NONE, "", 0, false, false);
573 test_make_sort_key(&fd);
574 }
575 {
576 SCOPED_TRACE("Field_new_decimal");
577 Field_new_decimal fnd(64, true, "", 0, false);
578 test_make_sort_key(&fnd);
579 }
580 {
581 SCOPED_TRACE("Field_tiny");
582 Field_tiny ft(NULL, 0, NULL, '\0', Field::NONE, "", false, true);
583 test_make_sort_key(&ft);
584 }
585 {
586 SCOPED_TRACE("Field_short");
587 Field_short fs(0,false, "", true);
588 test_integer_field(&fs);
589 }
590 {
591 SCOPED_TRACE("Field_long");
592 Field_long fl(0,false, "", true);
593 test_integer_field(&fl);
594 }
595 {
596 SCOPED_TRACE("Field_longlong");
597 Field_longlong fll(NULL, 64, NULL, '\0', Field::NONE, "", 0, true);
598 test_integer_field(&fll);
599 }
600 {
601 SCOPED_TRACE("Field_float");
602 Field_float ff(NULL, 0, NULL, '\0', Field::NONE, "", 0, false, false);
603 float from= 0.0;
604 uchar to []= { 128, 0, 0, 0 };
605 test_make_sort_key(&ff, reinterpret_cast<uchar*>(&from), to, 4);
606 }
607 {
608 SCOPED_TRACE("Field_double");
609 Field_double fd(NULL, 0, NULL, '\0', Field::NONE, "", 0, false, false);
610 double from= 0.0;
611 uchar expected []= { 128, 0, 0, 0, 0, 0, 0, 0 };
612 test_make_sort_key(&fd, reinterpret_cast<uchar*>(&from), expected, 1);
613 }
614 {
615 SCOPED_TRACE("Field_null");
616 CHARSET_INFO cs;
617 cs.state= MY_CHARSET_UNDEFINED; // Avoid valgrind warning.
618 Field_null fn(NULL, 0, Field::NONE, "", &cs);
619 test_make_sort_key(&fn);
620 }
621 {
622 SCOPED_TRACE("Field_timestamp");
623 Field_timestamp fts(false, "");
624 test_integer_field(&fts);
625 }
626 {
627 SCOPED_TRACE("Field_timestampf");
628 Field_timestampf
629 ftsf(NULL, NULL, 0, Field::NONE, "", DATETIME_MAX_DECIMALS);
630 test_make_sort_key(&ftsf);
631 }
632 {
633 SCOPED_TRACE("field_newdate");
634 Field_newdate fnd(false, "");
635 uchar from []= { '3', '2', '1' };
636 uchar expected []= { '1', '2', '3' };
637 test_make_sort_key(&fnd, from, expected, 3);
638 }
639 {
640 SCOPED_TRACE("Field_time");
641 Field_time ft(false, "");
642 uchar from []= { 3, 2, 1 };
643 uchar expected []= { 129, 2, 3 };
644 test_make_sort_key(&ft, from, expected, 3);
645 }
646 {
647 SCOPED_TRACE("Field_timef");
648 Field_timef ftf(false, "", 0);
649 test_make_sort_key(&ftf);
650 }
651 {
652 SCOPED_TRACE("Field_datetime");
653 Field_datetime fdt(NULL, NULL, '\0', Field::NONE, NULL);
654 test_integer_field(&fdt);
655 }
656 {
657 SCOPED_TRACE("Field_string");
658 Mock_charset mock_charset;
659 Field_string fs(NULL, 0, NULL, '\0', Field::NONE, "", &mock_charset);
660 uchar to;
661 fs.make_sort_key(&to, 666);
662 }
663 {
664 SCOPED_TRACE("Field_varstring");
665 Mock_charset mock_charset;
666 Fake_TABLE_SHARE fake_share(0);
667 uchar ptr[8]= {0, 0, 0, 0, 0, 0, 0, 0};
668 Field_varstring fvs(ptr, 0, 0, NULL, '\0', Field::NONE, "", &fake_share,
669 &mock_charset);
670 uchar to;
671 fvs.make_sort_key(&to, 666);
672 }
673 {
674 SCOPED_TRACE("Field_blob");
675 CHARSET_INFO cs;
676 cs.state= MY_CHARSET_UNDEFINED; // Avoid valgrind warning.
677 Field_blob fb(0, false, "", &cs, false);
678 }
679 {
680 SCOPED_TRACE("Field_enum");
681 for (int pack_length= 1; pack_length <= 8; ++pack_length)
682 for (int key_length= 1; key_length <= 8; ++key_length)
683 {
684 Field_enum fe(NULL, 0, NULL, '\0', Field::NONE, "", pack_length, NULL,
685 &my_charset_bin);
686 uchar from []= { '1', '2', '3', '4', '5', '6', '7', '8' };
687 uchar expected []=
688 #ifdef WORDS_BIGENDIAN
689 { '1', '2', '3', '4', '5', '6', '7', '8' };
690 test_make_sort_key(&fe, from, expected, key_length);
691 #else
692 { '8', '7', '6', '5', '4', '3', '2', '1' };
693 test_make_sort_key(&fe, from, expected + 8 - pack_length, key_length);
694 #endif
695 }
696 }
697 {
698 SCOPED_TRACE("Field_bit");
699 Field_bit fb(NULL, 0, NULL, '\0', NULL, '\0', Field::NONE, "");
700 }
701 }
702
703
testCopyInteger(bool is_big_endian,bool is_unsigned)704 void testCopyInteger(bool is_big_endian, bool is_unsigned)
705 {
706 const uchar from_template[]= { '1', '2', '3', '4', '5', '6', '7', '8' },
707 expected_for_big_endian[]= { '1', '2', '3', '4', '5', '6', '7', '8' },
708 expected_for_little_endian[]= { '8', '7', '6', '5', '4', '3', '2', '1' };
709
710 const size_t max_length= sizeof(from_template);
711 for (uint from_length= 1; from_length < max_length; ++from_length)
712 for (uint to_length= 1; to_length <= from_length; ++to_length)
713 {
714 uchar to[]= { '0', '0', '0', '0', '0', '0', '0', '0', '0' };
715 uchar from[max_length];
716 memcpy(from, from_template, max_length);
717
718 if (is_big_endian)
719 copy_integer<true>(to, to_length, from, from_length, is_unsigned);
720 else
721 copy_integer<false>(to, to_length, from, from_length, is_unsigned);
722
723 EXPECT_EQ('0', to[to_length])
724 << "Buffer overrun @ position " << to_length << ".";
725
726 ASSERT_EQ(is_unsigned ? 0 : 128, to[0] & 128)
727 << "Sign bit should" << (is_unsigned ? " not" : "") << " be flipped";
728
729 const uchar *expected=
730 is_big_endian ? expected_for_big_endian :
731 expected_for_little_endian + max_length - from_length;
732
733 for (uint i= 1; i < to_length; ++i)
734 {
735 ASSERT_FALSE(to[i] == '\0')
736 << "Too few bytes written @ position " << i
737 << " when copying a size " << from_length << " integer into a size "
738 << to_length << " integer.";
739
740 ASSERT_EQ(expected[i], to[i])
741 << "Result differs at position " << i
742 << " when copying a size " << from_length << " integer into a size "
743 << to_length << " integer.";
744 }
745 }
746 }
747
748
749 // Test of the copy_integer<>() function.
TEST_F(FieldTest,copyInteger)750 TEST_F(FieldTest, copyInteger)
751 {
752 {
753 SCOPED_TRACE("Big endian unsigned");
754 testCopyInteger(true, true);
755 }
756 {
757 SCOPED_TRACE("Big endian signed");
758 testCopyInteger(true, false);
759 }
760 {
761 SCOPED_TRACE("Little endian unsigned");
762 testCopyInteger(false, true);
763 }
764 {
765 SCOPED_TRACE("Little endian signed");
766 testCopyInteger(false, false);
767 }
768 }
769
770
771 }
772
773 #include "field_date-t.cc"
774 #include "field_datetime-t.cc"
775 #include "field_long-t.cc"
776 #include "field_newdecimal-t.cc"
777 #include "field_timestamp-t.cc"
778