Item_type_holder::get_real_type() has a switch(item->type()).
This coding style makes it impossible for user defined data type plugins to create their own Item types (e.g. descendants of Item_basic_constant, Item_func, Item_sum for data type specific literals and functions, etc) with a desired UNION aggregation behavior.
Also, this coding style is error prone, because it's very easy to forget to modify Item_type_holder::get_real_type properly when adding new built-in Items.
We'll do the following:
2. Move pieces from Item_type_holder::get_real_type() "case"s into virtual implementations of the corresponding Items:
Note, there is no a need for Item_func_get_user_var::real_type_handler(). The "case" corresponding to Item_func_get_user_var is not really needed and is a useless code, because starting from 10.1 Item_func_get_user_var is a descendant of Type_handler_hybrid_field_type, which makes sure that:
are always in sync to each other. All these methods use Type_handler_hybrid_field_type::m_type_handler to return the result.
In 10.0 and earlier, cmp_type and field_type were stored in separate members:
which could get out of sync in some cases.
We'll derive Item_type_holder from Type_handler_hybrid_field_type, because the new method Item::real_type_handler() makes it easy to use Type_handler_hybrid_field_type in Item_type_holder directly.
The idea of keep_field_type() is that the aggregate functions MAX() and MIN() try to preserve the exact data type (e.g. ENUM or SET) from the argument when they appear as a part of a UNION, e.g in combinations with NULL:
Notice, this script creates a column of the ENUM data type in the table t2:
Unlike MIN and MAX, most functions convert ENUM/SET to VARCHAR.
keep_field_type() is not needed after adding of real_type_handler(), which replaces this functionality in a more universal way.