/* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ // First include (the generated) my_config.h, to get correct platform defines. #include "my_config.h" #include #include #include "test_utils.h" #include "item.h" #include "item_cmpfunc.h" #include "item_create.h" #include "item_strfunc.h" #include "item_timefunc.h" #include "sql_class.h" #include "tztime.h" #include "fake_table.h" #include "mock_field_timestamp.h" namespace item_unittest { using my_testing::Server_initializer; using my_testing::Mock_error_handler; using ::testing::Return; class ItemTest : public ::testing::Test { protected: virtual void SetUp() { initializer.SetUp(); } virtual void TearDown() { initializer.TearDown(); } THD *thd() { return initializer.thd(); } Server_initializer initializer; }; /** This is a simple mock Field class, illustrating how to set expectations on type_conversion_status Field_long::store(longlong nr, bool unsigned_val); */ class Mock_field_long : public Field_long { public: Mock_field_long(uint32 lenght) : Field_long(0, // ptr_arg lenght, // len_arg NULL, // null_ptr_arg 0, // null_bit_arg Field::NONE, // unireg_check_arg 0, // field_name_arg false, // zero_arg false) // unsigned_arg {} // Avoid warning about hiding other overloaded versions of store(). using Field_long::store; /* This is the only member function we need to override. Note: Sun Studio needs a little help in resolving longlong. */ MOCK_METHOD2(store, type_conversion_status(::longlong nr, bool unsigned_val)); }; /** Mock class for CHAR field. */ class Mock_field_string : public Field_string { private: Fake_TABLE *m_fake_tbl; public: Mock_field_string(uint32 length, const CHARSET_INFO *cs= &my_charset_latin1) : Field_string(0, // ptr_arg length, // len_arg NULL, // null_ptr_arg 0, // null_bit_arg Field::NONE, // unireg_check_arg NULL, // field_name_arg cs) // char set { m_fake_tbl= new Fake_TABLE(this); // Allocate place for storing the field value ptr= new uchar[length]; // Make it possible to write into this field bitmap_set_bit(m_fake_tbl->write_set, 0); /* count_cuted_fields must be set in order for producing warning/error for Item_string::save_in_field(). */ m_fake_tbl->in_use->count_cuted_fields= CHECK_FIELD_WARN; } ~Mock_field_string() { delete [] ptr; ptr= NULL; delete m_fake_tbl; m_fake_tbl= NULL; } }; /** Mock class for VARCHAR field. */ class Mock_field_varstring : public Field_varstring { private: Fake_TABLE *m_fake_tbl; public: Mock_field_varstring(uint32 length, TABLE_SHARE *share, const CHARSET_INFO *cs= &my_charset_latin1) : Field_varstring(length, // len_arg false, // maybe_null_arg NULL, // field_name_arg share, // share cs) // char set { m_fake_tbl= new Fake_TABLE(this); // Allocate place for storing the field value ptr= new uchar[length + 1]; // Make it possible to write into this field bitmap_set_bit(m_fake_tbl->write_set, 0); /* count_cuted_fields must be set in order for producing warning/error for Item_string::save_in_field(). */ m_fake_tbl->in_use->count_cuted_fields= CHECK_FIELD_WARN; } ~Mock_field_varstring() { delete [] ptr; ptr= NULL; delete m_fake_tbl; m_fake_tbl= NULL; } }; TEST_F(ItemTest, ItemInt) { const int32 val= 42; char stringbuf[10]; (void) my_snprintf(stringbuf, sizeof(stringbuf), "%d", val); // An Item expects to be owned by current_thd->free_list, // so allocate with new, and do not delete it. Item_int *item_int= new Item_int(val); EXPECT_EQ(Item::INT_ITEM, item_int->type()); EXPECT_EQ(INT_RESULT, item_int->result_type()); EXPECT_EQ(MYSQL_TYPE_LONGLONG, item_int->field_type()); EXPECT_EQ(val, item_int->val_int()); EXPECT_DOUBLE_EQ((double) val, item_int->val_real()); EXPECT_TRUE(item_int->basic_const_item()); my_decimal decimal_val; EXPECT_EQ(&decimal_val, item_int->val_decimal(&decimal_val)); String string_val; EXPECT_EQ(&string_val, item_int->val_str(&string_val)); EXPECT_STREQ(stringbuf, string_val.c_ptr_safe()); Mock_field_long field_val(item_int->max_length); // We expect to be called with arguments(nr == val, unsigned_val == false) EXPECT_CALL(field_val, store(val, false)) .Times(1) .WillRepeatedly(Return(TYPE_OK)); EXPECT_EQ(TYPE_OK, item_int->save_in_field(&field_val, true)); Item *clone= item_int->clone_item(); EXPECT_TRUE(item_int->eq(clone, true)); EXPECT_TRUE(item_int->eq(item_int, true)); String print_val; item_int->print(&print_val, QT_ORDINARY); EXPECT_STREQ(stringbuf, print_val.c_ptr_safe()); const uint precision= item_int->decimal_precision(); EXPECT_EQ(MY_INT32_NUM_DECIMAL_DIGITS, precision); item_int->neg(); EXPECT_EQ(-val, item_int->val_int()); EXPECT_EQ(precision - 1, item_int->decimal_precision()); // Functions inherited from parent class(es). const table_map tmap= 0; EXPECT_EQ(tmap, item_int->used_tables()); /* TODO: There are about 100 member functions in Item. Figure out which ones are relevant for unit testing here. */ } TEST_F(ItemTest, ItemString) { const char short_str[]= "abc"; const char long_str[]= "abcd"; const char space_str[]= "abc "; const char bad_char[]= "𝌆abc"; const char bad_char_end[]= "abc𝌆"; Item_string *item_short_string= new Item_string(STRING_WITH_LEN(short_str), &my_charset_latin1); Item_string *item_long_string= new Item_string(STRING_WITH_LEN(long_str), &my_charset_latin1); Item_string *item_space_string= new Item_string(STRING_WITH_LEN(space_str), &my_charset_latin1); Item_string *item_bad_char= new Item_string(STRING_WITH_LEN(bad_char), &my_charset_bin); Item_string *item_bad_char_end= new Item_string(STRING_WITH_LEN(bad_char_end), &my_charset_bin); /* Bug 16407965 ITEM::SAVE_IN_FIELD_NO_WARNING() DOES NOT RETURN CORRECT CONVERSION STATUS */ // Create a CHAR field that can store short_str but not long_str Mock_field_string field_string(3); EXPECT_EQ(MYSQL_TYPE_STRING, field_string.type()); // CHAR field for testing strings with illegal values Mock_field_string field_string_utf8(20, &my_charset_utf8_general_ci); EXPECT_EQ(MYSQL_TYPE_STRING, field_string_utf8.type()); /* Tests of Item_string::save_in_field() when storing into a CHAR field. */ EXPECT_EQ(TYPE_OK, item_short_string->save_in_field(&field_string, true)); EXPECT_EQ(TYPE_WARN_TRUNCATED, item_long_string->save_in_field(&field_string, true)); // Field_string does not consider trailing spaces when truncating a string EXPECT_EQ(TYPE_OK, item_space_string->save_in_field(&field_string, true)); // When the first character invalid, the whole string is truncated. EXPECT_EQ(TYPE_WARN_INVALID_STRING, item_bad_char->save_in_field(&field_string_utf8, true)); // If the string contains an invalid character, the entire string is invalid EXPECT_EQ(TYPE_WARN_INVALID_STRING, item_bad_char_end->save_in_field(&field_string_utf8, true)); /* Tests of Item_string::save_in_field_no_warnings() when storing into a CHAR field. */ EXPECT_EQ(TYPE_OK, item_short_string->save_in_field_no_warnings(&field_string, true)); EXPECT_EQ(TYPE_WARN_TRUNCATED, item_long_string->save_in_field_no_warnings(&field_string, true)); // Field_string does not consider trailing spaces when truncating a string EXPECT_EQ(TYPE_OK, item_space_string->save_in_field_no_warnings(&field_string, true)); EXPECT_EQ(TYPE_WARN_INVALID_STRING, item_bad_char->save_in_field_no_warnings(&field_string_utf8, true)); // If the string contains an invalid character, the entire string is invalid EXPECT_EQ(TYPE_WARN_INVALID_STRING, item_bad_char_end->save_in_field_no_warnings(&field_string_utf8, true)); /* Create a VARCHAR field that can store short_str but not long_str. Need a table share object since the constructor for Field_varstring updates its table share. */ TABLE_SHARE table_share; Mock_field_varstring field_varstring(3, &table_share); EXPECT_EQ(MYSQL_TYPE_VARCHAR, field_varstring.type()); // VARCHAR field for testing strings with illegal values Mock_field_varstring field_varstring_utf8(20, &table_share, &my_charset_utf8_general_ci); EXPECT_EQ(MYSQL_TYPE_VARCHAR, field_varstring_utf8.type()); /* Tests of Item_string::save_in_field() when storing into a VARCHAR field. */ EXPECT_EQ(TYPE_OK, item_short_string->save_in_field(&field_varstring, true)); EXPECT_EQ(TYPE_WARN_TRUNCATED, item_long_string->save_in_field(&field_varstring, true)); // Field_varstring produces a note when truncating a string with // trailing spaces EXPECT_EQ(TYPE_NOTE_TRUNCATED, item_space_string->save_in_field(&field_varstring, true)); // When the first character invalid, the whole string is truncated. EXPECT_EQ(TYPE_WARN_INVALID_STRING, item_bad_char->save_in_field(&field_varstring_utf8, true)); // If the string contains an invalid character, the entire string is invalid EXPECT_EQ(TYPE_WARN_INVALID_STRING, item_bad_char_end->save_in_field(&field_varstring_utf8, true)); /* Tests of Item_string::save_in_field_no_warnings() when storing into a VARCHAR field. */ EXPECT_EQ(TYPE_OK, item_short_string->save_in_field_no_warnings(&field_varstring, true)); EXPECT_EQ(TYPE_WARN_TRUNCATED, item_long_string->save_in_field_no_warnings(&field_varstring, true)); // Field_varstring produces a note when truncating a string with // trailing spaces EXPECT_EQ(TYPE_NOTE_TRUNCATED, item_space_string->save_in_field_no_warnings(&field_varstring, true)); EXPECT_EQ(TYPE_WARN_INVALID_STRING, item_bad_char->save_in_field_no_warnings(&field_varstring_utf8, true)); // If the string contains an invalid character, the entire string is invalid EXPECT_EQ(TYPE_WARN_INVALID_STRING, item_bad_char_end->save_in_field_no_warnings(&field_varstring_utf8, true)); } TEST_F(ItemTest, ItemEqual) { // Bug#13720201 VALGRIND: VARIOUS BLOCKS OF BYTES DEFINITELY LOST Mock_field_timestamp mft; mft.table->const_table= true; mft.make_readable(); // foo is longer than STRING_BUFFER_USUAL_SIZE used by cmp_item_sort_string. const char foo[]= "0123456789012345678901234567890123456789" "0123456789012345678901234567890123456789" "0123456789012345678901234567890123456789"; Item_equal *item_equal= new Item_equal(new Item_string(STRING_WITH_LEN(foo), &my_charset_bin), new Item_field(&mft)); EXPECT_FALSE(item_equal->fix_fields(thd(), NULL)); EXPECT_EQ(1, item_equal->val_int()); } TEST_F(ItemTest, ItemFuncDesDecrypt) { // Bug #59632 Assertion failed: arg_length > length const uint length= 1U; Item_int *item_one= new Item_int(1, length); Item_int *item_two= new Item_int(2, length); Item *item_decrypt= new Item_func_des_decrypt(POS(), item_two, item_one); Parse_context pc(thd(), thd()->lex->current_select()); EXPECT_FALSE(item_decrypt->itemize(&pc, &item_decrypt)); EXPECT_FALSE(item_decrypt->fix_fields(thd(), NULL)); EXPECT_EQ(length, item_one->max_length); EXPECT_EQ(length, item_two->max_length); EXPECT_LE(item_decrypt->max_length, length); } TEST_F(ItemTest, ItemFuncExportSet) { String str; Item *on_string= new Item_string(STRING_WITH_LEN("on"), &my_charset_bin); Item *off_string= new Item_string(STRING_WITH_LEN("off"), &my_charset_bin); Item *sep_string= new Item_string(STRING_WITH_LEN(","), &my_charset_bin); { // Testing basic functionality. Item *export_set= new Item_func_export_set(POS(), new Item_int(2), on_string, off_string, sep_string, new Item_int(4)); Parse_context pc(thd(), thd()->lex->current_select()); EXPECT_FALSE(export_set->itemize(&pc, &export_set)); EXPECT_FALSE(export_set->fix_fields(thd(), NULL)); EXPECT_EQ(&str, export_set->val_str(&str)); EXPECT_STREQ("off,on,off,off", str.c_ptr_safe()); } { // Testing corner case: number_of_bits == zero. Item *export_set= new Item_func_export_set(POS(), new Item_int(2), on_string, off_string, sep_string, new Item_int(0)); Parse_context pc(thd(), thd()->lex->current_select()); EXPECT_FALSE(export_set->itemize(&pc, &export_set)); EXPECT_FALSE(export_set->fix_fields(thd(), NULL)); EXPECT_EQ(&str, export_set->val_str(&str)); EXPECT_STREQ("", str.c_ptr_safe()); } /* Bug#11765562 58545: EXPORT_SET() CAN BE USED TO MAKE ENTIRE SERVER COMPLETELY UNRESPONSIVE */ const ulong max_size= 1024; const ulonglong repeat= max_size / 2; Item *item_int_repeat= new Item_int(repeat); Item *string_x= new Item_string(STRING_WITH_LEN("x"), &my_charset_bin); String * const null_string= NULL; thd()->variables.max_allowed_packet= max_size; { // Testing overflow caused by 'on-string'. Mock_error_handler error_handler(thd(), ER_WARN_ALLOWED_PACKET_OVERFLOWED); Item *export_set= new Item_func_export_set(POS(), new Item_int(0xff), new Item_func_repeat(POS(), string_x, item_int_repeat), string_x, sep_string); Parse_context pc(thd(), thd()->lex->current_select()); SCOPED_TRACE(""); EXPECT_FALSE(export_set->itemize(&pc, &export_set)); EXPECT_FALSE(export_set->fix_fields(thd(), NULL)); EXPECT_EQ(null_string, export_set->val_str(&str)); EXPECT_STREQ("", str.c_ptr_safe()); EXPECT_EQ(1, error_handler.handle_called()); } { // Testing overflow caused by 'off-string'. Mock_error_handler error_handler(thd(), ER_WARN_ALLOWED_PACKET_OVERFLOWED); Item *export_set= new Item_func_export_set(POS(), new Item_int(0xff), string_x, new Item_func_repeat(POS(), string_x, item_int_repeat), sep_string); Parse_context pc(thd(), thd()->lex->current_select()); SCOPED_TRACE(""); EXPECT_FALSE(export_set->itemize(&pc, &export_set)); EXPECT_FALSE(export_set->fix_fields(thd(), NULL)); EXPECT_EQ(null_string, export_set->val_str(&str)); EXPECT_STREQ("", str.c_ptr_safe()); EXPECT_EQ(1, error_handler.handle_called()); } { // Testing overflow caused by 'separator-string'. Mock_error_handler error_handler(thd(), ER_WARN_ALLOWED_PACKET_OVERFLOWED); Item *export_set= new Item_func_export_set(POS(), new Item_int(0xff), string_x, string_x, new Item_func_repeat(POS(), string_x, item_int_repeat)); Parse_context pc(thd(), thd()->lex->current_select()); SCOPED_TRACE(""); EXPECT_FALSE(export_set->itemize(&pc, &export_set)); EXPECT_FALSE(export_set->fix_fields(thd(), NULL)); EXPECT_EQ(null_string, export_set->val_str(&str)); EXPECT_STREQ("", str.c_ptr_safe()); EXPECT_EQ(1, error_handler.handle_called()); } { // Testing overflow caused by 'on-string'. longlong max_size= 1024LL; thd()->variables.max_allowed_packet= static_cast(max_size); Mock_error_handler error_handler(thd(), ER_WARN_ALLOWED_PACKET_OVERFLOWED); Item *lpad= new Item_func_lpad(POS(), new Item_string(STRING_WITH_LEN("a"), &my_charset_bin), new Item_int(max_size), new Item_string(STRING_WITH_LEN("pppppppppppppppp" "pppppppppppppppp"), &my_charset_bin) ); Item *export_set= new Item_func_export_set(POS(), new Item_string(STRING_WITH_LEN("1111111"), &my_charset_bin), lpad, new Item_int(1)); Parse_context pc(thd(), thd()->lex->current_select()); SCOPED_TRACE(""); EXPECT_FALSE(export_set->itemize(&pc, &export_set)); EXPECT_FALSE(export_set->fix_fields(thd(), NULL)); EXPECT_EQ(null_string, export_set->val_str(&str)); EXPECT_STREQ("", str.c_ptr_safe()); EXPECT_EQ(1, error_handler.handle_called()); } } TEST_F(ItemTest, ItemFuncIntDivOverflow) { const char dividend_str[]= "99999999999999999999999999999999999999999" "99999999999999999999999999999999999999999"; const char divisor_str[]= "0.5"; Item_float *dividend= new Item_float(dividend_str, sizeof(dividend_str)); Item_float *divisor= new Item_float(divisor_str, sizeof(divisor_str)); Item_func_int_div* quotient= new Item_func_int_div(dividend, divisor); Mock_error_handler error_handler(thd(), ER_TRUNCATED_WRONG_VALUE); EXPECT_FALSE(quotient->fix_fields(thd(), NULL)); initializer.set_expected_error(ER_DATA_OUT_OF_RANGE); quotient->val_int(); } TEST_F(ItemTest, ItemFuncIntDivUnderflow) { // Bug #11792200 - DIVIDING LARGE NUMBERS CAUSES STACK CORRUPTIONS const char dividend_str[]= "1.175494351E-37"; const char divisor_str[]= "1.7976931348623157E+308"; Item_float *dividend= new Item_float(dividend_str, sizeof(dividend_str)); Item_float *divisor= new Item_float(divisor_str, sizeof(divisor_str)); Item_func_int_div* quotient= new Item_func_int_div(dividend, divisor); Mock_error_handler error_handler(thd(), ER_TRUNCATED_WRONG_VALUE); EXPECT_FALSE(quotient->fix_fields(thd(), NULL)); EXPECT_EQ(0, quotient->val_int()); } TEST_F(ItemTest, ItemFuncNegLongLongMin) { // Bug#14314156 MAIN.FUNC_MATH TEST FAILS ON MYSQL-TRUNK ON PB2 const longlong longlong_min= LLONG_MIN; Item_func_neg *item_neg= new Item_func_neg(new Item_int(longlong_min)); EXPECT_FALSE(item_neg->fix_fields(thd(), NULL)); initializer.set_expected_error(ER_DATA_OUT_OF_RANGE); EXPECT_EQ(0, item_neg->int_op()); } /* This is not an exhaustive test. It simply demonstrates that more of the initializations in mysqld.cc are needed for testing Item_xxx classes. */ TEST_F(ItemTest, ItemFuncSetUserVar) { const longlong val1= 1; Item_decimal *item_dec= new Item_decimal(val1, false); Item_string *item_str= new Item_string("1", 1, &my_charset_latin1); LEX_STRING var_name= { C_STRING_WITH_LEN("a") }; Item_func_set_user_var *user_var= new Item_func_set_user_var(var_name, item_str, false); EXPECT_FALSE(user_var->set_entry(thd(), true)); EXPECT_FALSE(user_var->fix_fields(thd(), NULL)); EXPECT_EQ(val1, user_var->val_int()); my_decimal decimal; my_decimal *decval_1= user_var->val_decimal(&decimal); user_var->save_item_result(item_str); my_decimal *decval_2= user_var->val_decimal(&decimal); user_var->save_item_result(item_dec); EXPECT_EQ(decval_1, decval_2); EXPECT_EQ(decval_1, &decimal); } // Test of Item::operator new() when we simulate out-of-memory. TEST_F(ItemTest, OutOfMemory) { Item_int *null_item= NULL; Item_int *item= new Item_int(42); EXPECT_NE(null_item, item); delete null_item; #if !defined(DBUG_OFF) // Setting debug flags triggers enter/exit trace, so redirect to /dev/null. DBUG_SET("o," IF_WIN("NUL", "/dev/null")); DBUG_SET("+d,simulate_out_of_memory"); item= new Item_int(42); EXPECT_EQ(null_item, item); DBUG_SET("+d,simulate_out_of_memory"); item= new (thd()->mem_root) Item_int(42); EXPECT_EQ(null_item, item); #endif } // We never use dynamic_cast, but we expect it to work. TEST_F(ItemTest, DynamicCast) { Item *item= new Item_int(42); const Item_int *null_item= NULL; EXPECT_NE(null_item, dynamic_cast(item)); } TEST_F(ItemTest, ItemFuncXor) { const uint length= 1U; Item_int *item_zero= new Item_int(0, length); Item_int *item_one_a= new Item_int(1, length); Item_func_xor *item_xor= new Item_func_xor(item_zero, item_one_a); EXPECT_FALSE(item_xor->fix_fields(thd(), NULL)); EXPECT_EQ(1, item_xor->val_int()); EXPECT_EQ(1U, item_xor->decimal_precision()); Item_int *item_one_b= new Item_int(1, length); Item_func_xor *item_xor_same= new Item_func_xor(item_one_a, item_one_b); EXPECT_FALSE(item_xor_same->fix_fields(thd(), NULL)); EXPECT_EQ(0, item_xor_same->val_int()); EXPECT_FALSE(item_xor_same->val_bool()); EXPECT_FALSE(item_xor_same->is_null()); String print_buffer; item_xor->print(&print_buffer, QT_ORDINARY); EXPECT_STREQ("(0 xor 1)", print_buffer.c_ptr_safe()); Item *neg_xor= item_xor->neg_transformer(thd()); EXPECT_FALSE(neg_xor->fix_fields(thd(), NULL)); EXPECT_EQ(0, neg_xor->val_int()); EXPECT_DOUBLE_EQ(0.0, neg_xor->val_real()); EXPECT_FALSE(neg_xor->val_bool()); EXPECT_FALSE(neg_xor->is_null()); print_buffer= String(); neg_xor->print(&print_buffer, QT_ORDINARY); EXPECT_STREQ("((not(0)) xor 1)", print_buffer.c_ptr_safe()); Item_func_xor *item_xor_null= new Item_func_xor(item_zero, new Item_null()); EXPECT_FALSE(item_xor_null->fix_fields(thd(), NULL)); EXPECT_EQ(0, item_xor_null->val_int()); EXPECT_TRUE(item_xor_null->is_null()); } /* Testing MYSQL_TIME_cache. */ TEST_F(ItemTest, MysqlTimeCache) { String str_buff, *str; MYSQL_TIME datetime6= { 2011, 11, 7, 10, 20, 30, 123456, 0, MYSQL_TIMESTAMP_DATETIME }; MYSQL_TIME time6= { 0, 0, 0, 10, 20, 30, 123456, 0, MYSQL_TIMESTAMP_TIME }; struct timeval tv6= {1320661230, 123456}; const MYSQL_TIME *ltime; MYSQL_TIME_cache cache; /* Testing DATETIME(6). Initializing from MYSQL_TIME. */ cache.set_datetime(&datetime6, 6); EXPECT_EQ(1840440237558456896LL, cache.val_packed()); EXPECT_EQ(6, cache.decimals()); // Call val_str() then cptr() str= cache.val_str(&str_buff); EXPECT_STREQ("2011-11-07 10:20:30.123456", str->c_ptr_safe()); EXPECT_STREQ("2011-11-07 10:20:30.123456", cache.cptr()); cache.set_datetime(&datetime6, 6); // Now call the other way around: cptr() then val_str() EXPECT_STREQ("2011-11-07 10:20:30.123456", cache.cptr()); EXPECT_STREQ("2011-11-07 10:20:30.123456", str->c_ptr_safe()); // Testing get_TIME_ptr() ltime= cache.get_TIME_ptr(); EXPECT_EQ(ltime->year, datetime6.year); EXPECT_EQ(ltime->month, datetime6.month); EXPECT_EQ(ltime->day, datetime6.day); EXPECT_EQ(ltime->hour, datetime6.hour); EXPECT_EQ(ltime->minute, datetime6.minute); EXPECT_EQ(ltime->second, datetime6.second); EXPECT_EQ(ltime->second_part, datetime6.second_part); EXPECT_EQ(ltime->neg, datetime6.neg); EXPECT_EQ(ltime->time_type, datetime6.time_type); // Testing eq() { MYSQL_TIME datetime6_2= datetime6; MYSQL_TIME_cache cache2; datetime6_2.second_part+= 1; cache2.set_datetime(&datetime6_2, 6); EXPECT_EQ(cache.eq(cache), true); EXPECT_EQ(cache.eq(cache2), false); EXPECT_EQ(cache2.eq(cache2), true); EXPECT_EQ(cache2.eq(cache), false); } /* Testing DATETIME(6). Initializing from "struct timeval". */ cache.set_datetime(tv6, 6, my_tz_UTC); EXPECT_EQ(1840440237558456896LL, cache.val_packed()); EXPECT_EQ(6, cache.decimals()); str= cache.val_str(&str_buff); EXPECT_STREQ("2011-11-07 10:20:30.123456", str->c_ptr_safe()); EXPECT_STREQ("2011-11-07 10:20:30.123456", cache.cptr()); /* Testing TIME(6). Initializing from MYSQL_TIME. */ cache.set_time(&time6, 6); EXPECT_EQ(709173043776LL, cache.val_packed()); EXPECT_EQ(6, cache.decimals()); // Call val_str() then cptr() str= cache.val_str(&str_buff); EXPECT_STREQ("10:20:30.123456", str->c_ptr_safe()); EXPECT_STREQ("10:20:30.123456", cache.cptr()); /* Testing TIME(6). Initializing from "struct timeval". */ cache.set_time(tv6, 6, my_tz_UTC); EXPECT_EQ(709173043776LL, cache.val_packed()); EXPECT_EQ(6, cache.decimals()); str= cache.val_str(&str_buff); EXPECT_STREQ("10:20:30.123456", str->c_ptr_safe()); EXPECT_STREQ("10:20:30.123456", cache.cptr()); /* Testing DATETIME(5) */ MYSQL_TIME datetime5= { 2011, 11, 7, 10, 20, 30, 123450, 0, MYSQL_TIMESTAMP_DATETIME }; cache.set_datetime(&datetime5, 5); EXPECT_EQ(1840440237558456890LL, cache.val_packed()); EXPECT_EQ(5, cache.decimals()); /* Call val_str() then cptr() */ str= cache.val_str(&str_buff); EXPECT_STREQ("2011-11-07 10:20:30.12345", str->c_ptr_safe()); EXPECT_STREQ("2011-11-07 10:20:30.12345", cache.cptr()); cache.set_datetime(&datetime5, 5); /* Now call the other way around: cptr() then val_str() */ EXPECT_STREQ("2011-11-07 10:20:30.12345", cache.cptr()); EXPECT_STREQ("2011-11-07 10:20:30.12345", str->c_ptr_safe()); /* Testing DATE. Initializing from MYSQL_TIME. */ MYSQL_TIME date= { 2011, 11, 7, 0, 0, 0, 0, 0, MYSQL_TIMESTAMP_DATE }; cache.set_date(&date); EXPECT_EQ(1840439528385413120LL, cache.val_packed()); EXPECT_EQ(0, cache.decimals()); str= cache.val_str(&str_buff); EXPECT_STREQ("2011-11-07", str->c_ptr_safe()); EXPECT_STREQ("2011-11-07", cache.cptr()); /* Testing DATE. Initializing from "struct tm". */ cache.set_date(tv6, my_tz_UTC); EXPECT_EQ(1840439528385413120LL, cache.val_packed()); EXPECT_EQ(0, cache.decimals()); str= cache.val_str(&str_buff); EXPECT_STREQ("2011-11-07", str->c_ptr_safe()); EXPECT_STREQ("2011-11-07", cache.cptr()); } extern "C" { // Verifies that Item_func_conv::val_str does not call my_strntoll() longlong fail_strntoll(const struct charset_info_st *, const char *s, size_t l, int base, char **e, int *err) { ADD_FAILURE() << "Unexpected call"; return 0; } } class Mock_charset : public CHARSET_INFO { public: Mock_charset(const CHARSET_INFO &csi) { CHARSET_INFO *this_as_cset= this; *this_as_cset= csi; number= 666; m_cset_handler= *(csi.cset); m_cset_handler.strntoll= fail_strntoll; cset= &m_cset_handler; } private: MY_CHARSET_HANDLER m_cset_handler; }; TEST_F(ItemTest, ItemFuncConvIntMin) { Mock_charset charset(*system_charset_info); SCOPED_TRACE(""); Item *item_conv= new Item_func_conv(POS(), new Item_string("5", 1, &charset), new Item_int(INT_MIN), // from_base new Item_int(INT_MIN)); // to_base Parse_context pc(thd(), thd()->lex->current_select()); EXPECT_FALSE(item_conv->itemize(&pc, &item_conv)); EXPECT_FALSE(item_conv->fix_fields(thd(), NULL)); const String *null_string= NULL; String str; EXPECT_EQ(null_string, item_conv->val_str(&str)); } TEST_F(ItemTest, ItemDecimalTypecast) { const char msg[]= ""; POS pos; pos.cpp.start= pos.cpp.end= pos.raw.start= pos.raw.end= msg; // Sun Studio needs this null_item, // it fails to compile EXPECT_EQ(NULL, create_func_cast()); const Item *null_item= NULL; Cast_type type; type.target= ITEM_CAST_DECIMAL; type.length= "123456789012345678901234567890"; type.dec= NULL; { initializer.set_expected_error(ER_TOO_BIG_PRECISION); EXPECT_EQ(null_item, create_func_cast(thd(), pos, NULL, &type)); } { char buff[20]; my_snprintf(buff, sizeof(buff) - 1, "%d", DECIMAL_MAX_PRECISION + 1); type.length= buff; type.dec= NULL; initializer.set_expected_error(ER_TOO_BIG_PRECISION); EXPECT_EQ(null_item, create_func_cast(thd(), pos, NULL, &type)); } { type.length= NULL; type.dec= "123456789012345678901234567890"; initializer.set_expected_error(ER_TOO_BIG_SCALE); EXPECT_EQ(null_item, create_func_cast(thd(), pos, NULL, &type)); } { char buff[20]; my_snprintf(buff, sizeof(buff) - 1, "%d", DECIMAL_MAX_SCALE + 1); type.length= buff; type.dec= buff; initializer.set_expected_error(ER_TOO_BIG_SCALE); EXPECT_EQ(null_item, create_func_cast(thd(), pos, NULL, &type)); } } TEST_F(ItemTest, NormalizedPrint) { Item_null *item_null= new Item_null; { String s; item_null->print(&s, QT_ORDINARY); EXPECT_STREQ("NULL", s.c_ptr()); } { String s; item_null->print(&s, QT_NORMALIZED_FORMAT); EXPECT_STREQ("?", s.c_ptr()); } } }