summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/main/type_varchar.result2
-rw-r--r--mysql-test/main/type_varchar_mysql41.result113
-rw-r--r--mysql-test/main/type_varchar_mysql41.test59
-rw-r--r--mysql-test/main/varbinary.result4
-rw-r--r--sql/field.cc45
-rw-r--r--sql/field.h26
-rw-r--r--sql/sp_head.cc3
-rw-r--r--sql/sql_type.h38
-rw-r--r--storage/tokudb/mysql-test/tokudb/r/type_varchar.result2
9 files changed, 228 insertions, 64 deletions
diff --git a/mysql-test/main/type_varchar.result b/mysql-test/main/type_varchar.result
index 0b2a5b54d08..53f390e8b38 100644
--- a/mysql-test/main/type_varchar.result
+++ b/mysql-test/main/type_varchar.result
@@ -12,7 +12,7 @@ t1 CREATE TABLE `t1` (
show create table vchar;
Table Create Table
vchar CREATE TABLE `vchar` (
- `v` varchar(30) DEFAULT NULL,
+ `v` varchar(30)/*old*/ DEFAULT NULL,
`c` char(3) DEFAULT NULL,
`e` enum('abc','def','ghi') DEFAULT NULL,
`t` text DEFAULT NULL
diff --git a/mysql-test/main/type_varchar_mysql41.result b/mysql-test/main/type_varchar_mysql41.result
new file mode 100644
index 00000000000..116e29a27c5
--- /dev/null
+++ b/mysql-test/main/type_varchar_mysql41.result
@@ -0,0 +1,113 @@
+#
+# MDEV-16325 CREATE..SELECT..UNION creates a wrong field type for old varchar
+#
+CREATE PROCEDURE p1(col VARCHAR(32))
+BEGIN
+EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2_simple AS SELECT col FROM t1old','col',col);
+SHOW CREATE TABLE t2_simple;
+DROP TABLE t2_simple;
+EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2_union_vv AS SELECT col FROM t1old UNION SELECT col FROM t1old','col',col);
+SHOW CREATE TABLE t2_union_vv;
+DROP TABLE t2_union_vv;
+EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2_union_vn AS SELECT col FROM t1old UNION SELECT NULL','col',col);
+SHOW CREATE TABLE t2_union_vn;
+DROP TABLE t2_union_vn;
+EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2_union_nv AS SELECT NULL AS col UNION SELECT col FROM t1old','col',col);
+SHOW CREATE TABLE t2_union_nv;
+DROP TABLE t2_union_nv;
+EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2 AS SELECT
+ COALESCE(col),
+ COALESCE(col,col),
+ COALESCE(col,NULL),
+ COALESCE(NULL,col)
+ FROM t1old', 'col', col);
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2 AS SELECT
+ LEAST(col,col),
+ LEAST(col,NULL),
+ LEAST(NULL,col)
+ FROM t1old','col',col);
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+END;
+$$
+TRUNCATE TABLE t1old;
+SHOW CREATE TABLE t1old;
+Table Create Table
+t1old CREATE TABLE `t1old` (
+ `v` varchar(30)/*old*/ DEFAULT NULL,
+ `c` char(3) DEFAULT NULL,
+ `e` enum('abc','def','ghi') DEFAULT NULL,
+ `t` text DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+CALL p1('v');
+Table Create Table
+t2_simple CREATE TABLE `t2_simple` (
+ `v` varchar(30) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Table Create Table
+t2_union_vv CREATE TABLE `t2_union_vv` (
+ `v` varchar(30) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Table Create Table
+t2_union_vn CREATE TABLE `t2_union_vn` (
+ `v` varchar(30) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Table Create Table
+t2_union_nv CREATE TABLE `t2_union_nv` (
+ `v` varchar(30) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `COALESCE(v)` varchar(30) DEFAULT NULL,
+ `COALESCE(v,v)` varchar(30) DEFAULT NULL,
+ `COALESCE(v,NULL)` varchar(30) DEFAULT NULL,
+ `COALESCE(NULL,v)` varchar(30) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `LEAST(v,v)` varchar(30) DEFAULT NULL,
+ `LEAST(v,NULL)` varchar(30) DEFAULT NULL,
+ `LEAST(NULL,v)` varchar(30) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1old;
+TRUNCATE TABLE t1old;
+SHOW CREATE TABLE t1old;
+Table Create Table
+t1old CREATE TABLE `t1old` (
+ `a` varbinary(255)/*old*/ DEFAULT NULL,
+ `b` varchar(255)/*old*/ DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+CALL p1('a');
+Table Create Table
+t2_simple CREATE TABLE `t2_simple` (
+ `a` varbinary(255) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Table Create Table
+t2_union_vv CREATE TABLE `t2_union_vv` (
+ `a` varbinary(255) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Table Create Table
+t2_union_vn CREATE TABLE `t2_union_vn` (
+ `a` varbinary(255) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Table Create Table
+t2_union_nv CREATE TABLE `t2_union_nv` (
+ `a` varbinary(255) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `COALESCE(a)` varbinary(255) DEFAULT NULL,
+ `COALESCE(a,a)` varbinary(255) DEFAULT NULL,
+ `COALESCE(a,NULL)` varbinary(255) DEFAULT NULL,
+ `COALESCE(NULL,a)` varbinary(255) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `LEAST(a,a)` varbinary(255) DEFAULT NULL,
+ `LEAST(a,NULL)` varbinary(255) DEFAULT NULL,
+ `LEAST(NULL,a)` varbinary(255) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1old;
+DROP PROCEDURE p1;
diff --git a/mysql-test/main/type_varchar_mysql41.test b/mysql-test/main/type_varchar_mysql41.test
new file mode 100644
index 00000000000..5624e9edaaa
--- /dev/null
+++ b/mysql-test/main/type_varchar_mysql41.test
@@ -0,0 +1,59 @@
+--echo #
+--echo # MDEV-16325 CREATE..SELECT..UNION creates a wrong field type for old varchar
+--echo #
+
+
+DELIMITER $$;
+CREATE PROCEDURE p1(col VARCHAR(32))
+BEGIN
+ EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2_simple AS SELECT col FROM t1old','col',col);
+ SHOW CREATE TABLE t2_simple;
+ DROP TABLE t2_simple;
+
+ EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2_union_vv AS SELECT col FROM t1old UNION SELECT col FROM t1old','col',col);
+ SHOW CREATE TABLE t2_union_vv;
+ DROP TABLE t2_union_vv;
+
+ EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2_union_vn AS SELECT col FROM t1old UNION SELECT NULL','col',col);
+ SHOW CREATE TABLE t2_union_vn;
+ DROP TABLE t2_union_vn;
+
+ EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2_union_nv AS SELECT NULL AS col UNION SELECT col FROM t1old','col',col);
+ SHOW CREATE TABLE t2_union_nv;
+ DROP TABLE t2_union_nv;
+
+ EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2 AS SELECT
+ COALESCE(col),
+ COALESCE(col,col),
+ COALESCE(col,NULL),
+ COALESCE(NULL,col)
+ FROM t1old', 'col', col);
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+
+ EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2 AS SELECT
+ LEAST(col,col),
+ LEAST(col,NULL),
+ LEAST(NULL,col)
+ FROM t1old','col',col);
+ SHOW CREATE TABLE t2;
+ DROP TABLE t2;
+END;
+$$
+DELIMITER ;$$
+
+let $MYSQLD_DATADIR= `SELECT @@datadir`;
+copy_file $MYSQL_TEST_DIR/std_data/vchar.frm $MYSQLD_DATADIR/test/t1old.frm;
+TRUNCATE TABLE t1old;
+SHOW CREATE TABLE t1old;
+CALL p1('v');
+DROP TABLE t1old;
+
+let $MYSQLD_DATADIR= `SELECT @@datadir`;
+copy_file $MYSQL_TEST_DIR/std_data/bug19371.frm $MYSQLD_DATADIR/test/t1old.frm;
+TRUNCATE TABLE t1old;
+SHOW CREATE TABLE t1old;
+CALL p1('a');
+DROP TABLE t1old;
+
+DROP PROCEDURE p1;
diff --git a/mysql-test/main/varbinary.result b/mysql-test/main/varbinary.result
index 58cab5ad1ca..3a182e74692 100644
--- a/mysql-test/main/varbinary.result
+++ b/mysql-test/main/varbinary.result
@@ -82,8 +82,8 @@ drop table t1;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` varbinary(255) DEFAULT NULL,
- `b` varchar(255) DEFAULT NULL
+ `a` varbinary(255)/*old*/ DEFAULT NULL,
+ `b` varchar(255)/*old*/ DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select length(a), length(b) from t1;
length(a) length(b)
diff --git a/sql/field.cc b/sql/field.cc
index 220785643bd..059b06b5dba 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -80,15 +80,14 @@ const int FIELDTYPE_LAST= 254;
const int FIELDTYPE_NUM= FIELDTYPE_TEAR_FROM + (FIELDTYPE_LAST -
FIELDTYPE_TEAR_TO);
-static inline int field_type2index (enum_field_types field_type)
+static inline int merge_type2index(enum_field_types merge_type)
{
- DBUG_ASSERT(real_type_to_type(field_type) < FIELDTYPE_TEAR_FROM ||
- real_type_to_type(field_type) > FIELDTYPE_TEAR_TO);
- DBUG_ASSERT(field_type <= FIELDTYPE_LAST);
- field_type= real_type_to_type(field_type);
- if (field_type < FIELDTYPE_TEAR_FROM)
- return field_type;
- return FIELDTYPE_TEAR_FROM + (field_type - FIELDTYPE_TEAR_TO) - 1;
+ DBUG_ASSERT(merge_type < FIELDTYPE_TEAR_FROM ||
+ merge_type > FIELDTYPE_TEAR_TO);
+ DBUG_ASSERT(merge_type <= FIELDTYPE_LAST);
+ if (merge_type < FIELDTYPE_TEAR_FROM)
+ return merge_type;
+ return FIELDTYPE_TEAR_FROM + (merge_type - FIELDTYPE_TEAR_TO) - 1;
}
@@ -913,31 +912,16 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
}
};
-/**
- Return type of which can carry value of both given types in UNION result.
-
- @param a type for merging
- @param b type for merging
-
- @return
- type of field
-*/
-
-enum_field_types Field::field_type_merge(enum_field_types a,
- enum_field_types b)
-{
- return field_types_merge_rules[field_type2index(a)]
- [field_type2index(b)];
-}
const Type_handler *
Type_handler::aggregate_for_result_traditional(const Type_handler *a,
const Type_handler *b)
{
- enum_field_types ta= a->real_field_type();
- enum_field_types tb= b->real_field_type();
- return
- Type_handler::get_handler_by_real_type(Field::field_type_merge(ta, tb));
+ enum_field_types ta= a->traditional_merge_field_type();
+ enum_field_types tb= b->traditional_merge_field_type();
+ enum_field_types res= field_types_merge_rules[merge_type2index(ta)]
+ [merge_type2index(tb)];
+ return Type_handler::get_handler_by_real_type(res);
}
@@ -7296,11 +7280,12 @@ void Field_string::sql_type(String &res) const
size_t length;
length= cs->cset->snprintf(cs,(char*) res.ptr(),
- res.alloced_length(), "%s(%d)",
+ res.alloced_length(), "%s(%d)%s",
(type() == MYSQL_TYPE_VAR_STRING ?
(has_charset() ? "varchar" : "varbinary") :
(has_charset() ? "char" : "binary")),
- (int) field_length / charset()->mbmaxlen);
+ (int) field_length / charset()->mbmaxlen,
+ type() == MYSQL_TYPE_VAR_STRING ? "/*old*/" : "");
res.length(length);
if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) &&
has_charset() && (charset()->state & MY_CS_BINSORT))
diff --git a/sql/field.h b/sql/field.h
index 5313f35d81a..eb4be46d3a0 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -467,31 +467,6 @@ inline bool is_temporal_type_with_date(enum_field_types type)
}
-/**
- Convert temporal real types as retuned by field->real_type()
- to field type as returned by field->type().
-
- @param real_type Real type.
- @retval Field type.
-*/
-inline enum_field_types real_type_to_type(enum_field_types real_type)
-{
- switch (real_type)
- {
- case MYSQL_TYPE_TIME2:
- return MYSQL_TYPE_TIME;
- case MYSQL_TYPE_DATETIME2:
- return MYSQL_TYPE_DATETIME;
- case MYSQL_TYPE_TIMESTAMP2:
- return MYSQL_TYPE_TIMESTAMP;
- case MYSQL_TYPE_NEWDATE:
- return MYSQL_TYPE_DATE;
- /* Note: NEWDECIMAL is a type, not only a real_type */
- default: return real_type;
- }
-}
-
-
enum enum_vcol_info_type
{
VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED,
@@ -873,7 +848,6 @@ public:
{
return type_handler()->cmp_type();
}
- static enum_field_types field_type_merge(enum_field_types, enum_field_types);
virtual bool eq(Field *field)
{
return (ptr == field->ptr && null_ptr == field->null_ptr &&
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index f7847bae89d..a9056553080 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -75,9 +75,8 @@ sp_map_item_type(const Type_handler *handler)
{
if (handler == &type_handler_row)
return Item::ROW_ITEM;
- enum_field_types type= real_type_to_type(handler->real_field_type());
- switch (type) {
+ switch (handler->real_field_type()) {
case MYSQL_TYPE_BIT:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 74aacc0e0d1..274194f52fe 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -1021,6 +1021,28 @@ public:
virtual const Name name() const= 0;
virtual enum_field_types field_type() const= 0;
virtual enum_field_types real_field_type() const { return field_type(); }
+ /**
+ Type code which is used for merging of traditional data types for result
+ (for UNION and for hybrid functions such as COALESCE).
+ Mapping can be done both ways: old->new, new->old, depending
+ on the particular data type implementation:
+ - type_handler_var_string (MySQL-4.1 old VARCHAR) is converted to
+ new VARCHAR before merging.
+ field_type_merge_rules[][] returns new VARCHAR.
+ - type_handler_newdate is converted to old DATE before merging.
+ field_type_merge_rules[][] returns NEWDATE.
+ - Temporal type_handler_xxx2 (new MySQL-5.6 types) are converted to
+ corresponding old type codes before merging (e.g. TIME2->TIME).
+ field_type_merge_rules[][] returns old type codes (e.g. TIME).
+ Then old types codes are supposed to convert to new type codes somehow,
+ but they do not. So UNION and COALESCE create old columns.
+ This is a bug and should be fixed eventually.
+ */
+ virtual enum_field_types traditional_merge_field_type() const
+ {
+ DBUG_ASSERT(is_traditional_type());
+ return field_type();
+ }
virtual Item_result result_type() const= 0;
virtual Item_result cmp_type() const= 0;
virtual enum_mysql_timestamp_type mysql_timestamp_type() const
@@ -3123,6 +3145,10 @@ public:
const Name name() const { return m_name_var_string; }
enum_field_types field_type() const { return MYSQL_TYPE_VAR_STRING; }
enum_field_types real_field_type() const { return MYSQL_TYPE_STRING; }
+ enum_field_types traditional_merge_field_type() const
+ {
+ return MYSQL_TYPE_VARCHAR;
+ }
const Type_handler *type_handler_for_tmp_table(const Item *item) const
{
return varstring_type_handler(item);
@@ -3427,7 +3453,11 @@ class Type_handler_enum: public Type_handler_typelib
public:
virtual ~Type_handler_enum() {}
const Name name() const { return m_name_enum; }
- virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; }
+ enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; }
+ enum_field_types traditional_merge_field_type() const
+ {
+ return MYSQL_TYPE_ENUM;
+ }
uint32 calc_pack_length(uint32 length) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
const Field *target) const;
@@ -3455,7 +3485,11 @@ class Type_handler_set: public Type_handler_typelib
public:
virtual ~Type_handler_set() {}
const Name name() const { return m_name_set; }
- virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; }
+ enum_field_types real_field_type() const { return MYSQL_TYPE_SET; }
+ enum_field_types traditional_merge_field_type() const
+ {
+ return MYSQL_TYPE_SET;
+ }
uint32 calc_pack_length(uint32 length) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
const Field *target) const;
diff --git a/storage/tokudb/mysql-test/tokudb/r/type_varchar.result b/storage/tokudb/mysql-test/tokudb/r/type_varchar.result
index bf98e12ce16..881a4cd66ac 100644
--- a/storage/tokudb/mysql-test/tokudb/r/type_varchar.result
+++ b/storage/tokudb/mysql-test/tokudb/r/type_varchar.result
@@ -13,7 +13,7 @@ t1 CREATE TABLE `t1` (
show create table vchar;
Table Create Table
vchar CREATE TABLE `vchar` (
- `v` varchar(30) DEFAULT NULL,
+ `v` varchar(30)/*old*/ DEFAULT NULL,
`c` char(3) DEFAULT NULL,
`e` enum('abc','def','ghi') DEFAULT NULL,
`t` text DEFAULT NULL