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; ...@@ -3059,5 +3059,177 @@ DROP TABLE t2;
DROP TABLE t1; DROP TABLE t1;
SET timestamp=DEFAULT; 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 # End of 10.1 tests
# #
...@@ -165,6 +165,140 @@ DROP TABLE t2; ...@@ -165,6 +165,140 @@ DROP TABLE t2;
DROP TABLE t1; DROP TABLE t1;
SET timestamp=DEFAULT; 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 #
--echo # End of 10.1 tests --echo # End of 10.1 tests
--echo # --echo #
...@@ -5362,17 +5362,6 @@ void Item::make_field(Send_field *tmp_field) ...@@ -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) void Item_empty_string::make_field(Send_field *tmp_field)
{ {
init_make_field(tmp_field, string_field_type()); init_make_field(tmp_field, string_field_type());
......
...@@ -761,7 +761,10 @@ class Item: public Value_source, ...@@ -761,7 +761,10 @@ class Item: public Value_source,
/* ... while cmp_type() specifies how it should be compared */ /* ... while cmp_type() specifies how it should be compared */
Item_result cmp_type() const; Item_result cmp_type() const;
virtual Item_result cast_to_int_type() const { return cmp_type(); } 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; enum_field_types field_type() const;
virtual enum Type type() const =0; virtual enum Type type() const =0;
/* /*
......
...@@ -1187,7 +1187,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) ...@@ -1187,7 +1187,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
if ((!item->fixed && item->fix_fields(thd, args)) || if ((!item->fixed && item->fix_fields(thd, args)) ||
(item= args[0])->check_cols(1)) (item= args[0])->check_cols(1))
return TRUE; return TRUE;
decimals=item->decimals; Type_std_attributes::set(args[0]);
with_subselect= args[0]->with_subselect; with_subselect= args[0]->with_subselect;
Item *item2= item->real_item(); Item *item2= item->real_item();
...@@ -1196,13 +1196,13 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) ...@@ -1196,13 +1196,13 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
else if (item->cmp_type() == TIME_RESULT) else if (item->cmp_type() == TIME_RESULT)
set_handler_by_field_type(item2->field_type()); set_handler_by_field_type(item2->field_type());
else 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()) { switch (Item_sum_hybrid::result_type()) {
case INT_RESULT: case INT_RESULT:
case DECIMAL_RESULT: case DECIMAL_RESULT:
case STRING_RESULT: case STRING_RESULT:
max_length= item->max_length;
break; break;
case REAL_RESULT: case REAL_RESULT:
max_length= float_length(decimals); max_length= float_length(decimals);
...@@ -1214,7 +1214,6 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) ...@@ -1214,7 +1214,6 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
setup_hybrid(thd, args[0], NULL); setup_hybrid(thd, args[0], NULL);
/* MIN/MAX can return NULL for empty set indepedent of the used column */ /* MIN/MAX can return NULL for empty set indepedent of the used column */
maybe_null= 1; maybe_null= 1;
unsigned_flag=item->unsigned_flag;
result_field=0; result_field=0;
null_value=1; null_value=1;
fix_length_and_dec(); fix_length_and_dec();
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "sql_type.h" #include "sql_type.h"
#include "sql_const.h"
static Type_handler_tiny type_handler_tiny; static Type_handler_tiny type_handler_tiny;
static Type_handler_short type_handler_short; static Type_handler_short type_handler_short;
...@@ -41,9 +42,47 @@ static Type_handler_blob type_handler_blob; ...@@ -41,9 +42,47 @@ static Type_handler_blob type_handler_blob;
static Type_handler_geometry type_handler_geometry; 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) ...@@ -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 * const Type_handler *
Type_handler_hybrid_field_type::get_handler_by_field_type(enum_field_types type) Type_handler_hybrid_field_type::get_handler_by_field_type(enum_field_types type)
const const
......
...@@ -25,12 +25,19 @@ ...@@ -25,12 +25,19 @@
class Type_handler class Type_handler
{ {
protected:
const Type_handler *string_type_handler(uint max_octet_length) const;
public: public:
virtual enum_field_types field_type() const= 0; virtual enum_field_types field_type() const= 0;
virtual Item_result result_type() const= 0; virtual Item_result result_type() const= 0;
virtual Item_result cmp_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 */ /*** Abstract classes for every XXX_RESULT */
class Type_handler_real_result: public Type_handler class Type_handler_real_result: public Type_handler
...@@ -70,6 +77,9 @@ class Type_handler_string_result: public Type_handler ...@@ -70,6 +77,9 @@ class Type_handler_string_result: public Type_handler
public: public:
Item_result result_type() const { return STRING_RESULT; } Item_result result_type() const { return STRING_RESULT; }
Item_result cmp_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 ...@@ -283,10 +293,27 @@ class Type_handler_hybrid_field_type: public Type_handler
{ {
return (m_type_handler= get_handler_by_result_type(type)); 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) const Type_handler *set_handler_by_field_type(enum_field_types type)
{ {
return (m_type_handler= get_handler_by_field_type(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 */ #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