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(&times[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