Commit 8afe96f0 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-8910 Wrong metadata or field type for MAX(COALESCE(string_field))

parent bed4e847
......@@ -3059,5 +3059,177 @@ DROP TABLE t2;
DROP TABLE t1;
SET timestamp=DEFAULT;
#
# MDEV-8910 Wrong metadata or field type for MAX(COALESCE(string_field))
#
CREATE TABLE t1 (c1 TINYBLOB, c2 MEDIUMBLOB, c3 BLOB, c4 LONGBLOB);
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3,
MAX(COALESCE(c4)) AS c4
FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`c1` varbinary(255) DEFAULT NULL,
`c2` mediumblob,
`c3` blob,
`c4` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3,
MAX(COALESCE(c4)) AS c4
FROM t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def c1 253 255 0 Y 128 31 63
def c2 250 16777215 0 Y 128 31 63
def c3 252 65535 0 Y 128 31 63
def c4 251 4294967295 0 Y 128 31 63
c1 c2 c3 c4
NULL NULL NULL NULL
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 CHAR(1), c2 CHAR(255)) CHARACTER SET latin1;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2
FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`c1` varchar(1) DEFAULT NULL,
`c2` varchar(255) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2
FROM t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def c1 253 1 0 Y 0 31 8
def c2 253 255 0 Y 0 31 8
c1 c2
NULL NULL
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 CHAR(1), c2 CHAR(255)) CHARACTER SET utf8;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2
FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`c1` varchar(1) CHARACTER SET utf8 DEFAULT NULL,
`c2` varchar(255) CHARACTER SET utf8 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2
FROM t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def c1 253 1 0 Y 0 31 8
def c2 253 255 0 Y 0 31 8
c1 c2
NULL NULL
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 VARCHAR(1), c2 VARCHAR(255), c3 VARCHAR(20000)) CHARACTER SET latin1;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3
FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`c1` varchar(1) DEFAULT NULL,
`c2` varchar(255) DEFAULT NULL,
`c3` text
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3
FROM t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def c1 253 1 0 Y 0 31 8
def c2 253 255 0 Y 0 31 8
def c3 252 20000 0 Y 0 31 8
c1 c2 c3
NULL NULL NULL
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 VARCHAR(1), c2 VARCHAR(255), c3 VARCHAR(20000)) CHARACTER SET utf8;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3
FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`c1` varchar(1) CHARACTER SET utf8 DEFAULT NULL,
`c2` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
`c3` text CHARACTER SET utf8
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3
FROM t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def c1 253 1 0 Y 0 31 8
def c2 253 255 0 Y 0 31 8
def c3 252 60000 0 Y 0 31 8
c1 c2 c3
NULL NULL NULL
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 ENUM('a')) CHARACTER SET latin1;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1
FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`c1` varchar(1) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT
MAX(COALESCE(c1)) AS c1
FROM t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def c1 253 1 0 Y 0 31 8
c1
NULL
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 ENUM('a')) CHARACTER SET utf8;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1
FROM t1;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`c1` varchar(1) CHARACTER SET utf8 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT
MAX(COALESCE(c1)) AS c1
FROM t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def c1 253 1 0 Y 0 31 8
c1
NULL
DROP TABLE t2;
DROP TABLE t1;
#
# End of 10.1 tests
#
......@@ -165,6 +165,140 @@ DROP TABLE t2;
DROP TABLE t1;
SET timestamp=DEFAULT;
--echo #
--echo # MDEV-8910 Wrong metadata or field type for MAX(COALESCE(string_field))
--echo #
CREATE TABLE t1 (c1 TINYBLOB, c2 MEDIUMBLOB, c3 BLOB, c4 LONGBLOB);
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3,
MAX(COALESCE(c4)) AS c4
FROM t1;
SHOW CREATE TABLE t2;
--disable_ps_protocol
--enable_metadata
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3,
MAX(COALESCE(c4)) AS c4
FROM t1;
--disable_metadata
--enable_ps_protocol
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 CHAR(1), c2 CHAR(255)) CHARACTER SET latin1;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2
FROM t1;
SHOW CREATE TABLE t2;
--disable_ps_protocol
--enable_metadata
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2
FROM t1;
--disable_metadata
--enable_ps_protocol
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 CHAR(1), c2 CHAR(255)) CHARACTER SET utf8;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2
FROM t1;
SHOW CREATE TABLE t2;
--disable_ps_protocol
--enable_metadata
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2
FROM t1;
--disable_metadata
--enable_ps_protocol
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 VARCHAR(1), c2 VARCHAR(255), c3 VARCHAR(20000)) CHARACTER SET latin1;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3
FROM t1;
SHOW CREATE TABLE t2;
--disable_ps_protocol
--enable_metadata
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3
FROM t1;
--disable_metadata
--enable_ps_protocol
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 VARCHAR(1), c2 VARCHAR(255), c3 VARCHAR(20000)) CHARACTER SET utf8;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3
FROM t1;
SHOW CREATE TABLE t2;
--disable_ps_protocol
--enable_metadata
SELECT
MAX(COALESCE(c1)) AS c1,
MAX(COALESCE(c2)) AS c2,
MAX(COALESCE(c3)) AS c3
FROM t1;
--disable_metadata
--enable_ps_protocol
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 ENUM('a')) CHARACTER SET latin1;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1
FROM t1;
SHOW CREATE TABLE t2;
--disable_ps_protocol
--enable_metadata
SELECT
MAX(COALESCE(c1)) AS c1
FROM t1;
--disable_metadata
--enable_ps_protocol
DROP TABLE t2;
DROP TABLE t1;
CREATE TABLE t1 (c1 ENUM('a')) CHARACTER SET utf8;
CREATE TABLE t2 AS
SELECT
MAX(COALESCE(c1)) AS c1
FROM t1;
SHOW CREATE TABLE t2;
--disable_ps_protocol
--enable_metadata
SELECT
MAX(COALESCE(c1)) AS c1
FROM t1;
--disable_metadata
--enable_ps_protocol
DROP TABLE t2;
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests
--echo #
......@@ -5362,17 +5362,6 @@ void Item::make_field(Send_field *tmp_field)
}
enum_field_types Item::string_field_type() const
{
enum_field_types f_type= MYSQL_TYPE_VAR_STRING;
if (max_length >= 16777216)
f_type= MYSQL_TYPE_LONG_BLOB;
else if (max_length >= 65536)
f_type= MYSQL_TYPE_MEDIUM_BLOB;
return f_type;
}
void Item_empty_string::make_field(Send_field *tmp_field)
{
init_make_field(tmp_field, string_field_type());
......
......@@ -761,7 +761,10 @@ class Item: public Value_source,
/* ... while cmp_type() specifies how it should be compared */
Item_result cmp_type() const;
virtual Item_result cast_to_int_type() const { return cmp_type(); }
virtual enum_field_types string_field_type() const;
enum_field_types string_field_type() const
{
return Type_handler::string_type_handler(max_length)->field_type();
}
enum_field_types field_type() const;
virtual enum Type type() const =0;
/*
......
......@@ -1187,7 +1187,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
if ((!item->fixed && item->fix_fields(thd, args)) ||
(item= args[0])->check_cols(1))
return TRUE;
decimals=item->decimals;
Type_std_attributes::set(args[0]);
with_subselect= args[0]->with_subselect;
Item *item2= item->real_item();
......@@ -1196,13 +1196,13 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
else if (item->cmp_type() == TIME_RESULT)
set_handler_by_field_type(item2->field_type());
else
set_handler_by_result_type(item2->result_type());
set_handler_by_result_type(item2->result_type(),
max_length, collation.collation);
switch (Item_sum_hybrid::result_type()) {
case INT_RESULT:
case DECIMAL_RESULT:
case STRING_RESULT:
max_length= item->max_length;
break;
case REAL_RESULT:
max_length= float_length(decimals);
......@@ -1214,7 +1214,6 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
setup_hybrid(thd, args[0], NULL);
/* MIN/MAX can return NULL for empty set indepedent of the used column */
maybe_null= 1;
unsigned_flag=item->unsigned_flag;
result_field=0;
null_value=1;
fix_length_and_dec();
......
......@@ -15,6 +15,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "sql_type.h"
#include "sql_const.h"
static Type_handler_tiny type_handler_tiny;
static Type_handler_short type_handler_short;
......@@ -41,9 +42,47 @@ static Type_handler_blob type_handler_blob;
static Type_handler_geometry type_handler_geometry;
Type_handler_hybrid_field_type::Type_handler_hybrid_field_type()
:m_type_handler(&type_handler_double)
/**
This method is used by:
- Item_func_set_user_var
- Item_func_get_user_var
- Item_user_var_as_out_param
- Item_func_udf_str
TODO: type_handler_adjusted_to_max_octet_length() and string_type_handler()
provide very similar functionality, to properly choose between
VARCHAR/VARBINARY vs TEXT/BLOB variations taking into accoung maximum
possible octet length.
We should probably get rid of either of them and use the same method
all around the code.
*/
const Type_handler *
Type_handler::string_type_handler(uint max_octet_length) const
{
if (max_octet_length >= 16777216)
return &type_handler_long_blob;
else if (max_octet_length >= 65536)
return &type_handler_medium_blob;
return &type_handler_varchar;
}
/**
This method is used by Item_sum_hybrid, e.g. MAX(item), MIN(item).
*/
const Type_handler *
Type_handler_string_result::type_handler_adjusted_to_max_octet_length(
uint max_octet_length,
CHARSET_INFO *cs) const
{
if (max_octet_length / cs->mbmaxlen <= CONVERT_IF_BIGGER_TO_BLOB)
return &type_handler_varchar; // See also Item::too_big_for_varchar()
if (max_octet_length >= 16777216)
return &type_handler_long_blob;
else if (max_octet_length >= 65536)
return &type_handler_medium_blob;
return &type_handler_blob;
}
......@@ -64,6 +103,12 @@ Type_handler_hybrid_field_type::get_handler_by_result_type(Item_result type)
}
Type_handler_hybrid_field_type::Type_handler_hybrid_field_type()
:m_type_handler(&type_handler_double)
{
}
const Type_handler *
Type_handler_hybrid_field_type::get_handler_by_field_type(enum_field_types type)
const
......
......@@ -25,12 +25,19 @@
class Type_handler
{
protected:
const Type_handler *string_type_handler(uint max_octet_length) const;
public:
virtual enum_field_types field_type() const= 0;
virtual Item_result result_type() const= 0;
virtual Item_result cmp_type() const= 0;
virtual const Type_handler*
type_handler_adjusted_to_max_octet_length(uint max_octet_length,
CHARSET_INFO *cs) const
{ return this; }
};
/*** Abstract classes for every XXX_RESULT */
class Type_handler_real_result: public Type_handler
......@@ -70,6 +77,9 @@ class Type_handler_string_result: public Type_handler
public:
Item_result result_type() const { return STRING_RESULT; }
Item_result cmp_type() const { return STRING_RESULT; }
const Type_handler *
type_handler_adjusted_to_max_octet_length(uint max_octet_length,
CHARSET_INFO *cs) const;
};
......@@ -283,10 +293,27 @@ class Type_handler_hybrid_field_type: public Type_handler
{
return (m_type_handler= get_handler_by_result_type(type));
}
const Type_handler *set_handler_by_result_type(Item_result type,
uint max_octet_length,
CHARSET_INFO *cs)
{
m_type_handler= get_handler_by_result_type(type);
return m_type_handler=
m_type_handler->type_handler_adjusted_to_max_octet_length(max_octet_length,
cs);
}
const Type_handler *set_handler_by_field_type(enum_field_types type)
{
return (m_type_handler= get_handler_by_field_type(type));
}
const Type_handler *
type_handler_adjusted_to_max_octet_length(uint max_octet_length,
CHARSET_INFO *cs) const
{
return
m_type_handler->type_handler_adjusted_to_max_octet_length(max_octet_length,
cs);
}
};
#endif /* SQL_TYPE_H_INCLUDED */
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