899 lines
30 KiB
C++

/* 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 <gtest/gtest.h>
#include <gmock/gmock.h>
#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<ulong>(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_int*>(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());
}
}
}