Commit b5fae7f7 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-20795 CAST(inet6 AS BINARY) returns wrong result

parent d04f2de8
......@@ -720,6 +720,99 @@ t1 CREATE TABLE `t1` (
`a` varchar(39) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a INET6);
INSERT INTO t1 VALUES ('ffff::ffff');
CREATE TABLE t2 AS SELECT
CAST(a AS CHAR),
CAST(a AS CHAR(39)),
CAST(a AS CHAR(530)),
CAST(a AS CHAR(65535)),
CAST(a AS CHAR(66000)),
CAST(a AS CHAR(16777215)),
CAST(a AS CHAR(16777216))
FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`CAST(a AS CHAR)` varchar(39) DEFAULT NULL,
`CAST(a AS CHAR(39))` varchar(39) DEFAULT NULL,
`CAST(a AS CHAR(530))` text DEFAULT NULL,
`CAST(a AS CHAR(65535))` text DEFAULT NULL,
`CAST(a AS CHAR(66000))` mediumtext DEFAULT NULL,
`CAST(a AS CHAR(16777215))` mediumtext DEFAULT NULL,
`CAST(a AS CHAR(16777216))` longtext DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT * FROM t2;
CAST(a AS CHAR) ffff::ffff
CAST(a AS CHAR(39)) ffff::ffff
CAST(a AS CHAR(530)) ffff::ffff
CAST(a AS CHAR(65535)) ffff::ffff
CAST(a AS CHAR(66000)) ffff::ffff
CAST(a AS CHAR(16777215)) ffff::ffff
CAST(a AS CHAR(16777216)) ffff::ffff
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (a INET6);
INSERT INTO t1 VALUES ('ffff::ffff');
CREATE TABLE t2 AS SELECT
CAST(a AS BINARY(4)) AS cb4,
CAST(a AS BINARY) AS cb,
CAST(a AS BINARY(16)) AS cb16,
CAST(a AS BINARY(32)) AS cb32,
CAST(a AS BINARY(530)) AS cb530,
CAST(a AS BINARY(65535)) AS cb65535,
CAST(a AS BINARY(66000)) AS cb66000,
CAST(a AS BINARY(16777215)) AS cb16777215,
CAST(a AS BINARY(16777216)) AS cb16777216
FROM t1 LIMIT 0;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`cb4` binary(4) DEFAULT NULL,
`cb` binary(16) DEFAULT NULL,
`cb16` binary(16) DEFAULT NULL,
`cb32` binary(32) DEFAULT NULL,
`cb530` varbinary(530) DEFAULT NULL,
`cb65535` blob DEFAULT NULL,
`cb66000` mediumblob DEFAULT NULL,
`cb16777215` mediumblob DEFAULT NULL,
`cb16777216` longblob DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
CREATE TABLE t2 AS SELECT
CAST(a AS BINARY(4)) AS cb4,
CAST(a AS BINARY) AS cb,
CAST(a AS BINARY(16)) AS cb16,
CAST(a AS BINARY(32)) AS cb32,
CAST(a AS BINARY(530)) AS cb530,
CAST(a AS BINARY(65535)) AS cb65535
FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`cb4` binary(4) DEFAULT NULL,
`cb` binary(16) DEFAULT NULL,
`cb16` binary(16) DEFAULT NULL,
`cb32` binary(32) DEFAULT NULL,
`cb530` varbinary(530) DEFAULT NULL,
`cb65535` blob DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT
HEX(cb4),
HEX(cb),
HEX(cb16),
HEX(cb32),
LENGTH(cb530),
LENGTH(cb65535)
FROM t2;
HEX(cb4) FFFF0000
HEX(cb) FFFF000000000000000000000000FFFF
HEX(cb16) FFFF000000000000000000000000FFFF
HEX(cb32) FFFF000000000000000000000000FFFF00000000000000000000000000000000
LENGTH(cb530) 530
LENGTH(cb65535) 65535
DROP TABLE t2;
DROP TABLE t1;
#
# Implicit conversion to other types in INSERT
#
......@@ -1516,3 +1609,15 @@ SELECT HEX(a) FROM t1;
HEX(a)
20010DB8000000000000FF0000428329
DROP TABLE t1;
#
# MDEV-20795 CAST(inet6 AS BINARY) returns wrong result
#
CREATE OR REPLACE TABLE t1 (a INET6);
INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
SELECT HEX(CAST(a AS BINARY)) FROM t1;
HEX(CAST(a AS BINARY))
20010DB8000000000000FF0000428329
SELECT HEX(CAST(a AS BINARY(16))) FROM t1;
HEX(CAST(a AS BINARY(16)))
20010DB8000000000000FF0000428329
DROP TABLE t1;
......@@ -383,6 +383,61 @@ CREATE TABLE t1 AS SELECT CAST(CAST('::' AS INET6) AS CHAR) AS a;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a INET6);
INSERT INTO t1 VALUES ('ffff::ffff');
CREATE TABLE t2 AS SELECT
CAST(a AS CHAR),
CAST(a AS CHAR(39)),
CAST(a AS CHAR(530)),
CAST(a AS CHAR(65535)),
CAST(a AS CHAR(66000)),
CAST(a AS CHAR(16777215)),
CAST(a AS CHAR(16777216))
FROM t1;
SHOW CREATE TABLE t2;
--vertical_results
SELECT * FROM t2;
--horizontal_results
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (a INET6);
INSERT INTO t1 VALUES ('ffff::ffff');
CREATE TABLE t2 AS SELECT
CAST(a AS BINARY(4)) AS cb4,
CAST(a AS BINARY) AS cb,
CAST(a AS BINARY(16)) AS cb16,
CAST(a AS BINARY(32)) AS cb32,
CAST(a AS BINARY(530)) AS cb530,
CAST(a AS BINARY(65535)) AS cb65535,
CAST(a AS BINARY(66000)) AS cb66000,
CAST(a AS BINARY(16777215)) AS cb16777215,
CAST(a AS BINARY(16777216)) AS cb16777216
FROM t1 LIMIT 0;
SHOW CREATE TABLE t2;
DROP TABLE t2;
CREATE TABLE t2 AS SELECT
CAST(a AS BINARY(4)) AS cb4,
CAST(a AS BINARY) AS cb,
CAST(a AS BINARY(16)) AS cb16,
CAST(a AS BINARY(32)) AS cb32,
CAST(a AS BINARY(530)) AS cb530,
CAST(a AS BINARY(65535)) AS cb65535
FROM t1;
SHOW CREATE TABLE t2;
--vertical_results
SELECT
HEX(cb4),
HEX(cb),
HEX(cb16),
HEX(cb32),
LENGTH(cb530),
LENGTH(cb65535)
FROM t2;
--horizontal_results
DROP TABLE t2;
DROP TABLE t1;
--echo #
--echo # Implicit conversion to other types in INSERT
......@@ -1049,3 +1104,13 @@ INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
ALTER TABLE t1 MODIFY a BINARY(16);
SELECT HEX(a) FROM t1;
DROP TABLE t1;
--echo #
--echo # MDEV-20795 CAST(inet6 AS BINARY) returns wrong result
--echo #
CREATE OR REPLACE TABLE t1 (a INET6);
INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
SELECT HEX(CAST(a AS BINARY)) FROM t1;
SELECT HEX(CAST(a AS BINARY(16))) FROM t1;
DROP TABLE t1;
......@@ -1216,6 +1216,54 @@ class in_inet6 :public in_vector
};
class Item_char_typecast_func_handler_inet6_to_binary:
public Item_handled_func::Handler_str
{
public:
const Type_handler *return_type_handler() const override
{
return &type_handler_string;
}
const Type_handler *
type_handler_for_create_select(const Item_handled_func *item) const
{
if (item->max_length > MAX_FIELD_VARCHARLENGTH)
return Type_handler::blob_type_handler(item->max_length);
if (item->max_length > 255)
return &type_handler_varchar;
return &type_handler_string;
}
bool fix_length_and_dec(Item_handled_func *xitem) const override
{
return false;
}
String *val_str(Item_handled_func *item, String *to) const override
{
DBUG_ASSERT(dynamic_cast<const Item_char_typecast*>(item));
return static_cast<Item_char_typecast*>(item)->
val_str_binary_from_native(to);
}
};
static const Item_char_typecast_func_handler_inet6_to_binary
item_char_typecast_func_handler_inet6_to_binary;
bool Type_handler_inet6::
Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
{
if (item->cast_charset() == &my_charset_bin)
{
item->fix_length_and_dec_native_to_binary(Inet6::binary_length());
item->set_func_handler(&item_char_typecast_func_handler_inet6_to_binary);
return false;
}
item->fix_length_and_dec_str();
return false;
}
bool
Type_handler_inet6::character_or_binary_string_to_native(THD *thd,
const String *str,
......
......@@ -930,11 +930,7 @@ class Type_handler_inet6: public Type_handler
}
bool
Item_char_typecast_fix_length_and_dec(Item_char_typecast *item)
const override
{
item->fix_length_and_dec_str();
return false;
}
const override;
bool
Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const override
{
......
......@@ -467,9 +467,46 @@ class Item_handled_func: public Item_func
virtual my_decimal *val_decimal(Item_handled_func *, my_decimal *) const= 0;
virtual bool get_date(THD *thd, Item_handled_func *, MYSQL_TIME *, date_mode_t fuzzydate) const= 0;
virtual const Type_handler *return_type_handler() const= 0;
virtual const Type_handler *
type_handler_for_create_select(const Item_handled_func *item) const
{
return return_type_handler();
}
virtual bool fix_length_and_dec(Item_handled_func *) const= 0;
};
class Handler_str: public Handler
{
public:
String *val_str_ascii(Item_handled_func *item, String *str) const
{
return item->Item::val_str_ascii(str);
}
double val_real(Item_handled_func *item) const
{
DBUG_ASSERT(item->is_fixed());
StringBuffer<64> tmp;
String *res= item->val_str(&tmp);
return res ? item->double_from_string_with_check(res) : 0.0;
}
longlong val_int(Item_handled_func *item) const
{
DBUG_ASSERT(item->is_fixed());
StringBuffer<22> tmp;
String *res= item->val_str(&tmp);
return res ? item->longlong_from_string_with_check(res) : 0;
}
my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const
{
return item->val_decimal_from_string(to);
}
bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to,
date_mode_t fuzzydate) const
{
return item->get_date_from_string(thd, to, fuzzydate);
}
};
/**
Abstract class for functions returning TIME, DATE, DATETIME or string values,
whose data type depends on parameters and is set at fix_fields time.
......@@ -496,6 +533,11 @@ class Item_handled_func: public Item_func
{
return &type_handler_string;
}
const Type_handler *
type_handler_for_create_select(const Item_handled_func *item) const
{
return return_type_handler()->type_handler_for_tmp_table(item);
}
double val_real(Item_handled_func *item) const
{
return Temporal_hybrid(item).to_double();
......@@ -613,6 +655,14 @@ class Item_handled_func: public Item_func
{
return m_func_handler->return_type_handler();
}
Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
{
DBUG_ASSERT(fixed);
const Type_handler *h= m_func_handler->type_handler_for_create_select(this);
return h->make_and_init_table_field(root, &name,
Record_addr(maybe_null),
*this, table);
}
String *val_str(String *to)
{
return m_func_handler->val_str(this, to);
......
......@@ -2326,7 +2326,7 @@ uint Item_char_typecast::adjusted_length_with_warn(uint length)
}
String *Item_char_typecast::val_str(String *str)
String *Item_char_typecast::val_str_generic(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res;
......@@ -2382,11 +2382,75 @@ String *Item_char_typecast::val_str(String *str)
}
String *Item_char_typecast::val_str_binary_from_native(String *str)
{
DBUG_ASSERT(fixed == 1);
DBUG_ASSERT(cast_cs == &my_charset_bin);
NativeBuffer<STRING_BUFFER_USUAL_SIZE> native;
if (args[0]->val_native(current_thd, &native))
{
null_value= 1;
return 0;
}
if (has_explicit_length())
{
cast_length= adjusted_length_with_warn(cast_length);
if (cast_length > native.length())
{
// add trailing 0x00s
DBUG_ASSERT(cast_length <= current_thd->variables.max_allowed_packet);
str->alloc(cast_length);
str->copy(native.ptr(), native.length(), &my_charset_bin);
bzero((char*) str->end(), cast_length - str->length());
str->length(cast_length);
}
else
str->copy(native.ptr(), cast_length, &my_charset_bin);
}
else
str->copy(native.ptr(), native.length(), &my_charset_bin);
return ((null_value= (str->length() >
adjusted_length_with_warn(str->length())))) ? 0 : str;
}
class Item_char_typecast_func_handler: public Item_handled_func::Handler_str
{
public:
const Type_handler *return_type_handler() const
{
return &type_handler_varchar;
}
const Type_handler *
type_handler_for_create_select(const Item_handled_func *item) const
{
return return_type_handler()->type_handler_for_tmp_table(item);
}
bool fix_length_and_dec(Item_handled_func *item) const
{
return false;
}
String *val_str(Item_handled_func *item, String *to) const
{
DBUG_ASSERT(dynamic_cast<const Item_char_typecast*>(item));
return static_cast<Item_char_typecast*>(item)->val_str_generic(to);
}
};
static const Item_char_typecast_func_handler item_char_typecast_func_handler;
void Item_char_typecast::fix_length_and_dec_numeric()
{
fix_length_and_dec_internal(from_cs= cast_cs->mbminlen == 1 ?
cast_cs :
&my_charset_latin1);
set_func_handler(&item_char_typecast_func_handler);
}
......@@ -2395,6 +2459,24 @@ void Item_char_typecast::fix_length_and_dec_generic()
fix_length_and_dec_internal(from_cs= args[0]->dynamic_result() ?
0 :
args[0]->collation.collation);
set_func_handler(&item_char_typecast_func_handler);
}
void Item_char_typecast::fix_length_and_dec_str()
{
fix_length_and_dec_generic();
m_suppress_warning_to_error_escalation= true;
set_func_handler(&item_char_typecast_func_handler);
}
void
Item_char_typecast::fix_length_and_dec_native_to_binary(uint32 octet_length)
{
collation.set(&my_charset_bin, DERIVATION_IMPLICIT);
max_length= has_explicit_length() ? (uint32) cast_length : octet_length;
maybe_null|= current_thd->is_strict_mode();
}
......@@ -2438,6 +2520,8 @@ void Item_char_typecast::fix_length_and_dec_internal(CHARSET_INFO *from_cs)
(cast_cs == &my_charset_bin ? 1 :
args[0]->collation.collation->mbmaxlen));
max_length= char_length * cast_cs->mbmaxlen;
// Add NULL-ability in strict mode. See Item_str_func::fix_fields()
maybe_null= maybe_null || current_thd->is_strict_mode();
}
......
......@@ -1074,14 +1074,16 @@ class Item_extract :public Item_int_func,
};
class Item_char_typecast :public Item_str_func
class Item_char_typecast :public Item_handled_func
{
uint cast_length;
CHARSET_INFO *cast_cs, *from_cs;
bool charset_conversion;
String tmp_value;
bool m_suppress_warning_to_error_escalation;
public:
bool has_explicit_length() const { return cast_length != ~0U; }
private:
String *reuse(String *src, size_t length);
String *copy(String *src, CHARSET_INFO *cs);
uint adjusted_length_with_warn(uint length);
......@@ -1092,20 +1094,18 @@ class Item_char_typecast :public Item_str_func
uint get_cast_length() const { return cast_length; }
public:
Item_char_typecast(THD *thd, Item *a, uint length_arg, CHARSET_INFO *cs_arg):
Item_str_func(thd, a), cast_length(length_arg), cast_cs(cs_arg),
Item_handled_func(thd, a), cast_length(length_arg), cast_cs(cs_arg),
m_suppress_warning_to_error_escalation(false) {}
enum Functype functype() const { return CHAR_TYPECAST_FUNC; }
bool eq(const Item *item, bool binary_cmp) const;
const char *func_name() const { return "cast_as_char"; }
CHARSET_INFO *cast_charset() const { return cast_cs; }
String *val_str(String *a);
String *val_str_generic(String *a);
String *val_str_binary_from_native(String *a);
void fix_length_and_dec_generic();
void fix_length_and_dec_numeric();
void fix_length_and_dec_str()
{
fix_length_and_dec_generic();
m_suppress_warning_to_error_escalation= true;
}
void fix_length_and_dec_str();
void fix_length_and_dec_native_to_binary(uint32 octet_length);
bool fix_length_and_dec()
{
return args[0]->type_handler()->Item_char_typecast_fix_length_and_dec(this);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment