Commit 0e273510 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-34376 Wrong data types when mixing an utf8 *TEXT column and a short binary

A mixture of a multi-byte *TEXT column and a short binary column
produced a too large column.
For example, COALESCE(tinytext_utf8mb4, short_varbinary)
produced a BLOB column instead of an expected TINYBLOB.

- Adding a virtual method Type_all_attributes::character_octet_length(),
  returning max_length by default.
- Overriding Item_field::character_octet_length() to extract
  the octet length from the underlying Field.
- Overriding Item_ref::character_octet_length() to extract
  the octet length from the references Item (e.g. as VIEW fields).
- Fixing Type_numeric_attributes::find_max_octet_length() to
  take the octet length using the new method character_octet_length()
  instead of accessing max_length directly.
parent c83ba513
......@@ -4165,5 +4165,126 @@ SELECT 1 COLLATE utf8mb4_bin;
SELECT 1 COLLATE latin1_swedish_ci;
ERROR 42000: COLLATION 'latin1_swedish_ci' is not valid for CHARACTER SET 'utf8mb4'
#
# MDEV-34376 Wrong data types when mixing an utf8 *TEXT column and a short binary
#
CREATE TABLE t1 (
c_tinytext tinytext,
c_text text,
c_mediumtext mediumtext,
c_longtext longtext
) CHARACTER SET utf8mb4;
CREATE VIEW v1 AS SELECT * FROM t1;
CREATE VIEW v2 AS SELECT * FROM v1;
# Using table fields
CREATE TABLE t2 AS SELECT
COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary,
COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary,
COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary,
COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary
FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`mix_tinytext_binary` tinyblob DEFAULT NULL,
`mix_text_binary` blob DEFAULT NULL,
`mix_mediumtext_binary` mediumblob DEFAULT NULL,
`mix_longtext_binary` longblob DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t2;
CREATE TABLE t2 AS SELECT
c_tinytext AS mix_tinytext_binary,
c_text AS mix_text_binary,
c_mediumtext AS mix_mediumtext_binary,
c_longtext AS mix_longtext_binary
FROM t1
UNION SELECT
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY);
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`mix_tinytext_binary` tinyblob DEFAULT NULL,
`mix_text_binary` blob DEFAULT NULL,
`mix_mediumtext_binary` mediumblob DEFAULT NULL,
`mix_longtext_binary` longblob DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t2;
# Using view fields
CREATE TABLE t2 AS SELECT
COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary,
COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary,
COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary,
COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary
FROM v1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`mix_tinytext_binary` tinyblob DEFAULT NULL,
`mix_text_binary` blob DEFAULT NULL,
`mix_mediumtext_binary` mediumblob DEFAULT NULL,
`mix_longtext_binary` longblob DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t2;
CREATE TABLE t2 AS SELECT
c_tinytext AS mix_tinytext_binary,
c_text AS mix_text_binary,
c_mediumtext AS mix_mediumtext_binary,
c_longtext AS mix_longtext_binary
FROM v1
UNION SELECT
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY);
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`mix_tinytext_binary` tinyblob DEFAULT NULL,
`mix_text_binary` blob DEFAULT NULL,
`mix_mediumtext_binary` mediumblob DEFAULT NULL,
`mix_longtext_binary` longblob DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t2;
# Using view on view fields
CREATE TABLE t2 AS SELECT
COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary,
COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary,
COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary,
COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary
FROM v2;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`mix_tinytext_binary` tinyblob DEFAULT NULL,
`mix_text_binary` blob DEFAULT NULL,
`mix_mediumtext_binary` mediumblob DEFAULT NULL,
`mix_longtext_binary` longblob DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t2;
CREATE TABLE t2 AS SELECT
c_tinytext AS mix_tinytext_binary,
c_text AS mix_text_binary,
c_mediumtext AS mix_mediumtext_binary,
c_longtext AS mix_longtext_binary
FROM v2
UNION SELECT
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY);
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`mix_tinytext_binary` tinyblob DEFAULT NULL,
`mix_text_binary` blob DEFAULT NULL,
`mix_mediumtext_binary` mediumblob DEFAULT NULL,
`mix_longtext_binary` longblob DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t2;
DROP VIEW v2, v1;
DROP TABLE t1;
#
# End of 10.5 tests
#
......@@ -2062,6 +2062,99 @@ SELECT 1 COLLATE utf8mb4_bin;
--error ER_COLLATION_CHARSET_MISMATCH
SELECT 1 COLLATE latin1_swedish_ci;
--echo #
--echo # MDEV-34376 Wrong data types when mixing an utf8 *TEXT column and a short binary
--echo #
CREATE TABLE t1 (
c_tinytext tinytext,
c_text text,
c_mediumtext mediumtext,
c_longtext longtext
) CHARACTER SET utf8mb4;
CREATE VIEW v1 AS SELECT * FROM t1;
CREATE VIEW v2 AS SELECT * FROM v1;
--echo # Using table fields
CREATE TABLE t2 AS SELECT
COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary,
COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary,
COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary,
COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary
FROM t1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
CREATE TABLE t2 AS SELECT
c_tinytext AS mix_tinytext_binary,
c_text AS mix_text_binary,
c_mediumtext AS mix_mediumtext_binary,
c_longtext AS mix_longtext_binary
FROM t1
UNION SELECT
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY);
SHOW CREATE TABLE t2;
DROP TABLE t2;
--echo # Using view fields
CREATE TABLE t2 AS SELECT
COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary,
COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary,
COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary,
COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary
FROM v1;
SHOW CREATE TABLE t2;
DROP TABLE t2;
CREATE TABLE t2 AS SELECT
c_tinytext AS mix_tinytext_binary,
c_text AS mix_text_binary,
c_mediumtext AS mix_mediumtext_binary,
c_longtext AS mix_longtext_binary
FROM v1
UNION SELECT
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY);
SHOW CREATE TABLE t2;
DROP TABLE t2;
--echo # Using view on view fields
CREATE TABLE t2 AS SELECT
COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary,
COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary,
COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary,
COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary
FROM v2;
SHOW CREATE TABLE t2;
DROP TABLE t2;
CREATE TABLE t2 AS SELECT
c_tinytext AS mix_tinytext_binary,
c_text AS mix_text_binary,
c_mediumtext AS mix_mediumtext_binary,
c_longtext AS mix_longtext_binary
FROM v2
UNION SELECT
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY),
CAST('binary data' AS BINARY);
SHOW CREATE TABLE t2;
DROP TABLE t2;
DROP VIEW v2, v1;
DROP TABLE t1;
--echo #
--echo # End of 10.5 tests
--echo #
......@@ -3576,6 +3576,10 @@ class Item_field :public Item_ident,
return &type_handler_null;
return field->type_handler();
}
uint32 character_octet_length() const override
{
return field->character_octet_length();
}
Field *create_tmp_field_from_item_field(MEM_ROOT *root, TABLE *new_table,
Item_ref *orig_item,
const Tmp_field_param *param);
......@@ -5578,6 +5582,10 @@ class Item_ref :public Item_ident,
{ return (*ref)->type_handler(); }
const Type_handler *real_type_handler() const override
{ return (*ref)->real_type_handler(); }
uint32 character_octet_length() const override
{
return Item_ref::real_item()->character_octet_length();
}
Field *get_tmp_table_field() override
{ return result_field ? result_field : (*ref)->get_tmp_table_field(); }
Item *get_tmp_table_item(THD *thd) override;
......@@ -5616,6 +5624,10 @@ class Item_ref :public Item_ident,
(*ref)->save_in_field(result_field, no_conversions);
}
Item *real_item() override { return ref ? (*ref)->real_item() : this; }
const Item *real_item() const
{
return const_cast<Item_ref*>(this)->Item_ref::real_item();
}
const TYPELIB *get_typelib() const override
{
return ref ? (*ref)->get_typelib() : NULL;
......
......@@ -1221,7 +1221,7 @@ uint32 Type_numeric_attributes::find_max_octet_length(Item **item, uint nitems)
{
uint32 octet_length= 0;
for (uint i= 0; i < nitems ; i++)
set_if_bigger(octet_length, item[i]->max_length);
set_if_bigger(octet_length, item[i]->character_octet_length());
return octet_length;
}
......
......@@ -3345,6 +3345,7 @@ class Type_all_attributes: public Type_std_attributes
{ }
virtual ~Type_all_attributes() = default;
virtual void set_maybe_null(bool maybe_null_arg)= 0;
virtual uint32 character_octet_length() const { return max_length; }
// Returns total number of decimal digits
virtual uint decimal_precision() const= 0;
virtual const TYPELIB *get_typelib() const= 0;
......
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