← Back to team overview

maria-developers team mailing list archive

Re: MDEV-9217 Split Item::tmp_table_field_from_field_type() into virtual methods in Type_handler

 

Hello Sanja,

I wrote extended commit comments for the patch, to make review easier.

Please find attached.

Thanks.



On 04/21/2017 08:05 PM, Alexander Barkov wrote:
> Hello Sanja,
> 
> Please review a patch for MDEV-9217.
> 
> Thanks!
> 
commit d56d0da5ec8e07b81c719e6fc173fcb50b598fec
Author: Alexander Barkov <bar@xxxxxxxxxxx>
Date:   Fri Apr 21 23:32:02 2017 +0400

    MDEV-9217 Split Item::tmp_table_field_from_field_type() into virtual methods in Type_handler
    
    - Adding Type_handler::make_table_field() and moving pieces of the code
      from Item::tmp_table_field_from_field_type() to virtual implementations
      for various type handlers.
    
    - Adding a new Type_all_attributes, to access to Item's extended
      attributes, such as decimal_precision() and geometry_type().
    
    - Adding a new class Record_addr, to pass record related information
      to Type_handler methods (ptr, null_ptr and null_bit) as a single structure.
      Note, later it will possibly be extended for BIT-alike field purposes,
      by adding new members (bit_ptr_arg, bit_ofs_arg).
    
    - Moving the code from Field_new_decimal::create_from_item()
      to Type_handler_newdecimal::make_table_field().
    
    - Removing Field_new_decimal() and Field_geom() helper constructor
      variants that were used for temporary field creation.
    
    - Adding Item_field::type_handler(), Field::type_handler() and
      Field_blob::type_handler() to return correct type handlers for
      blob variants, according to Field_blob::packlength.
    
    - Adding Type_handler_blob_common, as a common parent for
      Type_handler_tiny_blob, Type_handler_blob, Type_handler_medium_blob
      and Type_handler_long_blob.
    
    - Implementing Type_handler_blob_common::Item_hybrid_func_fix_attributes().
    
      It's needed for cases when TEXT variants of different character sets are mixed
      in LEAST, GREATEST, CASE and its abreviations (IF, IFNULL, COALESCE), e.g.:
          CREATE TABLE t1 (
            a TINYTEXT CHARACTER SET latin1,
            b TINYTEXT CHARACTER SET utf8
          );
          CREATE TABLE t2 AS SELECT COALESCE(a,b) FROM t1;
      Type handler aggregation returns TINYTEXT as a common data type
      for the two columns. But as conversion from latin1 to utf8
      happens for "a", the maximum possible length of "a" grows from 255 to 255*3.
      Type_handler_blob_common::Item_hybrid_func_fix_attributes() makes sure
      to update the blob type handler according to max_length.
    
    - Adding Type_handler::blob_type_handler(uint max_octet_length).
    
    - Adding a few m_type_aggregator_for_result.add() pairs, because
      now Item_xxx::type_handler() can return pointers to type_handler_tiny_blob,
      type_handler_blob, type_handler_medium_blob, type_handler_long_blob.
      Before the patch only type_handler_blob was possible result of type_handler().
    
    - Making type_handler_tiny_blob, type_handler_blob, type_handler_medium_blob,
      type_handler_long_blob public.
    
    - Removing the condition in Item_sum_avg::create_tmp_field()
      checking Item_sum_avg::result_type() against DECIMAL_RESULT.
      Now both REAL_RESULT and DECIMAL_RESULT are symmetrically handled
      by tmp_table_field_from_field_type().
    
    - Removing Item_geometry_func::create_field_for_create_select(),
      as the inherited version perfectly works.
    
    - Fixing Item_func_as_wkb::field_type() to return MYSQL_TYPE_LONG_BLOB
      rather than MYSQL_TYPE_BLOB. It's needed to make sure that
      tmp_table_field_from_field_type() creates a LONGBLOB field for AsWKB().
    
    - Fixing Item_func_as_wkt::fix_length_and_dec() to set max_length to
      4294967295U rather than MAX_BLOB_WIDTH, to make sure that
      tmp_table_field_from_field_type() creates a LONGTEXT field for AsWKT().
    
    - Removing Item_func_set_user_var::create_field_for_create_select(),
      as the inherited version works fine.
    
    - Adding Item_func_get_user_var::create_field_for_create_select() to
      make sure that "CREATE TABLE t1 AS SELECT @string_user variable"
      always creates a field of LONGTEXT/LONGBLOB type.
    
    - Item_func_ifnull::create_field_for_create_select()
      behavior has changed. Before the patch it passed set_blob_packflag=false,
      which meant to create LONGBLOB for all blob variants.
      Now it takes into account max_length, which gives better column
      data types for:
        CREATE TABLE t2 AS SELECT IFNULL(blob_column1, blob_column2) FROM t1;
    
    - Fixing Item_func_nullif::fix_length_and_dec() to use
      set_handler(args[2]->type_handler()) instead of
      set_handler_by_field_type(args[2]->field_type()).
      This is needed to distinguish between BLOB variants.
    
    - Implementing Item_blob::type_handler(), to make sure to create
      proper BLOB field variant, according to max_length, for queries like:
        CREATE TABLE t1 AS
          SELECT some_blob_field FROM INFORMATION_SCHEMA.SOME_TABLE;
    
    - Fixing Item_field::real_type_handler() to make sure that
      the code aggregating fields for UNION gets a proper BLOB
      variant type handler from fields.
    
    - Adding a special code into Item_type_holder::make_field_by_type(),
      to make sure that after aggregating field types it also properly
      takes into account max_length when mixing TEXT variants of different
      character sets and chooses a proper TEXT variant:
          CREATE TABLE t1 (
            a TINYTEXT CHARACTER SET latin1,
            b TINYTEXT CHARACTER SET utf8
          );
          CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1;
    
    - Adding tests, for better coverage of IFNULL, NULLIF, UNION.
    
    - The fact that tmp_table_field_from_field_type() now takes
      into account BLOB variants (instead of always creating LONGBLOB),
      tests results for WEIGHT_STRING() and NULLIF() and UNION
      have become more precise.

diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index 1f032fa..1a3289b 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -488,13 +488,35 @@ d	date	YES		NULL
 e	varchar(1)	YES		NULL	
 f	datetime	YES		NULL	
 g	time	YES		NULL	
-h	longblob	YES		NULL	
+h	blob	YES		NULL	
 dd	time	YES		NULL	
 select * from t2;
 a	b	c	d	e	f	g	h	dd
 1	-7	7	2000-01-01	b	2000-01-01 00:00:00	05:04:03	yet another binary data	02:00:00
 2	-2	2	1825-12-14	a	2003-01-01 03:02:01	04:03:02	binary data	02:00:00
 drop table t1, t2;
+CREATE TABLE t1 (
+c_tinytext tinytext,
+c_text text,
+c_mediumtext mediumtext,
+c_longtext longtext
+);
+CREATE TABLE t2 AS SELECT
+ifnull(c_tinytext,   CAST('yet another binary data' AS BINARY)),
+ifnull(c_text,       CAST('yet another binary data' AS BINARY)),
+ifnull(c_mediumtext, CAST('yet another binary data' AS BINARY)),
+ifnull(c_longtext,   CAST('yet another binary data' AS BINARY))
+FROM t1;
+SHOW CREATE TABLE t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `ifnull(c_tinytext,   CAST('yet another binary data' AS BINARY))` tinyblob DEFAULT NULL,
+  `ifnull(c_text,       CAST('yet another binary data' AS BINARY))` blob DEFAULT NULL,
+  `ifnull(c_mediumtext, CAST('yet another binary data' AS BINARY))` mediumblob DEFAULT NULL,
+  `ifnull(c_longtext,   CAST('yet another binary data' AS BINARY))` longblob DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
 create table t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float(3,2), g double(4,3), h decimal(5,4), i year, j date, k timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, l datetime, m enum('a','b'), n set('a','b'), o char(10));
 create table t2 select ifnull(a,a), ifnull(b,b), ifnull(c,c), ifnull(d,d), ifnull(e,e), ifnull(f,f), ifnull(g,g), ifnull(h,h), ifnull(i,i), ifnull(j,j), ifnull(k,k), ifnull(l,l), ifnull(m,m), ifnull(n,n), ifnull(o,o) from t1;
 show create table t2;
diff --git a/mysql-test/r/func_weight_string.result b/mysql-test/r/func_weight_string.result
index 04fd996..5fa78c8 100644
--- a/mysql-test/r/func_weight_string.result
+++ b/mysql-test/r/func_weight_string.result
@@ -57,7 +57,7 @@ create table t1 select weight_string(repeat('t',66000)) as w;
 show create table t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (
-  `w` longblob DEFAULT NULL
+  `w` mediumblob DEFAULT NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 drop table t1;
 select weight_string(NULL);
diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result
index 6a7b7e7..9be5bac 100644
--- a/mysql-test/r/gis.result
+++ b/mysql-test/r/gis.result
@@ -709,7 +709,7 @@ def	test	t1	t1	g	g	255	4294967295	0	Y	144	0	63
 g
 select asbinary(g) from t1;
 Catalog	Database	Table	Table_alias	Column	Column_alias	Type	Length	Max length	Is_null	Flags	Decimals	Charsetnr
-def					asbinary(g)	252	4294967295	0	Y	128	0	63
+def					asbinary(g)	251	4294967295	0	Y	128	0	63
 asbinary(g)
 drop table t1;
 create table t1 (a TEXT, b GEOMETRY NOT NULL, SPATIAL KEY(b));
diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result
index 0ff5c32..8bbdfb2 100644
--- a/mysql-test/r/null.result
+++ b/mysql-test/r/null.result
@@ -575,8 +575,14 @@ c_float      FLOAT,
 c_double     DOUBLE,
 c_decimal103 DECIMAL(10,3),
 c_varchar10  VARCHAR(10),
+c_tinytext   TINYTEXT,
 c_text       TEXT,
+c_mediumtext MEDIUMTEXT,
+c_longtext   LONGTEXT,
+c_tinyblob   TINYBLOB,
 c_blob       BLOB,
+c_mediumblob MEDIUMBLOB,
+c_longblob   LONGBLOB,
 c_enum       ENUM('one','two','tree'),
 c_datetime3  DATETIME(3),
 c_timestamp3 TIMESTAMP(3),
@@ -899,6 +905,45 @@ t2	CREATE TABLE `t2` (
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 DROP TABLE t2;
 CREATE TABLE t2 AS SELECT
+NULLIF(c_tinytext,  1),
+NULLIF(c_tinytext,  c_smallint),
+NULLIF(c_tinytext,  c_tinyint),
+NULLIF(c_tinytext,  c_int),
+NULLIF(c_tinytext,  c_bigint),
+NULLIF(c_tinytext,  c_float),
+NULLIF(c_tinytext,  c_double),
+NULLIF(c_tinytext,  c_decimal103),
+NULLIF(c_tinytext,  c_varchar10),
+NULLIF(c_tinytext,  c_text),
+NULLIF(c_tinytext,  c_blob),
+NULLIF(c_tinytext,  c_enum),
+NULLIF(c_tinytext,  c_datetime3),
+NULLIF(c_tinytext,  c_timestamp3),
+NULLIF(c_tinytext,  c_date),
+NULLIF(c_tinytext,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `NULLIF(c_tinytext,  1)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_smallint)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_tinyint)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_int)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_bigint)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_float)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_double)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_decimal103)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_varchar10)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_text)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_blob)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_enum)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_datetime3)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_timestamp3)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_date)` tinytext DEFAULT NULL,
+  `NULLIF(c_tinytext,  c_time)` tinytext DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT
 NULLIF(c_text,  1),
 NULLIF(c_text,  c_smallint),
 NULLIF(c_text,  c_tinyint),
@@ -919,22 +964,139 @@ FROM t1;
 SHOW CREATE TABLE t2;
 Table	Create Table
 t2	CREATE TABLE `t2` (
-  `NULLIF(c_text,  1)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_smallint)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_tinyint)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_int)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_bigint)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_float)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_double)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_decimal103)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_varchar10)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_text)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_blob)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_enum)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_datetime3)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_timestamp3)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_date)` longtext DEFAULT NULL,
-  `NULLIF(c_text,  c_time)` longtext DEFAULT NULL
+  `NULLIF(c_text,  1)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_smallint)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_tinyint)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_int)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_bigint)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_float)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_double)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_decimal103)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_varchar10)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_text)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_blob)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_enum)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_datetime3)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_timestamp3)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_date)` text DEFAULT NULL,
+  `NULLIF(c_text,  c_time)` text DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT
+NULLIF(c_mediumtext,  1),
+NULLIF(c_mediumtext,  c_smallint),
+NULLIF(c_mediumtext,  c_tinyint),
+NULLIF(c_mediumtext,  c_int),
+NULLIF(c_mediumtext,  c_bigint),
+NULLIF(c_mediumtext,  c_float),
+NULLIF(c_mediumtext,  c_double),
+NULLIF(c_mediumtext,  c_decimal103),
+NULLIF(c_mediumtext,  c_varchar10),
+NULLIF(c_mediumtext,  c_text),
+NULLIF(c_mediumtext,  c_blob),
+NULLIF(c_mediumtext,  c_enum),
+NULLIF(c_mediumtext,  c_datetime3),
+NULLIF(c_mediumtext,  c_timestamp3),
+NULLIF(c_mediumtext,  c_date),
+NULLIF(c_mediumtext,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `NULLIF(c_mediumtext,  1)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_smallint)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_tinyint)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_int)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_bigint)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_float)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_double)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_decimal103)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_varchar10)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_text)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_blob)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_enum)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_datetime3)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_timestamp3)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_date)` mediumtext DEFAULT NULL,
+  `NULLIF(c_mediumtext,  c_time)` mediumtext DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT
+NULLIF(c_longtext,  1),
+NULLIF(c_longtext,  c_smallint),
+NULLIF(c_longtext,  c_tinyint),
+NULLIF(c_longtext,  c_int),
+NULLIF(c_longtext,  c_bigint),
+NULLIF(c_longtext,  c_float),
+NULLIF(c_longtext,  c_double),
+NULLIF(c_longtext,  c_decimal103),
+NULLIF(c_longtext,  c_varchar10),
+NULLIF(c_longtext,  c_text),
+NULLIF(c_longtext,  c_blob),
+NULLIF(c_longtext,  c_enum),
+NULLIF(c_longtext,  c_datetime3),
+NULLIF(c_longtext,  c_timestamp3),
+NULLIF(c_longtext,  c_date),
+NULLIF(c_longtext,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `NULLIF(c_longtext,  1)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_smallint)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_tinyint)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_int)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_bigint)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_float)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_double)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_decimal103)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_varchar10)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_text)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_blob)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_enum)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_datetime3)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_timestamp3)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_date)` longtext DEFAULT NULL,
+  `NULLIF(c_longtext,  c_time)` longtext DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT
+NULLIF(c_tinyblob,  1),
+NULLIF(c_tinyblob,  c_smallint),
+NULLIF(c_tinyblob,  c_tinyint),
+NULLIF(c_tinyblob,  c_int),
+NULLIF(c_tinyblob,  c_bigint),
+NULLIF(c_tinyblob,  c_float),
+NULLIF(c_tinyblob,  c_double),
+NULLIF(c_tinyblob,  c_decimal103),
+NULLIF(c_tinyblob,  c_varchar10),
+NULLIF(c_tinyblob,  c_text),
+NULLIF(c_tinyblob,  c_blob),
+NULLIF(c_tinyblob,  c_enum),
+NULLIF(c_tinyblob,  c_datetime3),
+NULLIF(c_tinyblob,  c_timestamp3),
+NULLIF(c_tinyblob,  c_date),
+NULLIF(c_tinyblob,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `NULLIF(c_tinyblob,  1)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_smallint)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_tinyint)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_int)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_bigint)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_float)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_double)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_decimal103)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_varchar10)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_text)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_blob)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_enum)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_datetime3)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_timestamp3)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_date)` tinyblob DEFAULT NULL,
+  `NULLIF(c_tinyblob,  c_time)` tinyblob DEFAULT NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 DROP TABLE t2;
 CREATE TABLE t2 AS SELECT
@@ -958,22 +1120,100 @@ FROM t1;
 SHOW CREATE TABLE t2;
 Table	Create Table
 t2	CREATE TABLE `t2` (
-  `NULLIF(c_blob,  1)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_smallint)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_tinyint)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_int)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_bigint)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_float)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_double)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_decimal103)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_varchar10)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_text)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_blob)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_enum)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_datetime3)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_timestamp3)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_date)` longblob DEFAULT NULL,
-  `NULLIF(c_blob,  c_time)` longblob DEFAULT NULL
+  `NULLIF(c_blob,  1)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_smallint)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_tinyint)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_int)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_bigint)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_float)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_double)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_decimal103)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_varchar10)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_text)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_blob)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_enum)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_datetime3)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_timestamp3)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_date)` blob DEFAULT NULL,
+  `NULLIF(c_blob,  c_time)` blob DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT
+NULLIF(c_mediumblob,  1),
+NULLIF(c_mediumblob,  c_smallint),
+NULLIF(c_mediumblob,  c_tinyint),
+NULLIF(c_mediumblob,  c_int),
+NULLIF(c_mediumblob,  c_bigint),
+NULLIF(c_mediumblob,  c_float),
+NULLIF(c_mediumblob,  c_double),
+NULLIF(c_mediumblob,  c_decimal103),
+NULLIF(c_mediumblob,  c_varchar10),
+NULLIF(c_mediumblob,  c_text),
+NULLIF(c_mediumblob,  c_blob),
+NULLIF(c_mediumblob,  c_enum),
+NULLIF(c_mediumblob,  c_datetime3),
+NULLIF(c_mediumblob,  c_timestamp3),
+NULLIF(c_mediumblob,  c_date),
+NULLIF(c_mediumblob,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `NULLIF(c_mediumblob,  1)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_smallint)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_tinyint)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_int)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_bigint)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_float)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_double)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_decimal103)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_varchar10)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_text)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_blob)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_enum)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_datetime3)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_timestamp3)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_date)` mediumblob DEFAULT NULL,
+  `NULLIF(c_mediumblob,  c_time)` mediumblob DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT
+NULLIF(c_longblob,  1),
+NULLIF(c_longblob,  c_smallint),
+NULLIF(c_longblob,  c_tinyint),
+NULLIF(c_longblob,  c_int),
+NULLIF(c_longblob,  c_bigint),
+NULLIF(c_longblob,  c_float),
+NULLIF(c_longblob,  c_double),
+NULLIF(c_longblob,  c_decimal103),
+NULLIF(c_longblob,  c_varchar10),
+NULLIF(c_longblob,  c_text),
+NULLIF(c_longblob,  c_blob),
+NULLIF(c_longblob,  c_enum),
+NULLIF(c_longblob,  c_datetime3),
+NULLIF(c_longblob,  c_timestamp3),
+NULLIF(c_longblob,  c_date),
+NULLIF(c_longblob,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `NULLIF(c_longblob,  1)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_smallint)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_tinyint)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_int)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_bigint)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_float)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_double)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_decimal103)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_varchar10)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_text)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_blob)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_enum)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_datetime3)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_timestamp3)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_date)` longblob DEFAULT NULL,
+  `NULLIF(c_longblob,  c_time)` longblob DEFAULT NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 DROP TABLE t2;
 CREATE TABLE t2 AS SELECT
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
index fe456e2..807a194 100644
--- a/mysql-test/r/union.result
+++ b/mysql-test/r/union.result
@@ -1449,6 +1449,28 @@ t2	CREATE TABLE `t2` (
   `f8` mediumtext CHARACTER SET utf8 DEFAULT NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 drop table t1, t2;
+CREATE TABLE t1
+(
+c_varchar varchar(1) character set utf8 collate utf8_general_ci,
+c_tinytext tinytext,
+c_text text,
+c_mediumtext mediumtext,
+c_longtext longtext
+);
+CREATE TABLE t2 AS
+SELECT c_tinytext, c_text, c_mediumtext, c_longtext FROM t1
+UNION
+SELECT c_varchar, c_varchar, c_varchar, c_varchar FROM t1;
+SHOW CREATE TABLE t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `c_tinytext` text CHARACTER SET utf8 DEFAULT NULL,
+  `c_text` mediumtext CHARACTER SET utf8 DEFAULT NULL,
+  `c_mediumtext` longtext CHARACTER SET utf8 DEFAULT NULL,
+  `c_longtext` longtext CHARACTER SET utf8 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
 (select avg(1)) union (select avg(1)) union (select avg(1)) union
 (select avg(1)) union (select avg(1)) union (select avg(1)) union
 (select avg(1)) union (select avg(1)) union (select avg(1)) union
diff --git a/mysql-test/suite/innodb_gis/r/1.result b/mysql-test/suite/innodb_gis/r/1.result
index 31579a1..3ab57ba 100644
--- a/mysql-test/suite/innodb_gis/r/1.result
+++ b/mysql-test/suite/innodb_gis/r/1.result
@@ -681,7 +681,7 @@ def	test	t1	t1	g	g	255	4294967295	0	Y	144	0	63
 g
 select ST_asbinary(g) from t1;
 Catalog	Database	Table	Table_alias	Column	Column_alias	Type	Length	Max length	Is_null	Flags	Decimals	Charsetnr
-def					ST_asbinary(g)	252	4294967295	0	Y	128	0	63
+def					ST_asbinary(g)	251	4294967295	0	Y	128	0	63
 ST_asbinary(g)
 drop table t1;
 create table t1 (a TEXT, b GEOMETRY NOT NULL, INDEX(b(5)));
diff --git a/mysql-test/suite/innodb_gis/r/gis.result b/mysql-test/suite/innodb_gis/r/gis.result
index 4257413..beb4115 100644
--- a/mysql-test/suite/innodb_gis/r/gis.result
+++ b/mysql-test/suite/innodb_gis/r/gis.result
@@ -681,7 +681,7 @@ def	test	t1	t1	g	g	255	4294967295	0	Y	144	0	63
 g
 select ST_asbinary(g) from t1;
 Catalog	Database	Table	Table_alias	Column	Column_alias	Type	Length	Max length	Is_null	Flags	Decimals	Charsetnr
-def					ST_asbinary(g)	252	4294967295	0	Y	128	0	63
+def					ST_asbinary(g)	251	4294967295	0	Y	128	0	63
 ST_asbinary(g)
 drop table t1;
 create table t1 (a TEXT, b GEOMETRY NOT NULL, SPATIAL KEY(b));
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index 6461204..bd89f22 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -402,6 +402,22 @@ explain t2;
 select * from t2;
 drop table t1, t2;
 
+CREATE TABLE t1 (
+  c_tinytext tinytext,
+  c_text text,
+  c_mediumtext mediumtext,
+  c_longtext longtext
+);
+CREATE TABLE t2 AS SELECT
+  ifnull(c_tinytext,   CAST('yet another binary data' AS BINARY)),
+  ifnull(c_text,       CAST('yet another binary data' AS BINARY)),
+  ifnull(c_mediumtext, CAST('yet another binary data' AS BINARY)),
+  ifnull(c_longtext,   CAST('yet another binary data' AS BINARY))
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
 create table t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float(3,2), g double(4,3), h decimal(5,4), i year, j date, k timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, l datetime, m enum('a','b'), n set('a','b'), o char(10));
 create table t2 select ifnull(a,a), ifnull(b,b), ifnull(c,c), ifnull(d,d), ifnull(e,e), ifnull(f,f), ifnull(g,g), ifnull(h,h), ifnull(i,i), ifnull(j,j), ifnull(k,k), ifnull(l,l), ifnull(m,m), ifnull(n,n), ifnull(o,o) from t1;
 show create table t2;
diff --git a/mysql-test/t/null.test b/mysql-test/t/null.test
index 3de35a7..4037903 100644
--- a/mysql-test/t/null.test
+++ b/mysql-test/t/null.test
@@ -414,8 +414,14 @@ CREATE TABLE t1
   c_double     DOUBLE,
   c_decimal103 DECIMAL(10,3),
   c_varchar10  VARCHAR(10),
+  c_tinytext   TINYTEXT,
   c_text       TEXT,
+  c_mediumtext MEDIUMTEXT,
+  c_longtext   LONGTEXT,
+  c_tinyblob   TINYBLOB,
   c_blob       BLOB,
+  c_mediumblob MEDIUMBLOB,
+  c_longblob   LONGBLOB,
   c_enum       ENUM('one','two','tree'),
   c_datetime3  DATETIME(3),
   c_timestamp3 TIMESTAMP(3),
@@ -597,6 +603,27 @@ SHOW CREATE TABLE t2;
 DROP TABLE t2;
 
 CREATE TABLE t2 AS SELECT
+  NULLIF(c_tinytext,  1),
+  NULLIF(c_tinytext,  c_smallint),
+  NULLIF(c_tinytext,  c_tinyint),
+  NULLIF(c_tinytext,  c_int),
+  NULLIF(c_tinytext,  c_bigint),
+  NULLIF(c_tinytext,  c_float),
+  NULLIF(c_tinytext,  c_double),
+  NULLIF(c_tinytext,  c_decimal103),
+  NULLIF(c_tinytext,  c_varchar10),
+  NULLIF(c_tinytext,  c_text),
+  NULLIF(c_tinytext,  c_blob),
+  NULLIF(c_tinytext,  c_enum),
+  NULLIF(c_tinytext,  c_datetime3),
+  NULLIF(c_tinytext,  c_timestamp3),
+  NULLIF(c_tinytext,  c_date),
+  NULLIF(c_tinytext,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+CREATE TABLE t2 AS SELECT
   NULLIF(c_text,  1),
   NULLIF(c_text,  c_smallint),
   NULLIF(c_text,  c_tinyint),
@@ -617,7 +644,70 @@ FROM t1;
 SHOW CREATE TABLE t2;
 DROP TABLE t2;
 
-# QQ: this should probably create BLOB instead of LONGBLOB
+CREATE TABLE t2 AS SELECT
+  NULLIF(c_mediumtext,  1),
+  NULLIF(c_mediumtext,  c_smallint),
+  NULLIF(c_mediumtext,  c_tinyint),
+  NULLIF(c_mediumtext,  c_int),
+  NULLIF(c_mediumtext,  c_bigint),
+  NULLIF(c_mediumtext,  c_float),
+  NULLIF(c_mediumtext,  c_double),
+  NULLIF(c_mediumtext,  c_decimal103),
+  NULLIF(c_mediumtext,  c_varchar10),
+  NULLIF(c_mediumtext,  c_text),
+  NULLIF(c_mediumtext,  c_blob),
+  NULLIF(c_mediumtext,  c_enum),
+  NULLIF(c_mediumtext,  c_datetime3),
+  NULLIF(c_mediumtext,  c_timestamp3),
+  NULLIF(c_mediumtext,  c_date),
+  NULLIF(c_mediumtext,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+CREATE TABLE t2 AS SELECT
+  NULLIF(c_longtext,  1),
+  NULLIF(c_longtext,  c_smallint),
+  NULLIF(c_longtext,  c_tinyint),
+  NULLIF(c_longtext,  c_int),
+  NULLIF(c_longtext,  c_bigint),
+  NULLIF(c_longtext,  c_float),
+  NULLIF(c_longtext,  c_double),
+  NULLIF(c_longtext,  c_decimal103),
+  NULLIF(c_longtext,  c_varchar10),
+  NULLIF(c_longtext,  c_text),
+  NULLIF(c_longtext,  c_blob),
+  NULLIF(c_longtext,  c_enum),
+  NULLIF(c_longtext,  c_datetime3),
+  NULLIF(c_longtext,  c_timestamp3),
+  NULLIF(c_longtext,  c_date),
+  NULLIF(c_longtext,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+
+CREATE TABLE t2 AS SELECT
+  NULLIF(c_tinyblob,  1),
+  NULLIF(c_tinyblob,  c_smallint),
+  NULLIF(c_tinyblob,  c_tinyint),
+  NULLIF(c_tinyblob,  c_int),
+  NULLIF(c_tinyblob,  c_bigint),
+  NULLIF(c_tinyblob,  c_float),
+  NULLIF(c_tinyblob,  c_double),
+  NULLIF(c_tinyblob,  c_decimal103),
+  NULLIF(c_tinyblob,  c_varchar10),
+  NULLIF(c_tinyblob,  c_text),
+  NULLIF(c_tinyblob,  c_blob),
+  NULLIF(c_tinyblob,  c_enum),
+  NULLIF(c_tinyblob,  c_datetime3),
+  NULLIF(c_tinyblob,  c_timestamp3),
+  NULLIF(c_tinyblob,  c_date),
+  NULLIF(c_tinyblob,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
 CREATE TABLE t2 AS SELECT
   NULLIF(c_blob,  1),
   NULLIF(c_blob,  c_smallint),
@@ -639,6 +729,49 @@ FROM t1;
 SHOW CREATE TABLE t2;
 DROP TABLE t2;
 
+CREATE TABLE t2 AS SELECT
+  NULLIF(c_mediumblob,  1),
+  NULLIF(c_mediumblob,  c_smallint),
+  NULLIF(c_mediumblob,  c_tinyint),
+  NULLIF(c_mediumblob,  c_int),
+  NULLIF(c_mediumblob,  c_bigint),
+  NULLIF(c_mediumblob,  c_float),
+  NULLIF(c_mediumblob,  c_double),
+  NULLIF(c_mediumblob,  c_decimal103),
+  NULLIF(c_mediumblob,  c_varchar10),
+  NULLIF(c_mediumblob,  c_text),
+  NULLIF(c_mediumblob,  c_blob),
+  NULLIF(c_mediumblob,  c_enum),
+  NULLIF(c_mediumblob,  c_datetime3),
+  NULLIF(c_mediumblob,  c_timestamp3),
+  NULLIF(c_mediumblob,  c_date),
+  NULLIF(c_mediumblob,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+CREATE TABLE t2 AS SELECT
+  NULLIF(c_longblob,  1),
+  NULLIF(c_longblob,  c_smallint),
+  NULLIF(c_longblob,  c_tinyint),
+  NULLIF(c_longblob,  c_int),
+  NULLIF(c_longblob,  c_bigint),
+  NULLIF(c_longblob,  c_float),
+  NULLIF(c_longblob,  c_double),
+  NULLIF(c_longblob,  c_decimal103),
+  NULLIF(c_longblob,  c_varchar10),
+  NULLIF(c_longblob,  c_text),
+  NULLIF(c_longblob,  c_blob),
+  NULLIF(c_longblob,  c_enum),
+  NULLIF(c_longblob,  c_datetime3),
+  NULLIF(c_longblob,  c_timestamp3),
+  NULLIF(c_longblob,  c_date),
+  NULLIF(c_longblob,  c_time)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+
 # QQ: this should probably create a ENUM column instead of VARCHAR(4)
 CREATE TABLE t2 AS SELECT
   NULLIF(c_enum,  1),
diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test
index e0c011e..fa07dc2 100644
--- a/mysql-test/t/union.test
+++ b/mysql-test/t/union.test
@@ -889,6 +889,22 @@ create table t2 as select *, f6 as f8 from t1 union select *, f7 from t1;
 show create table t2;
 drop table t1, t2;
 
+CREATE TABLE t1
+(
+  c_varchar varchar(1) character set utf8 collate utf8_general_ci,
+  c_tinytext tinytext,
+  c_text text,
+  c_mediumtext mediumtext,
+  c_longtext longtext
+);
+CREATE TABLE t2 AS
+SELECT c_tinytext, c_text, c_mediumtext, c_longtext FROM t1
+UNION
+SELECT c_varchar, c_varchar, c_varchar, c_varchar FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
 #
 # Bug#18175: Union select over 129 tables with a sum function fails.
 #
diff --git a/sql/field.cc b/sql/field.cc
index 812c4db..ed14ba3 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2910,68 +2910,6 @@ Field_new_decimal::Field_new_decimal(uchar *ptr_arg,
 }
 
 
-Field_new_decimal::Field_new_decimal(uint32 len_arg,
-                                     bool maybe_null_arg,
-                                     const char *name,
-                                     uint8 dec_arg,
-                                     bool unsigned_arg)
-  :Field_num((uchar*) 0, len_arg,
-             maybe_null_arg ? (uchar*) "": 0, 0,
-             NONE, name, dec_arg, 0, unsigned_arg)
-{
-  precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
-  set_if_smaller(precision, DECIMAL_MAX_PRECISION);
-  DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) &&
-              (dec <= DECIMAL_MAX_SCALE));
-  bin_size= my_decimal_get_binary_size(precision, dec);
-}
-
-
-Field *Field_new_decimal::create_from_item(MEM_ROOT *mem_root, Item *item)
-{
-  uint8 dec= item->decimals;
-  uint8 intg= item->decimal_precision() - dec;
-  uint32 len= item->max_char_length();
-
-  DBUG_ASSERT (item->result_type() == DECIMAL_RESULT);
-
-  /*
-    Trying to put too many digits overall in a DECIMAL(prec,dec)
-    will always throw a warning. We must limit dec to
-    DECIMAL_MAX_SCALE however to prevent an assert() later.
-  */
-
-  if (dec > 0)
-  {
-    signed int overflow;
-
-    dec= MY_MIN(dec, DECIMAL_MAX_SCALE);
-
-    /*
-      If the value still overflows the field with the corrected dec,
-      we'll throw out decimals rather than integers. This is still
-      bad and of course throws a truncation warning.
-      +1: for decimal point
-      */
-
-    const int required_length=
-      my_decimal_precision_to_length(intg + dec, dec,
-                                     item->unsigned_flag);
-
-    overflow= required_length - len;
-
-    if (overflow > 0)
-      dec= MY_MAX(0, dec - overflow);            // too long, discard fract
-    else
-      /* Corrected value fits. */
-      len= required_length;
-  }
-  return new (mem_root)
-    Field_new_decimal(len, item->maybe_null, item->name,
-                      dec, item->unsigned_flag);
-}
-
-
 int Field_new_decimal::reset(void)
 {
   store_value(&decimal_zero);
diff --git a/sql/field.h b/sql/field.h
index 9559ba7..26ea849 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -969,6 +969,10 @@ class Field: public Value_source
   virtual bool zero_pack() const { return 1; }
   virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
   virtual uint32 key_length() const { return pack_length(); }
+  virtual const Type_handler *type_handler() const
+  {
+    return Type_handler::get_handler_by_field_type(type());
+  }
   virtual enum_field_types type() const =0;
   virtual enum_field_types real_type() const { return type(); }
   virtual enum_field_types binlog_type() const
@@ -1839,9 +1843,6 @@ class Field_new_decimal :public Field_num {
                     uchar null_bit_arg,
                     enum utype unireg_check_arg, const char *field_name_arg,
                     uint8 dec_arg, bool zero_arg, bool unsigned_arg);
-  Field_new_decimal(uint32 len_arg, bool maybe_null_arg,
-                    const char *field_name_arg, uint8 dec_arg,
-                    bool unsigned_arg);
   enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;}
   enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
   Item_result result_type () const { return DECIMAL_RESULT; }
@@ -1894,7 +1895,6 @@ class Field_new_decimal :public Field_num {
                              uint16 mflags, int *order_var);
   uint is_equal(Create_field *new_field);
   virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data);
-  static Field *create_from_item(MEM_ROOT *root, Item *);
   Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
 };
 
@@ -3217,6 +3217,15 @@ class Field_blob :public Field_longstr {
   Field_blob(uint32 packlength_arg)
     :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, "temp", system_charset_info),
     packlength(packlength_arg) {}
+  const Type_handler *type_handler() const
+  {
+    switch (packlength) {
+    case 1: return &type_handler_tiny_blob;
+    case 2: return &type_handler_blob;
+    case 3: return &type_handler_medium_blob;
+    }
+    return &type_handler_long_blob;
+  }
   /* Note that the default copy constructor is used, in clone() */
   enum_field_types type() const { return MYSQL_TYPE_BLOB;}
   enum ha_base_keytype key_type() const
@@ -3403,11 +3412,11 @@ class Field_geom :public Field_blob {
      :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, 
                  field_name_arg, share, blob_pack_length, &my_charset_bin)
   { geom_type= geom_type_arg; srid= field_srid; }
-  Field_geom(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
-	     TABLE_SHARE *share, enum geometry_type geom_type_arg)
-    :Field_blob(len_arg, maybe_null_arg, field_name_arg, &my_charset_bin)
-  { geom_type= geom_type_arg; srid= 0; }
   enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; }
+  const Type_handler *type_handler() const
+  {
+    return &type_handler_geometry;
+  }
   enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; }
   bool can_optimize_range(const Item_bool_func *cond,
                                   const Item *item,
diff --git a/sql/item.cc b/sql/item.cc
index b99b3a2..6f2f4e5 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -509,7 +509,7 @@ Item::Item(THD *thd):
   tables.
 */
 Item::Item(THD *thd, Item *item):
-  Type_std_attributes(item),
+  Type_all_attributes(item),
   join_tab_idx(item->join_tab_idx),
   is_expensive_cache(-1),
   rsize(0),
@@ -5852,6 +5852,8 @@ const Type_handler *Item_field::real_type_handler() const
   // TODO: We should add Field::real_type_handler() eventually
   if (type == MYSQL_TYPE_STRING && field->type() == MYSQL_TYPE_VAR_STRING)
     type= MYSQL_TYPE_VAR_STRING;
+  else if (type == MYSQL_TYPE_BLOB)
+    return field->type_handler();
   return Type_handler::get_handler_by_real_type(type);
 
 }
@@ -6276,119 +6278,23 @@ Field *Item::make_string_field(TABLE *table)
     \#    Created field
 */
 
-Field *Item::tmp_table_field_from_field_type(TABLE *table,
-                                             bool fixed_length,
-                                             bool set_blob_packlength)
+Field *Item::tmp_table_field_from_field_type(TABLE *table)
 {
-  /*
-    The field functions defines a field to be not null if null_ptr is not 0
-  */
-  uchar *null_ptr= maybe_null ? (uchar*) "" : 0;
-  Field *field;
-  MEM_ROOT *mem_root= table->in_use->mem_root;
+  const Type_handler *handler= type_handler();
+  Record_addr addr(maybe_null);
 
-  switch (field_type()) {
-  case MYSQL_TYPE_DECIMAL:
-  case MYSQL_TYPE_NEWDECIMAL:
-    field= Field_new_decimal::create_from_item(mem_root, this);
-    break;
-  case MYSQL_TYPE_TINY:
-    field= new (mem_root)
-      Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-                 name, 0, unsigned_flag);
-    break;
-  case MYSQL_TYPE_SHORT:
-    field= new (mem_root)
-      Field_short((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-                  name, 0, unsigned_flag);
-    break;
-  case MYSQL_TYPE_LONG:
-    field= new (mem_root)
-      Field_long((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-                 name, 0, unsigned_flag);
-    break;
-#ifdef HAVE_LONG_LONG
-  case MYSQL_TYPE_LONGLONG:
-    field= new (mem_root)
-      Field_longlong((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-                     name, 0, unsigned_flag);
-    break;
-#endif
-  case MYSQL_TYPE_FLOAT:
-    field= new (mem_root)
-      Field_float((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-                  name, decimals, 0, unsigned_flag);
-    break;
-  case MYSQL_TYPE_DOUBLE:
-    field= new (mem_root)
-      Field_double((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-                   name, decimals, 0, unsigned_flag);
-    break;
-  case MYSQL_TYPE_INT24:
-    field= new (mem_root)
-      Field_medium((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-                   name, 0, unsigned_flag);
-    break;
-  case MYSQL_TYPE_NEWDATE:
-  case MYSQL_TYPE_DATE:
-    field= new (mem_root)
-      Field_newdate(0, null_ptr, 0, Field::NONE, name);
-    break;
-  case MYSQL_TYPE_TIME:
-    field= new_Field_time(mem_root, 0, null_ptr, 0, Field::NONE, name,
-                          decimals);
-    break;
-  case MYSQL_TYPE_TIMESTAMP:
-    field= new_Field_timestamp(mem_root, 0, null_ptr, 0,
-                               Field::NONE, name, 0, decimals);
-    break;
-  case MYSQL_TYPE_DATETIME:
-    field= new_Field_datetime(mem_root, 0, null_ptr, 0, Field::NONE, name,
-                              decimals);
-    break;
-  case MYSQL_TYPE_YEAR:
-    field= new (mem_root)
-      Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE, name);
-    break;
-  case MYSQL_TYPE_BIT:
-    field= new (mem_root)
-      Field_bit_as_char(NULL, max_length, null_ptr, 0, Field::NONE, name);
-    break;
-  default:
-    /* This case should never be chosen */
-    DBUG_ASSERT(0);
-    /* If something goes awfully wrong, it's better to get a string than die */
+  switch (handler->field_type()) {
   case MYSQL_TYPE_NULL:
   case MYSQL_TYPE_STRING:
-    if (fixed_length && !too_big_for_varchar())
-    {
-      field= new (mem_root)
-        Field_string(max_length, maybe_null, name, collation.collation);
-      break;
-    }
-    /* Fall through to make_string_field() */
   case MYSQL_TYPE_ENUM:
   case MYSQL_TYPE_SET:
   case MYSQL_TYPE_VAR_STRING:
   case MYSQL_TYPE_VARCHAR:
     return make_string_field(table);
-  case MYSQL_TYPE_TINY_BLOB:
-  case MYSQL_TYPE_MEDIUM_BLOB:
-  case MYSQL_TYPE_LONG_BLOB:
-  case MYSQL_TYPE_BLOB:
-    field= new (mem_root)
-           Field_blob(max_length, maybe_null, name,
-                      collation.collation, set_blob_packlength);
-    break;					// Blob handled outside of case
-#ifdef HAVE_SPATIAL
-  case MYSQL_TYPE_GEOMETRY:
-    field= new (mem_root)
-      Field_geom(max_length, maybe_null, name, table->s, get_geometry_type());
-#endif /* HAVE_SPATIAL */
+  default:
+    break;
   }
-  if (field)
-    field->init(table);
-  return field;
+  return handler->make_and_init_table_field(name, addr, *this, table);
 }
 
 
@@ -10407,10 +10313,16 @@ Field *Item_type_holder::make_field_by_type(TABLE *table)
     return field;
   case MYSQL_TYPE_NULL:
     return make_string_field(table);
+  case MYSQL_TYPE_TINY_BLOB:
+  case MYSQL_TYPE_BLOB:
+  case MYSQL_TYPE_MEDIUM_BLOB:
+  case MYSQL_TYPE_LONG_BLOB:
+    set_handler(Type_handler::blob_type_handler(max_length));
+    break;    
   default:
     break;
   }
-  return tmp_table_field_from_field_type(table, false, true);
+  return tmp_table_field_from_field_type(table);
 }
 
 
diff --git a/sql/item.h b/sql/item.h
index bd24b64..978aa53 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -482,7 +482,7 @@ class String_copier_for_item: public String_copier
 
 
 class Item: public Value_source,
-            public Type_std_attributes
+            public Type_all_attributes
 {
   void operator=(Item &);
   /**
@@ -536,9 +536,7 @@ class Item: public Value_source,
   SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param);
 
   virtual Field *make_string_field(TABLE *table);
-  Field *tmp_table_field_from_field_type(TABLE *table,
-                                         bool fixed_length,
-                                         bool set_blob_packlength);
+  Field *tmp_table_field_from_field_type(TABLE *table);
   Field *create_tmp_field(bool group, TABLE *table, uint convert_int_length);
 
   void push_note_converted_to_negative_complement(THD *thd);
@@ -1740,6 +1738,8 @@ class Item: public Value_source,
   }
   virtual Field::geometry_type get_geometry_type() const
     { return Field::GEOM_GEOMETRY; };
+  uint uint_geometry_type() const
+  { return get_geometry_type(); }
   String *check_well_formed_result(String *str, bool send_error= 0);
   bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs); 
   bool too_big_for_varchar() const
@@ -2266,7 +2266,7 @@ class Item_splocal_with_delayed_data_type: public Item_splocal
     based on result_type(), which is less exact.
   */
   Field *create_field_for_create_select(TABLE *table)
-  { return tmp_table_field_from_field_type(table, false, true); }
+  { return tmp_table_field_from_field_type(table); }
 };
 
 
@@ -2642,6 +2642,10 @@ class Item_field :public Item_ident
   fast_field_copier setup_fast_field_copier(Field *field);
   table_map used_tables() const;
   table_map all_used_tables() const; 
+  const Type_handler *type_handler() const
+  {
+    return field->type_handler();
+  }
   enum Item_result result_type () const
   {
     return field->result_type();
@@ -3635,7 +3639,14 @@ class Item_blob :public Item_partition_func_safe_string
     Item_partition_func_safe_string(thd, name_arg, strlen(name_arg), &my_charset_bin)
   { max_length= length; }
   enum Type type() const { return TYPE_HOLDER; }
-  enum_field_types field_type() const { return MYSQL_TYPE_BLOB; }
+  enum_field_types field_type() const
+  {
+    return Item_blob::type_handler()->field_type();
+  }
+  const Type_handler *type_handler() const
+  {
+    return Type_handler::blob_type_handler(max_length);
+  }
   const Type_handler *real_type_handler() const
   {
     // Should not be called, Item_blob is used for SHOW purposes only.
@@ -3643,7 +3654,7 @@ class Item_blob :public Item_partition_func_safe_string
     return &type_handler_varchar;
   }
   Field *create_field_for_schema(THD *thd, TABLE *table)
-  { return tmp_table_field_from_field_type(table, false, true); }
+  { return tmp_table_field_from_field_type(table); }
 };
 
 
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 6d2135d..6712b98 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2577,7 +2577,7 @@ Item_func_nullif::fix_length_and_dec()
     thd->change_item_tree(&args[0], m_cache);
     thd->change_item_tree(&args[2], m_cache);
   }
-  set_handler_by_field_type(args[2]->field_type());
+  set_handler(args[2]->type_handler());
   collation.set(args[2]->collation);
   decimals= args[2]->decimals;
   unsigned_flag= args[2]->unsigned_flag;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index a94105b..6a6adb2 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1057,7 +1057,7 @@ class Item_func_ifnull :public Item_func_case_abbreviation2
   }
   const char *func_name() const { return "ifnull"; }
   Field *create_field_for_create_select(TABLE *table)
-  { return tmp_table_field_from_field_type(table, false, false); }
+  { return tmp_table_field_from_field_type(table); }
 
   table_map not_null_tables() const { return 0; }
   uint decimal_precision() const
diff --git a/sql/item_func.h b/sql/item_func.h
index a367a0d..bb6b680 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -208,7 +208,7 @@ class Item_func :public Item_func_or_sum
   {
     return result_type() != STRING_RESULT ?
            create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS) :
-           tmp_table_field_from_field_type(table, false, false);
+           tmp_table_field_from_field_type(table);
   }
   Item *get_tmp_table_item(THD *thd);
 
@@ -2229,12 +2229,6 @@ class Item_func_set_user_var :public Item_func_user_var
   bool update();
   bool fix_fields(THD *thd, Item **ref);
   void fix_length_and_dec();
-  Field *create_field_for_create_select(TABLE *table)
-  {
-    return result_type() != STRING_RESULT ?
-           create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS) :
-           tmp_table_field_from_field_type(table, false, true);
-  }
   table_map used_tables() const
   {
     return used_tables_cache | RAND_TABLE_BIT;
@@ -2276,6 +2270,14 @@ class Item_func_get_user_var :public Item_func_user_var,
   my_decimal *val_decimal(my_decimal*);
   String *val_str(String* str);
   void fix_length_and_dec();
+  Field *create_field_for_create_select(TABLE *table)
+  {
+    return cmp_type() == STRING_RESULT ?
+      type_handler_long_blob.make_and_init_table_field(Item::name,
+                                                       Record_addr(maybe_null),
+                                                       *this, table) :
+      create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS);
+  }
   virtual void print(String *str, enum_query_type query_type);
   /*
     We must always return variables as strings to guard against selects of type
@@ -2628,7 +2630,7 @@ class Item_func_sp :public Item_func
   {
     return result_type() != STRING_RESULT ?
            sp_result_field :
-           tmp_table_field_from_field_type(table, false, false);
+           tmp_table_field_from_field_type(table);
   }
   void make_field(THD *thd, Send_field *tmp_field);
 
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 7ac2e05..4fa0631 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -40,15 +40,6 @@
 #include "opt_range.h"
 
 
-Field *Item_geometry_func::create_field_for_create_select(TABLE *t_arg)
-{
-  Field *result;
-  if ((result= new Field_geom(max_length, maybe_null, name, t_arg->s,
-                              get_geometry_type())))
-    result->init(t_arg);
-  return result;
-}
-
 void Item_geometry_func::fix_length_and_dec()
 {
   collation.set(&my_charset_bin);
@@ -206,7 +197,7 @@ String *Item_func_as_wkt::val_str_ascii(String *str)
 void Item_func_as_wkt::fix_length_and_dec()
 {
   collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
-  max_length=MAX_BLOB_WIDTH;
+  max_length= 4294967295U;
   maybe_null= 1;
 }
 
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index a164f9d..b6a49a3 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -40,7 +40,6 @@ class Item_geometry_func: public Item_str_func
   Item_geometry_func(THD *thd, List<Item> &list): Item_str_func(thd, list) {}
   void fix_length_and_dec();
   enum_field_types field_type() const  { return MYSQL_TYPE_GEOMETRY; }
-  Field *create_field_for_create_select(TABLE *table);
 };
 
 class Item_func_geometry_from_text: public Item_geometry_func
@@ -101,7 +100,7 @@ class Item_func_as_wkb: public Item_geometry_func
   Item_func_as_wkb(THD *thd, Item *a): Item_geometry_func(thd, a) {}
   const char *func_name() const { return "st_aswkb"; }
   String *val_str(String *);
-  enum_field_types field_type() const  { return MYSQL_TYPE_BLOB; }
+  enum_field_types field_type() const  { return MYSQL_TYPE_LONG_BLOB; }
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_func_as_wkb>(thd, mem_root, this); }
 };
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index b1c797c..6760471 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1663,8 +1663,6 @@ Item *Item_sum_avg::copy_or_same(THD* thd)
 
 Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table)
 {
-  Field *field;
-  MEM_ROOT *mem_root= table->in_use->mem_root;
 
   if (group)
   {
@@ -1673,19 +1671,15 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table)
       The easiest way is to do this is to store both value in a string
       and unpack on access.
     */
-    field= new (mem_root)
+    Field *field= new (table->in_use->mem_root)
       Field_string(((Item_sum_avg::result_type() == DECIMAL_RESULT) ?
                     dec_bin_size : sizeof(double)) + sizeof(longlong),
                    0, name, &my_charset_bin);
+    if (field)
+      field->init(table);
+    return field;
   }
-  else if (Item_sum_avg::result_type() == DECIMAL_RESULT)
-    field= Field_new_decimal::create_from_item(mem_root, this);
-  else
-    field= new (mem_root) Field_double(max_length, maybe_null, name, decimals,
-                                       TRUE);
-  if (field)
-    field->init(table);
-  return field;
+  return tmp_table_field_from_field_type(table);
 }
 
 
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 40b8c16..4eb22bd 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -535,7 +535,7 @@ class Item_temporal_func: public Item_func
   my_decimal *val_decimal(my_decimal *decimal_value)
   { return  val_decimal_from_date(decimal_value); }
   Field *create_field_for_create_select(TABLE *table)
-  { return tmp_table_field_from_field_type(table, false, false); }
+  { return tmp_table_field_from_field_type(table); }
   int save_in_field(Field *field, bool no_conversions)
   { return save_date_in_field(field, no_conversions); }
 };
@@ -1013,7 +1013,7 @@ class Item_extract :public Item_int_func
     return true;
   }
   Field *create_field_for_create_select(TABLE *table)
-  { return tmp_table_field_from_field_type(table, false, false); }
+  { return tmp_table_field_from_field_type(table); }
 
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_extract>(thd, mem_root, this); }
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 47c0302..1e88e82 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -15875,7 +15875,8 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length)
         Field_long(max_char_length(), maybe_null, name, unsigned_flag);
     break;
   case TIME_RESULT:
-    new_field= tmp_table_field_from_field_type(table, true, false);
+  case DECIMAL_RESULT:
+    new_field= tmp_table_field_from_field_type(table);
     break;
   case STRING_RESULT:
     DBUG_ASSERT(collation.collation);
@@ -15884,14 +15885,11 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length)
       To preserve type they needed to be handled separately.
     */
     if (field_type() == MYSQL_TYPE_GEOMETRY)
-      new_field= tmp_table_field_from_field_type(table, true, false);
+      new_field= tmp_table_field_from_field_type(table);
     else
       new_field= make_string_field(table);
     new_field->set_derivation(collation.derivation, collation.repertoire);
     break;
-  case DECIMAL_RESULT:
-    new_field= Field_new_decimal::create_from_item(mem_root, this);
-    break;
   case ROW_RESULT:
     // This case should never be choosen
     DBUG_ASSERT(0);
@@ -15975,7 +15973,7 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table)
       field->init(table);
     return field;
   }
-  return tmp_table_field_from_field_type(table, false, false);
+  return tmp_table_field_from_field_type(table);
 }
 
 
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index cf5e4e4..8197e22 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -30,10 +30,6 @@ static Type_handler_date        type_handler_date;
 static Type_handler_timestamp   type_handler_timestamp;
 static Type_handler_timestamp2  type_handler_timestamp2;
 static Type_handler_olddecimal  type_handler_olddecimal;
-static Type_handler_tiny_blob   type_handler_tiny_blob;
-static Type_handler_medium_blob type_handler_medium_blob;
-static Type_handler_long_blob   type_handler_long_blob;
-static Type_handler_blob        type_handler_blob;
 
 
 Type_handler_null        type_handler_null;
@@ -53,6 +49,11 @@ Type_handler_time2       type_handler_time2;
 Type_handler_newdate     type_handler_newdate;
 Type_handler_datetime2   type_handler_datetime2;
 
+Type_handler_tiny_blob   type_handler_tiny_blob;
+Type_handler_medium_blob type_handler_medium_blob;
+Type_handler_long_blob   type_handler_long_blob;
+Type_handler_blob        type_handler_blob;
+
 #ifdef HAVE_SPATIAL
 Type_handler_geometry    type_handler_geometry;
 #endif
@@ -80,9 +81,18 @@ bool Type_handler_data::init()
                                      &type_handler_geometry,
                                      &type_handler_geometry) ||
     m_type_aggregator_for_result.add(&type_handler_geometry,
+                                     &type_handler_tiny_blob,
+                                     &type_handler_long_blob) ||
+    m_type_aggregator_for_result.add(&type_handler_geometry,
                                      &type_handler_blob,
                                      &type_handler_long_blob) ||
     m_type_aggregator_for_result.add(&type_handler_geometry,
+                                     &type_handler_medium_blob,
+                                     &type_handler_long_blob) ||
+    m_type_aggregator_for_result.add(&type_handler_geometry,
+                                     &type_handler_long_blob,
+                                     &type_handler_long_blob) ||
+    m_type_aggregator_for_result.add(&type_handler_geometry,
                                      &type_handler_varchar,
                                      &type_handler_long_blob) ||
     m_type_aggregator_for_result.add(&type_handler_geometry,
@@ -139,6 +149,19 @@ Type_handler::string_type_handler(uint max_octet_length)
 }
 
 
+const Type_handler *
+Type_handler::blob_type_handler(uint max_octet_length)
+{
+  if (max_octet_length <= 255)
+    return &type_handler_tiny_blob;
+  if (max_octet_length <= 65535)
+    return &type_handler_blob;
+  if (max_octet_length <= 16777215)
+    return &type_handler_medium_blob;
+  return &type_handler_long_blob;
+}
+
+
 /**
   This method is used by:
   - Item_sum_hybrid, e.g. MAX(item), MIN(item).
@@ -1067,6 +1090,423 @@ Field *Type_handler_set::make_conversion_table_field(TABLE *table,
 }
 
 /*************************************************************************/
+Field *Type_handler::make_and_init_table_field(const LEX_CSTRING *name,
+                                               const Record_addr &addr,
+                                               const Type_all_attributes &attr,
+                                               TABLE *table) const
+{
+  Field *field= make_table_field(name, addr, attr, table);
+  if (field)
+    field->init(table);
+  return field;
+}
+
+
+Field *Type_handler_tiny::make_table_field(const LEX_CSTRING *name,
+                                           const Record_addr &addr,
+                                           const Type_all_attributes &attr,
+                                           TABLE *table) const
+{
+  return new (table->in_use->mem_root)
+         Field_tiny(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+                    Field::NONE, name->str, 0/*zerofill*/, attr.unsigned_flag);
+}
+
+
+Field *Type_handler_short::make_table_field(const LEX_CSTRING *name,
+                                           const Record_addr &addr,
+                                           const Type_all_attributes &attr,
+                                           TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_short(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+                     Field::NONE, name->str, 0/*zerofill*/, attr.unsigned_flag);
+}
+
+
+Field *Type_handler_int24::make_table_field(const LEX_CSTRING *name,
+                                            const Record_addr &addr,
+                                            const Type_all_attributes &attr,
+                                            TABLE *table) const
+{
+  return new (table->in_use->mem_root)
+         Field_medium(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+                      Field::NONE, name->str,
+                      0/*zerofill*/, attr.unsigned_flag);
+}
+
+
+Field *Type_handler_long::make_table_field(const LEX_CSTRING *name,
+                                           const Record_addr &addr,
+                                           const Type_all_attributes &attr,
+                                           TABLE *table) const
+{
+  return new (table->in_use->mem_root)
+         Field_long(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+                    Field::NONE, name->str, 0/*zerofill*/, attr.unsigned_flag);
+}
+
+
+Field *Type_handler_longlong::make_table_field(const LEX_CSTRING *name,
+                                               const Record_addr &addr,
+                                               const Type_all_attributes &attr,
+                                               TABLE *table) const
+{
+  return new (table->in_use->mem_root)
+         Field_longlong(addr.ptr, attr.max_length,
+                        addr.null_ptr, addr.null_bit,
+                        Field::NONE, name->str,
+                        0/*zerofill*/, attr.unsigned_flag);
+}
+
+
+Field *Type_handler_float::make_table_field(const LEX_CSTRING *name,
+                                            const Record_addr &addr,
+                                            const Type_all_attributes &attr,
+                                            TABLE *table) const
+{
+  return new (table->in_use->mem_root)
+         Field_float(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+                     Field::NONE, name->str,
+                     attr.decimals, 0/*zerofill*/, attr.unsigned_flag);
+}
+
+
+Field *Type_handler_double::make_table_field(const LEX_CSTRING *name,
+                                             const Record_addr &addr,
+                                             const Type_all_attributes &attr,
+                                             TABLE *table) const
+{
+  return new (table->in_use->mem_root)
+         Field_double(addr.ptr, attr.max_length,
+                      addr.null_ptr, addr.null_bit,
+                      Field::NONE, name->str,
+                      attr.decimals, 0/*zerofill*/, attr.unsigned_flag);
+}
+
+
+Field *
+Type_handler_olddecimal::make_table_field(const LEX_CSTRING *name,
+                                          const Record_addr &addr,
+                                          const Type_all_attributes &attr,
+                                          TABLE *table) const
+{
+  /*
+    Currently make_table_field() is used for Item purpose only.
+    On Item level we have type_handler_newdecimal only.
+    Will be implemented when we reuse Type_handler::make_table_field()
+    in make_field() in field.cc, to open old tables with old decimal.
+  */
+  DBUG_ASSERT(0);
+  return NULL;
+}
+
+
+Field *
+Type_handler_newdecimal::make_table_field(const LEX_CSTRING *name,
+                                          const Record_addr &addr,
+                                          const Type_all_attributes &attr,
+                                          TABLE *table) const
+{
+  uint8 dec= attr.decimals;
+  uint8 intg= attr.decimal_precision() - dec;
+  uint32 len= attr.max_char_length();
+
+  /*
+    Trying to put too many digits overall in a DECIMAL(prec,dec)
+    will always throw a warning. We must limit dec to
+    DECIMAL_MAX_SCALE however to prevent an assert() later.
+  */
+
+  if (dec > 0)
+  {
+    signed int overflow;
+
+    dec= MY_MIN(dec, DECIMAL_MAX_SCALE);
+
+    /*
+      If the value still overflows the field with the corrected dec,
+      we'll throw out decimals rather than integers. This is still
+      bad and of course throws a truncation warning.
+      +1: for decimal point
+      */
+
+    const int required_length=
+      my_decimal_precision_to_length(intg + dec, dec, attr.unsigned_flag);
+
+    overflow= required_length - len;
+
+    if (overflow > 0)
+      dec= MY_MAX(0, dec - overflow);            // too long, discard fract
+    else
+      /* Corrected value fits. */
+      len= required_length;
+  }
+  return new (table->in_use->mem_root)
+         Field_new_decimal(addr.ptr, len, addr.null_ptr, addr.null_bit,
+                           Field::NONE, name->str,
+                           dec, 0/*zerofill*/, attr.unsigned_flag);
+}
+
+
+Field *Type_handler_year::make_table_field(const LEX_CSTRING *name,
+                                           const Record_addr &addr,
+                                           const Type_all_attributes &attr,
+                                           TABLE *table) const
+{
+  return new (table->in_use->mem_root)
+         Field_year(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+                    Field::NONE, name->str);
+}
+
+
+Field *Type_handler_null::make_table_field(const LEX_CSTRING *name,
+                                           const Record_addr &addr,
+                                           const Type_all_attributes &attr,
+                                           TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_null(addr.ptr, attr.max_length,
+                    Field::NONE, name->str, attr.collation.collation);
+}
+
+
+Field *Type_handler_timestamp::make_table_field(const LEX_CSTRING *name,
+                                                const Record_addr &addr,
+                                                const Type_all_attributes &attr,
+                                                TABLE *table) const
+
+{
+  return new_Field_timestamp(table->in_use->mem_root,
+                             addr.ptr, addr.null_ptr, addr.null_bit,
+                             Field::NONE, name->str, table->s, attr.decimals);
+}
+
+
+Field *Type_handler_timestamp2::make_table_field(const LEX_CSTRING *name,
+                                                 const Record_addr &addr,
+                                                 const Type_all_attributes &attr,
+                                                 TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_timestampf(addr.ptr, addr.null_ptr, addr.null_bit,
+                          Field::NONE, name->str, table->s, attr.decimals);
+}
+
+
+Field *Type_handler_newdate::make_table_field(const LEX_CSTRING *name,
+                                              const Record_addr &addr,
+                                              const Type_all_attributes &attr,
+                                              TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_newdate(addr.ptr, addr.null_ptr, addr.null_bit,
+                       Field::NONE, name->str);
+}
+
+
+Field *Type_handler_date::make_table_field(const LEX_CSTRING *name,
+                                           const Record_addr &addr,
+                                           const Type_all_attributes &attr,
+                                           TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_date(addr.ptr, addr.null_ptr, addr.null_bit,
+                    Field::NONE, name->str);
+}
+
+
+Field *Type_handler_time::make_table_field(const LEX_CSTRING *name,
+                                           const Record_addr &addr,
+                                           const Type_all_attributes &attr,
+                                           TABLE *table) const
+
+{
+  return new_Field_time(table->in_use->mem_root,
+                        addr.ptr, addr.null_ptr, addr.null_bit,
+                        Field::NONE, name->str, attr.decimals);
+}
+
+
+Field *Type_handler_time2::make_table_field(const LEX_CSTRING *name,
+                                            const Record_addr &addr,
+                                            const Type_all_attributes &attr,
+                                            TABLE *table) const
+
+
+{
+  return new (table->in_use->mem_root)
+         Field_timef(addr.ptr, addr.null_ptr, addr.null_bit,
+                     Field::NONE, name->str, attr.decimals);
+}
+
+
+Field *Type_handler_datetime::make_table_field(const LEX_CSTRING *name,
+                                               const Record_addr &addr,
+                                               const Type_all_attributes &attr,
+                                               TABLE *table) const
+
+{
+  return new_Field_datetime(table->in_use->mem_root,
+                            addr.ptr, addr.null_ptr, addr.null_bit,
+                            Field::NONE, name->str, attr.decimals);
+}
+
+
+Field *Type_handler_datetime2::make_table_field(const LEX_CSTRING *name,
+                                                const Record_addr &addr,
+                                                const Type_all_attributes &attr,
+                                                TABLE *table) const
+{
+  return new (table->in_use->mem_root)
+         Field_datetimef(addr.ptr, addr.null_ptr, addr.null_bit,
+                         Field::NONE, name->str, attr.decimals);
+}
+
+
+Field *Type_handler_bit::make_table_field(const LEX_CSTRING *name,
+                                          const Record_addr &addr,
+                                          const Type_all_attributes &attr,
+                                          TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_bit_as_char(addr.ptr, attr.max_length,
+                           addr.null_ptr, addr.null_bit,
+                           Field::NONE, name->str);
+}
+
+
+Field *Type_handler_string::make_table_field(const LEX_CSTRING *name,
+                                             const Record_addr &addr,
+                                             const Type_all_attributes &attr,
+                                             TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_string(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+                      Field::NONE, name->str, attr.collation.collation);
+}
+
+
+Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name,
+                                              const Record_addr &addr,
+                                              const Type_all_attributes &attr,
+                                              TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_varstring(addr.ptr, attr.max_length,
+                         HA_VARCHAR_PACKLENGTH(attr.max_length),
+                         addr.null_ptr, addr.null_bit,
+                         Field::NONE, name->str,
+                         table->s, attr.collation.collation);
+}
+
+
+Field *Type_handler_tiny_blob::make_table_field(const LEX_CSTRING *name,
+                                                const Record_addr &addr,
+                                                const Type_all_attributes &attr,
+                                                TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_blob(addr.ptr, addr.null_ptr, addr.null_bit,
+                    Field::NONE, name->str, table->s,
+                    1, attr.collation.collation);
+}
+
+
+Field *Type_handler_blob::make_table_field(const LEX_CSTRING *name,
+                                           const Record_addr &addr,
+                                           const Type_all_attributes &attr,
+                                           TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_blob(addr.ptr, addr.null_ptr, addr.null_bit,
+                    Field::NONE, name->str, table->s,
+                    2, attr.collation.collation);
+}
+
+
+Field *
+Type_handler_medium_blob::make_table_field(const LEX_CSTRING *name,
+                                           const Record_addr &addr,
+                                           const Type_all_attributes &attr,
+                                           TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_blob(addr.ptr, addr.null_ptr, addr.null_bit,
+                    Field::NONE, name->str, table->s,
+                    3, attr.collation.collation);
+}
+
+
+Field *Type_handler_long_blob::make_table_field(const LEX_CSTRING *name,
+                                                const Record_addr &addr,
+                                                const Type_all_attributes &attr,
+                                                TABLE *table) const
+
+{
+  return new (table->in_use->mem_root)
+         Field_blob(addr.ptr, addr.null_ptr, addr.null_bit,
+                    Field::NONE, name->str, table->s,
+                    4, attr.collation.collation);
+}
+
+
+
+#ifdef HAVE_SPATIAL
+Field *Type_handler_geometry::make_table_field(const LEX_CSTRING *name,
+                                               const Record_addr &addr,
+                                               const Type_all_attributes &attr,
+                                               TABLE *table) const
+{
+  return new (table->in_use->mem_root)
+         Field_geom(addr.ptr, addr.null_ptr, addr.null_bit,
+                    Field::NONE, name->str, table->s, 4,
+                    (Field::geometry_type) attr.uint_geometry_type(),
+                    0);
+}
+#endif
+
+
+Field *Type_handler_enum::make_table_field(const LEX_CSTRING *name,
+                                           const Record_addr &addr,
+                                           const Type_all_attributes &attr,
+                                           TABLE *table) const
+{
+  /*
+    Will be implemented when we split Item_type_holder::make_field_by_type()
+    and/or reuse Type_handler::make_table_field() in make_field() in field.cc
+  */
+  DBUG_ASSERT(0);
+  return 0;
+}
+
+
+Field *Type_handler_set::make_table_field(const LEX_CSTRING *name,
+                                          const Record_addr &addr,
+                                          const Type_all_attributes &attr,
+                                          TABLE *table) const
+
+{
+  /*
+    Will be implemented when we split Item_type_holder::make_field_by_type()
+    and/or reuse Type_handler::make_table_field() in make_field() in field.cc
+  */
+  DBUG_ASSERT(0);
+  return 0;
+}
+
+/*************************************************************************/
 
 uint32 Type_handler_decimal_result::max_display_length(const Item *item) const
 {
@@ -1343,6 +1783,17 @@ bool Type_handler_string_result::
 }
 
 
+bool Type_handler_blob_common::
+       Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
+                                       Item **items, uint nitems) const
+{
+  if (func->aggregate_attributes_string(items, nitems))
+    return true;
+  func->set_handler(blob_type_handler(func->max_length));
+  return false;
+}
+
+
 bool Type_handler_date_common::
        Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
                                        Item **items, uint nitems) const
diff --git a/sql/sql_type.h b/sql/sql_type.h
index bd5290a..9eadfeb 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -314,6 +314,27 @@ class Type_std_attributes
 };
 
 
+class Type_all_attributes: public Type_std_attributes
+{
+public:
+  Type_all_attributes()
+   :Type_std_attributes()
+  { }
+  Type_all_attributes(const Type_all_attributes *other)
+   :Type_std_attributes(other)
+  { }
+  // Returns total number of decimal digits
+  virtual uint decimal_precision() const= 0;
+  /*
+    Field::geometry_type is not visible here.
+    Let's use an "uint" wrapper for now. Later when we move Field_geom
+    into a plugin, this method will be replaced to some generic
+    datatype indepented method.
+  */
+  virtual uint uint_geometry_type() const= 0;
+};
+
+
 class Name: private LEX_CSTRING
 {
 public:
@@ -327,6 +348,31 @@ class Name: private LEX_CSTRING
 };
 
 
+class Record_addr
+{
+public:
+  uchar *ptr;      // Position to field in record
+  /**
+     Byte where the @c NULL bit is stored inside a record. If this Field is a
+     @c NOT @c NULL field, this member is @c NULL.
+  */
+  uchar *null_ptr;
+  uchar null_bit;  // Bit used to test null bit
+  Record_addr(uchar *ptr_arg,
+              uchar *null_ptr_arg,
+              uchar null_bit_arg)
+   :ptr(ptr_arg),
+    null_ptr(null_ptr_arg),
+    null_bit(null_bit_arg)
+  { }
+  Record_addr(bool maybe_null)
+   :ptr(NULL),
+    null_ptr(maybe_null ? (uchar*) "" : 0),
+    null_bit(0)
+  { }
+};
+
+
 class Type_handler
 {
 protected:
@@ -342,6 +388,7 @@ class Type_handler
   bool
   Item_func_or_sum_illegal_param(const Item_func_or_sum *) const;
 public:
+  static const Type_handler *blob_type_handler(uint max_octet_length);
   static const Type_handler *string_type_handler(uint max_octet_length);
   static const Type_handler *get_handler_by_field_type(enum_field_types type);
   static const Type_handler *get_handler_by_real_type(enum_field_types type);
@@ -418,6 +465,22 @@ class Type_handler
   virtual Field *make_conversion_table_field(TABLE *TABLE,
                                              uint metadata,
                                              const Field *target) const= 0;
+  virtual Field *make_table_field(const LEX_CSTRING *name,
+                                  const Record_addr &addr,
+                                  const Type_all_attributes &attr,
+                                  TABLE *table) const= 0;
+  Field *make_and_init_table_field(const LEX_CSTRING *name,
+                                   const Record_addr &addr,
+                                   const Type_all_attributes &attr,
+                                   TABLE *table) const;
+  Field *make_and_init_table_field(const char *name,
+                                   const Record_addr &addr,
+                                   const Type_all_attributes &attr,
+                                   TABLE *table) const
+  {
+    LEX_CSTRING lex_string_name= {name, name ? strlen(name) : 0};
+    return make_and_init_table_field(&lex_string_name, addr, attr, table);
+  }
   virtual void make_sort_key(uchar *to, Item *item,
                              const SORT_FIELD_ATTR *sort_field,
                              Sort_param *param) const= 0;
@@ -604,6 +667,14 @@ class Type_handler_row: public Type_handler
     DBUG_ASSERT(0);
     return NULL;
   }
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const
+  {
+    DBUG_ASSERT(0);
+    return NULL;
+  }
   void make_sort_key(uchar *to, Item *item,
                      const SORT_FIELD_ATTR *sort_field,
                      Sort_param *param) const
@@ -1132,6 +1203,10 @@ class Type_handler_tiny: public Type_handler_int_result
   uint32 max_display_length(const Item *item) const { return 4; }
   Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1145,6 +1220,10 @@ class Type_handler_short: public Type_handler_int_result
   uint32 max_display_length(const Item *item) const { return 6; }
   Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1161,6 +1240,10 @@ class Type_handler_long: public Type_handler_int_result
   }
   Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1174,6 +1257,10 @@ class Type_handler_longlong: public Type_handler_int_result
   uint32 max_display_length(const Item *item) const { return 20; }
   Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1187,6 +1274,10 @@ class Type_handler_int24: public Type_handler_int_result
   uint32 max_display_length(const Item *item) const { return 8; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1200,6 +1291,10 @@ class Type_handler_year: public Type_handler_int_result
   uint32 max_display_length(const Item *item) const;
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1217,6 +1312,10 @@ class Type_handler_bit: public Type_handler_int_result
   }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1231,6 +1330,10 @@ class Type_handler_float: public Type_handler_real_result
   Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1244,6 +1347,10 @@ class Type_handler_double: public Type_handler_real_result
   uint32 max_display_length(const Item *item) const { return 53; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1270,6 +1377,10 @@ class Type_handler_time: public Type_handler_time_common
   virtual ~Type_handler_time() {}
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1280,6 +1391,10 @@ class Type_handler_time2: public Type_handler_time_common
   enum_field_types real_field_type() const { return MYSQL_TYPE_TIME2; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1312,6 +1427,10 @@ class Type_handler_date: public Type_handler_date_common
   virtual ~Type_handler_date() {}
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1321,6 +1440,10 @@ class Type_handler_newdate: public Type_handler_date_common
   virtual ~Type_handler_newdate() {}
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1343,6 +1466,10 @@ class Type_handler_datetime: public Type_handler_datetime_common
   virtual ~Type_handler_datetime() {}
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1353,6 +1480,10 @@ class Type_handler_datetime2: public Type_handler_datetime_common
   enum_field_types real_field_type() const { return MYSQL_TYPE_DATETIME2; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1375,6 +1506,10 @@ class Type_handler_timestamp: public Type_handler_timestamp_common
   virtual ~Type_handler_timestamp() {}
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1385,6 +1520,10 @@ class Type_handler_timestamp2: public Type_handler_timestamp_common
   enum_field_types real_field_type() const { return MYSQL_TYPE_TIMESTAMP2; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1397,6 +1536,10 @@ class Type_handler_olddecimal: public Type_handler_decimal_result
   enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1409,6 +1552,10 @@ class Type_handler_newdecimal: public Type_handler_decimal_result
   enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1423,6 +1570,10 @@ class Type_handler_null: public Type_handler_string_result
   uint32 max_display_length(const Item *item) const { return 0; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1435,6 +1586,10 @@ class Type_handler_string: public Type_handler_string_result
   enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1447,10 +1602,23 @@ class Type_handler_varchar: public Type_handler_string_result
   enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
-class Type_handler_tiny_blob: public Type_handler_string_result
+class Type_handler_blob_common: public Type_handler_string_result
+{
+public:
+  virtual ~Type_handler_blob_common() { }
+  bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func,
+                                       Item **items, uint nitems) const;
+};
+
+
+class Type_handler_tiny_blob: public Type_handler_blob_common
 {
   static const Name m_name_tinyblob;
 public:
@@ -1459,10 +1627,14 @@ class Type_handler_tiny_blob: public Type_handler_string_result
   enum_field_types field_type() const { return MYSQL_TYPE_TINY_BLOB; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
-class Type_handler_medium_blob: public Type_handler_string_result
+class Type_handler_medium_blob: public Type_handler_blob_common
 {
   static const Name m_name_mediumblob;
 public:
@@ -1471,10 +1643,14 @@ class Type_handler_medium_blob: public Type_handler_string_result
   enum_field_types field_type() const { return MYSQL_TYPE_MEDIUM_BLOB; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
-class Type_handler_long_blob: public Type_handler_string_result
+class Type_handler_long_blob: public Type_handler_blob_common
 {
   static const Name m_name_longblob;
 public:
@@ -1483,10 +1659,14 @@ class Type_handler_long_blob: public Type_handler_string_result
   enum_field_types field_type() const { return MYSQL_TYPE_LONG_BLOB; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
-class Type_handler_blob: public Type_handler_string_result
+class Type_handler_blob: public Type_handler_blob_common
 {
   static const Name m_name_blob;
 public:
@@ -1495,6 +1675,10 @@ class Type_handler_blob: public Type_handler_string_result
   enum_field_types field_type() const { return MYSQL_TYPE_BLOB; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1509,6 +1693,11 @@ class Type_handler_geometry: public Type_handler_string_result
   const Type_handler *type_handler_for_comparison() const;
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
+
   bool is_traditional_type() const
   {
     return false;
@@ -1545,6 +1734,10 @@ class Type_handler_enum: public Type_handler_string_result
   virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1558,6 +1751,10 @@ class Type_handler_set: public Type_handler_string_result
   virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; }
   Field *make_conversion_table_field(TABLE *, uint metadata,
                                      const Field *target) const;
+  Field *make_table_field(const LEX_CSTRING *name,
+                          const Record_addr &addr,
+                          const Type_all_attributes &attr,
+                          TABLE *table) const;
 };
 
 
@@ -1651,6 +1848,10 @@ extern Type_handler_time2       type_handler_time2;
 extern Type_handler_newdate     type_handler_newdate;
 extern Type_handler_datetime2   type_handler_datetime2;
 
+extern Type_handler_tiny_blob   type_handler_tiny_blob;
+extern Type_handler_blob        type_handler_blob;
+extern Type_handler_medium_blob type_handler_medium_blob;
+extern Type_handler_long_blob   type_handler_long_blob;
 
 class Type_aggregator
 {

Follow ups

References