MDEV-20806 Federated does not work with INET6, returns NULL with warning ER_TRUNCATED_WRONG_VALUE

This commit is contained in:
Alexander Barkov 2019-10-11 23:16:01 +04:00
parent a0d3a351b8
commit 530f3f7cfc
9 changed files with 118 additions and 34 deletions

View File

@ -0,0 +1,24 @@
connect master,127.0.0.1,root,,test,$MASTER_MYPORT,;
connect slave,127.0.0.1,root,,test,$SLAVE_MYPORT,;
connection master;
CREATE DATABASE federated;
connection slave;
CREATE DATABASE federated;
#
# MDEV-20806 Federated does not work with INET6, returns NULL with warning ER_TRUNCATED_WRONG_VALUE
#
connection master;
CREATE TABLE t1 (a INET6);
INSERT INTO t1 VALUES ('::'),('f::f');
CREATE TABLE t2 (a INET6) ENGINE=Federated CONNECTION='mysql://root@127.0.0.1:MASTER_PORT/test/t1';
SELECT * FROM t2;
a
::
f::f
DROP TABLE t1, t2;
connection master;
DROP TABLE IF EXISTS federated.t1;
DROP DATABASE IF EXISTS federated;
connection slave;
DROP TABLE IF EXISTS federated.t1;
DROP DATABASE IF EXISTS federated;

View File

@ -0,0 +1,17 @@
source include/federated.inc;
--echo #
--echo # MDEV-20806 Federated does not work with INET6, returns NULL with warning ER_TRUNCATED_WRONG_VALUE
--echo #
connection master;
CREATE TABLE t1 (a INET6);
INSERT INTO t1 VALUES ('::'),('f::f');
--replace_result $MASTER_MYPORT MASTER_PORT
eval CREATE TABLE t2 (a INET6) ENGINE=Federated CONNECTION='mysql://root@127.0.0.1:$MASTER_MYPORT/test/t1';
SELECT * FROM t2;
DROP TABLE t1, t2;
source include/federated_cleanup.inc;

View File

@ -631,6 +631,16 @@ class Field_inet6: public Field
set_max_value((char*) ptr);
return 1;
}
int store_inet6_null_with_warn(const Inet6_null &inet6,
const ErrConvString &err)
{
DBUG_ASSERT(marked_for_write_or_computed());
if (inet6.is_null())
return maybe_null() ? set_null_with_warn(err) :
set_min_value_with_warn(err);
inet6.to_binary((char *) ptr, Inet6::binary_length());
return 0;
}
public:
Field_inet6(const LEX_CSTRING *field_name_arg, const Record_addr &rec)
@ -749,23 +759,26 @@ public:
int store(const char *str, size_t length, CHARSET_INFO *cs) override
{
DBUG_ASSERT(marked_for_write_or_computed());
Inet6_null tmp= cs == &my_charset_bin ?
Inet6_null(str, length) :
Inet6_null(str, length, cs);
if (tmp.is_null())
{
return maybe_null() ?
set_null_with_warn(ErrConvString(str, length, cs)) :
set_min_value_with_warn(ErrConvString(str, length, cs));
}
tmp.to_binary((char *) ptr, Inet6::binary_length());
return 0;
return cs == &my_charset_bin ? store_binary(str, length) :
store_text(str, length, cs);
}
int store_text(const char *str, size_t length, CHARSET_INFO *cs) override
{
return store_inet6_null_with_warn(Inet6_null(str, length, cs),
ErrConvString(str, length, cs));
}
int store_binary(const char *str, size_t length) override
{
return store_inet6_null_with_warn(Inet6_null(str, length),
ErrConvString(str, length,
&my_charset_bin));
}
int store_hex_hybrid(const char *str, size_t length) override
{
return store(str, length, &my_charset_bin);
return Field_inet6::store_binary(str, length);
}
int store_decimal(const my_decimal *num) override

View File

@ -1887,13 +1887,16 @@ bool Field::compatible_field_size(uint field_metadata,
int Field::store(const char *to, size_t length, CHARSET_INFO *cs,
enum_check_fields check_level)
{
int res;
THD *thd= get_thd();
enum_check_fields old_check_level= thd->count_cuted_fields;
thd->count_cuted_fields= check_level;
res= store(to, length, cs);
thd->count_cuted_fields= old_check_level;
return res;
Check_level_instant_set tmp_level(get_thd(), check_level);
return store(to, length, cs);
}
int Field::store_text(const char *to, size_t length, CHARSET_INFO *cs,
enum_check_fields check_level)
{
Check_level_instant_set tmp_level(get_thd(), check_level);
return store_text(to, length, cs);
}

View File

@ -916,6 +916,23 @@ public:
reset();
}
virtual int store(const char *to, size_t length,CHARSET_INFO *cs)=0;
/*
This is used by engines like CSV and Federated to signal the field
that the data is going to be in text (rather than binary) representation,
even if cs points to &my_charset_bin.
If a Field distinguishes between text and binary formats (e.g. INET6),
we cannot call store(str,length,&my_charset_bin),
to avoid "field" mis-interpreting the data format as binary.
*/
virtual int store_text(const char *to, size_t length, CHARSET_INFO *cs)
{
return store(to, length, cs);
}
virtual int store_binary(const char *to, size_t length)
{
return store(to, length, &my_charset_bin);
}
virtual int store_hex_hybrid(const char *str, size_t length);
virtual int store(double nr)=0;
virtual int store(longlong nr, bool unsigned_val)=0;
@ -940,6 +957,8 @@ public:
{ return store_time_dec(ltime, TIME_SECOND_PART_DIGITS); }
int store(const char *to, size_t length, CHARSET_INFO *cs,
enum_check_fields check_level);
int store_text(const char *to, size_t length, CHARSET_INFO *cs,
enum_check_fields check_level);
int store(const LEX_STRING *ls, CHARSET_INFO *cs)
{
DBUG_ASSERT(ls->length < UINT_MAX32);

View File

@ -6884,6 +6884,23 @@ public:
};
class Check_level_instant_set
{
THD *m_thd;
enum_check_fields m_check_level;
public:
Check_level_instant_set(THD *thd, enum_check_fields temporary_value)
:m_thd(thd), m_check_level(thd->count_cuted_fields)
{
thd->count_cuted_fields= temporary_value;
}
~Check_level_instant_set()
{
m_thd->count_cuted_fields= m_check_level;
}
};
/**
This class resembles the SQL Standard schema qualified object name:
<schema qualified name> ::= [ <schema name> <period> ] <qualified identifier>

View File

@ -820,16 +820,6 @@ int ha_tina::find_current_row(uchar *buf)
if (read_all || bitmap_is_set(table->read_set, (*field)->field_index))
{
bool is_enum= ((*field)->real_type() == MYSQL_TYPE_ENUM);
/*
If "field" distinguishes between text and binary formats (e.g. INET6),
we cannot pass buffer.char() (which is &my_charset_bin) to store(),
to avoid "field" mis-interpreting the data format as binary.
Let's pass my_charset_latin1 to tell the field that we're storing
in text format.
*/
CHARSET_INFO *storecs=
(*field)->type_handler()->convert_to_binary_using_val_native() ?
&my_charset_latin1 : buffer.charset();
/*
Here CHECK_FIELD_WARN checks that all values in the csv file are valid
which is normally the case, if they were written by
@ -838,8 +828,8 @@ int ha_tina::find_current_row(uchar *buf)
Thus, for enums we silence the warning, as it doesn't really mean
an invalid value.
*/
if ((*field)->store(buffer.ptr(), buffer.length(), storecs,
is_enum ? CHECK_FIELD_IGNORE : CHECK_FIELD_WARN))
if ((*field)->store_text(buffer.ptr(), buffer.length(), buffer.charset(),
is_enum ? CHECK_FIELD_IGNORE : CHECK_FIELD_WARN))
{
if (!is_enum)
goto err;

View File

@ -959,7 +959,7 @@ uint ha_federated::convert_row_to_internal_format(uchar *record,
if (bitmap_is_set(table->read_set, (*field)->field_index))
{
(*field)->set_notnull();
(*field)->store(*row, *lengths, &my_charset_bin);
(*field)->store_text(*row, *lengths, &my_charset_bin);
}
}
(*field)->move_field_offset(-old_ptr);

View File

@ -893,7 +893,8 @@ uint ha_federatedx::convert_row_to_internal_format(uchar *record,
if (bitmap_is_set(table->read_set, (*field)->field_index))
{
(*field)->set_notnull();
(*field)->store(io->get_column_data(row, column), lengths[column], &my_charset_bin);
(*field)->store_text(io->get_column_data(row, column), lengths[column],
&my_charset_bin);
}
}
(*field)->move_field_offset(-old_ptr);