Skip to content

Commit 5ad67c6

Browse files
author
Alexander Barkov
committed
A clean up patch for WL#946:
- Removing Item_typecast, as it's not needed any more. Before WL#946 it was a common parent for Item_char_typecast, Item_date_typecast, Item_time_typecast and Item_datetime_typecast. Now casts to the temporal types descend from the corresponding Item_{date|time|datetime}_func. Making Item_char_typecast descend from Item_str_func directly - Moving Item_char_typecast from item_timefunc.cc and item_timefunc.h to item_strfunc.cc and item_strfunc.h (finally!!!). These methods have been moved AS IS (cut and paste): Item_char_typecast::eq() Item_char_typecast::print() Item_char_typecast::val_str() The method Item_char_typecast::fix_length_and_dec() has had some slight changes: a. in how "from_cs" variable is initialized. Now we check args[0]->collation.repertoire instead of args[0]->result_type(). This helps to avoid character set conversion in more cases. b. in how max_length is calculated. Instead of direct access to max_length, now we use methods max_char_length() and fix_char_length() introduced by WL#2649 Number-to-string conversions. - Fixing that Item_sp_varianble and Item_named_const did not initialize their collation.repertoire properly (only collation.collation and collation.derivation were initialized). This flaws were found by adding this code into Item_char_typecast::fix_length_and_dec() temporary and running mtr: if (args[0]->result_type() == INT_RESULT || args[0]->result_type() == DECIMAL_RESULT || args[0]->result_type() == REAL_RESULT) { DBUG_ASSERT(args[0]->collation.collation == &my_charset_numeric); DBUG_ASSERT(args[0]->collation.repertoire == MY_REPERTOIRE_ASCII); } - Recording ctype_cp1251.result and ctype_utf8.result, caused by initializing Item_sp_variable::collation.repertoire properly.
1 parent c99bbb7 commit 5ad67c6

7 files changed

Lines changed: 178 additions & 220 deletions

File tree

mysql-test/r/ctype_cp1251.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3245,7 +3245,7 @@ Note 1003 /* select#1 */ select (v_LastPaymentDate@0 < now()) AS `v_LastPaymentD
32453245
id select_type table type possible_keys key key_len ref rows filtered Extra
32463246
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
32473247
Warnings:
3248-
Note 1003 /* select#1 */ select concat(convert(v_LastPaymentDate@0 using cp1251),now()) AS `CONCAT(v_LastPaymentDate, NOW())`
3248+
Note 1003 /* select#1 */ select concat(v_LastPaymentDate@0,now()) AS `CONCAT(v_LastPaymentDate, NOW())`
32493249
DROP PROCEDURE p1;
32503250
#
32513251
# Bug#52159 returning time type from function and empty left join causes debug assertion

mysql-test/r/ctype_utf8.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5099,7 +5099,7 @@ Note 1003 /* select#1 */ select (v_LastPaymentDate@0 < now()) AS `v_LastPaymentD
50995099
id select_type table type possible_keys key key_len ref rows filtered Extra
51005100
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
51015101
Warnings:
5102-
Note 1003 /* select#1 */ select concat(convert(v_LastPaymentDate@0 using utf8),now()) AS `CONCAT(v_LastPaymentDate, NOW())`
5102+
Note 1003 /* select#1 */ select concat(v_LastPaymentDate@0,now()) AS `CONCAT(v_LastPaymentDate, NOW())`
51035103
DROP PROCEDURE p1;
51045104
#
51055105
# Bug#52159 returning time type from function and empty left join causes debug assertion

sql/item.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,7 +1521,7 @@ bool Item_sp_variable::fix_fields(THD *thd, Item **)
15211521
decimals= it->decimals;
15221522
unsigned_flag= it->unsigned_flag;
15231523
fixed= 1;
1524-
collation.set(it->collation.collation, it->collation.derivation);
1524+
collation.set(it->collation);
15251525

15261526
return FALSE;
15271527
}
@@ -1866,7 +1866,8 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref)
18661866
{
18671867
set_name(item_name->ptr(), (uint) item_name->length(), system_charset_info);
18681868
}
1869-
collation.set(value_item->collation.collation, DERIVATION_IMPLICIT);
1869+
collation.set(value_item->collation.collation, DERIVATION_IMPLICIT,
1870+
value_item->collation.repertoire);
18701871
max_length= value_item->max_length;
18711872
decimals= value_item->decimals;
18721873
fixed= 1;

sql/item_strfunc.cc

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3470,6 +3470,161 @@ String *Item_func_like_range::val_str(String *str)
34703470
#endif
34713471

34723472

3473+
bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const
3474+
{
3475+
if (this == item)
3476+
return 1;
3477+
if (item->type() != FUNC_ITEM ||
3478+
functype() != ((Item_func*)item)->functype())
3479+
return 0;
3480+
3481+
Item_char_typecast *cast= (Item_char_typecast*)item;
3482+
if (cast_length != cast->cast_length ||
3483+
cast_cs != cast->cast_cs)
3484+
return 0;
3485+
3486+
if (!args[0]->eq(cast->args[0], binary_cmp))
3487+
return 0;
3488+
return 1;
3489+
}
3490+
3491+
3492+
void Item_char_typecast::print(String *str, enum_query_type query_type)
3493+
{
3494+
str->append(STRING_WITH_LEN("cast("));
3495+
args[0]->print(str, query_type);
3496+
str->append(STRING_WITH_LEN(" as char"));
3497+
if (cast_length >= 0)
3498+
str->append_parenthesized(cast_length);
3499+
if (cast_cs)
3500+
{
3501+
str->append(STRING_WITH_LEN(" charset "));
3502+
str->append(cast_cs->csname);
3503+
}
3504+
str->append(')');
3505+
}
3506+
3507+
3508+
String *Item_char_typecast::val_str(String *str)
3509+
{
3510+
DBUG_ASSERT(fixed == 1);
3511+
String *res;
3512+
uint32 length;
3513+
3514+
if (cast_length >= 0 &&
3515+
((unsigned) cast_length) > current_thd->variables.max_allowed_packet)
3516+
{
3517+
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
3518+
ER_WARN_ALLOWED_PACKET_OVERFLOWED,
3519+
ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED),
3520+
cast_cs == &my_charset_bin ?
3521+
"cast_as_binary" : func_name(),
3522+
current_thd->variables.max_allowed_packet);
3523+
null_value= 1;
3524+
return 0;
3525+
}
3526+
3527+
if (!charset_conversion)
3528+
{
3529+
if (!(res= args[0]->val_str(str)))
3530+
{
3531+
null_value= 1;
3532+
return 0;
3533+
}
3534+
}
3535+
else
3536+
{
3537+
// Convert character set if differ
3538+
uint dummy_errors;
3539+
if (!(res= args[0]->val_str(str)) ||
3540+
tmp_value.copy(res->ptr(), res->length(), from_cs,
3541+
cast_cs, &dummy_errors))
3542+
{
3543+
null_value= 1;
3544+
return 0;
3545+
}
3546+
res= &tmp_value;
3547+
}
3548+
3549+
res->set_charset(cast_cs);
3550+
3551+
/*
3552+
Cut the tail if cast with length
3553+
and the result is longer than cast length, e.g.
3554+
CAST('string' AS CHAR(1))
3555+
*/
3556+
if (cast_length >= 0)
3557+
{
3558+
if (res->length() > (length= (uint32) res->charpos(cast_length)))
3559+
{ // Safe even if const arg
3560+
char char_type[40];
3561+
my_snprintf(char_type, sizeof(char_type), "%s(%lu)",
3562+
cast_cs == &my_charset_bin ? "BINARY" : "CHAR",
3563+
(ulong) length);
3564+
3565+
if (!res->alloced_length())
3566+
{ // Don't change const str
3567+
str_value= *res; // Not malloced string
3568+
res= &str_value;
3569+
}
3570+
ErrConvString err(res);
3571+
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
3572+
ER_TRUNCATED_WRONG_VALUE,
3573+
ER(ER_TRUNCATED_WRONG_VALUE), char_type,
3574+
err.ptr());
3575+
res->length((uint) length);
3576+
}
3577+
else if (cast_cs == &my_charset_bin && res->length() < (uint) cast_length)
3578+
{
3579+
if (res->alloced_length() < (uint) cast_length)
3580+
{
3581+
str_value.alloc(cast_length);
3582+
str_value.copy(*res);
3583+
res= &str_value;
3584+
}
3585+
memset(const_cast<char*>(res->ptr() + res->length()), 0,
3586+
cast_length - res->length());
3587+
res->length(cast_length);
3588+
}
3589+
}
3590+
null_value= 0;
3591+
return res;
3592+
}
3593+
3594+
3595+
void Item_char_typecast::fix_length_and_dec()
3596+
{
3597+
/*
3598+
If we convert between two ASCII compatible character sets and the
3599+
argument repertoire is MY_REPERTOIRE_ASCII then from_cs is set to cast_cs.
3600+
This allows just to take over the args[0]->val_str() result
3601+
and thus avoid unnecessary character set conversion.
3602+
*/
3603+
from_cs= args[0]->collation.repertoire == MY_REPERTOIRE_ASCII &&
3604+
my_charset_is_ascii_based(cast_cs) &&
3605+
my_charset_is_ascii_based(args[0]->collation.collation) ?
3606+
cast_cs : args[0]->collation.collation;
3607+
3608+
3609+
collation.set(cast_cs, DERIVATION_IMPLICIT);
3610+
fix_char_length(cast_length >= 0 ? cast_length :
3611+
cast_cs == &my_charset_bin ? args[0]->max_length :
3612+
args[0]->max_char_length());
3613+
3614+
/*
3615+
We always force character set conversion if cast_cs
3616+
is a multi-byte character set. It garantees that the
3617+
result of CAST is a well-formed string.
3618+
For single-byte character sets we allow just to copy from the argument.
3619+
A single-byte character sets string is always well-formed.
3620+
*/
3621+
charset_conversion= (cast_cs->mbmaxlen > 1) ||
3622+
(!my_charset_same(from_cs, cast_cs) &&
3623+
from_cs != &my_charset_bin &&
3624+
cast_cs != &my_charset_bin);
3625+
}
3626+
3627+
34733628
void Item_func_binary::print(String *str, enum_query_type query_type)
34743629
{
34753630
str->append(STRING_WITH_LEN("cast("));

sql/item_strfunc.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,24 @@ class Item_func_like_range_max :public Item_func_like_range
751751
#endif
752752

753753

754+
class Item_char_typecast :public Item_str_func
755+
{
756+
int cast_length;
757+
const CHARSET_INFO *cast_cs, *from_cs;
758+
bool charset_conversion;
759+
String tmp_value;
760+
public:
761+
Item_char_typecast(Item *a, int length_arg, const CHARSET_INFO *cs_arg)
762+
:Item_str_func(a), cast_length(length_arg), cast_cs(cs_arg) {}
763+
enum Functype functype() const { return CHAR_TYPECAST_FUNC; }
764+
bool eq(const Item *item, bool binary_cmp) const;
765+
const char *func_name() const { return "cast_as_char"; }
766+
String *val_str(String *a);
767+
void fix_length_and_dec();
768+
virtual void print(String *str, enum_query_type query_type);
769+
};
770+
771+
754772
class Item_func_binary :public Item_str_func
755773
{
756774
public:

0 commit comments

Comments
 (0)