diff options
author | Eugene Kosov <claprix@yandex.ru> | 2019-06-17 16:54:47 +0300 |
---|---|---|
committer | Eugene Kosov <claprix@yandex.ru> | 2019-06-22 14:09:12 +0300 |
commit | a82e42fd133949b560790c9b74a4072f899baee4 (patch) | |
tree | 644d04d14fd58e03105fb486f0e90eb29ce136d1 /storage/innobase/handler | |
parent | 854c219a7f0e1878517d5a821992f650342380dd (diff) | |
download | mariadb-git-a82e42fd133949b560790c9b74a4072f899baee4.tar.gz |
NFC: refactor Field::is_equal() and related stuff
Make Field::is_equal() const and return bool as it's a naturally fitting
type for it. Also it's agrument was narrowed to Column_definition.
InnoDB can change type of some columns by itself. InnoDB-specific code used to
reside in Field_xxx:is_equal() methods. Now engine-specific stuff was
moved to a virtual methods of handler::can_convert{string,varstring,blob,geom}.
These methods are called by Field::can_be_converted_by_engine() which is a
double dispatch pattern.
Some InnoDB-specific code still resides in compare_keys_but_name(). It should
be moved from here someday to handler::compare_key_parts(...) or similar.
IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET
IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET_BUT_COLLATE: both was removed
IS_EQUAL_NO, IS_EQUAL_YES are not needed now and should be removed
along with deprecated handler::check_if_incompatible_data().
HA_EXTENDED_TYPES_CONVERSION: was removed as such logic is not needed now by
server code.
ALTER_COLUMN_EQUAL_PACK_LENGTH: was renamed to a more generic
ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE
Diffstat (limited to 'storage/innobase/handler')
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 146 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.h | 7 | ||||
-rw-r--r-- | storage/innobase/handler/handler0alter.cc | 8 |
3 files changed, 152 insertions, 9 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 88ea6f5e642..107fcac762a 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -54,6 +54,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include <my_bitmap.h> #include <mysql/service_thd_alloc.h> #include <mysql/service_thd_wait.h> +#include "field.h" // MYSQL_PLUGIN_IMPORT extern my_bool lower_case_file_system; // MYSQL_PLUGIN_IMPORT extern char mysql_unpacked_real_data_home[]; @@ -6141,11 +6142,6 @@ no_such_table: DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); } - if (!ib_table->not_redundant()) { - m_int_table_flags |= HA_EXTENDED_TYPES_CONVERSION; - cached_table_flags |= HA_EXTENDED_TYPES_CONVERSION; - } - size_t n_fields = omits_virtual_cols(*table_share) ? table_share->stored_fields : table_share->fields; size_t n_cols = dict_table_get_n_user_cols(ib_table) @@ -20875,6 +20871,146 @@ bool ha_innobase::rowid_filter_push(Rowid_filter* pk_filter) DBUG_RETURN(false); } +static bool +is_part_of_a_primary_key(const Field* field) +{ + const TABLE_SHARE* s = field->table->s; + + return s->primary_key != MAX_KEY + && field->part_of_key.is_set(s->primary_key); +} + +bool +ha_innobase::can_convert_string(const Field_string* field, + const Column_definition& new_type) const +{ + DBUG_ASSERT(!field->compression_method()); + if (new_type.type_handler() != field->type_handler()) { + return false; + } + + if (new_type.char_length < field->char_length()) { + return false; + } + + if (new_type.charset != field->charset()) { + if (new_type.length != field->max_display_length() + && !m_prebuilt->table->not_redundant()) { + return IS_EQUAL_NO; + } + + Charset field_cs(field->charset()); + if (!field_cs.encoding_allows_reinterpret_as( + new_type.charset)) { + return false; + } + + if (!field_cs.eq_collation_specific_names(new_type.charset)) { + return !is_part_of_a_primary_key(field); + } + + return true; + } + + if (new_type.length != field->max_display_length()) { + return false; + } + + return true; +} + +static bool +supports_enlarging(const dict_table_t* table, const Field_varstring* field, + const Column_definition& new_type) +{ + return field->field_length <= 127 || new_type.length <= 255 + || field->field_length > 255 || !table->not_redundant(); +} + +bool +ha_innobase::can_convert_varstring(const Field_varstring* field, + const Column_definition& new_type) const +{ + if (new_type.length < field->field_length) { + return false; + } + + if (new_type.char_length < field->char_length()) { + return false; + } + + if (!new_type.compression_method() != !field->compression_method()) { + return false; + } + + if (new_type.type_handler() != field->type_handler()) { + return false; + } + + if (new_type.charset != field->charset()) { + if (!supports_enlarging(m_prebuilt->table, field, new_type)) { + return false; + } + + Charset field_cs(field->charset()); + if (!field_cs.encoding_allows_reinterpret_as( + new_type.charset)) { + return false; + } + + if (!field_cs.eq_collation_specific_names(new_type.charset)) { + return !is_part_of_a_primary_key(field); + } + + return true; + } + + if (new_type.length != field->field_length) { + if (!supports_enlarging(m_prebuilt->table, field, new_type)) { + return false; + } + + return true; + } + + return true; +} + +bool +ha_innobase::can_convert_blob(const Field_blob* field, + const Column_definition& new_type) const +{ + if (new_type.type_handler() != field->type_handler()) { + return false; + } + + if (!new_type.compression_method() != !field->compression_method()) { + return false; + } + + if (new_type.pack_length != field->pack_length()) { + return false; + } + + if (new_type.charset != field->charset()) { + Charset field_cs(field->charset()); + if (!field_cs.encoding_allows_reinterpret_as( + new_type.charset)) { + return false; + } + + if (!field_cs.eq_collation_specific_names(new_type.charset)) { + bool is_part_of_a_key + = !field->part_of_key.is_clear_all(); + return !is_part_of_a_key; + } + + return true; + } + + return true; +} + /******************************************************************//** Use this when the args are passed to the format string from errmsg-utf8.txt directly as is. diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 11b69974558..60c560f9bc7 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -437,6 +437,13 @@ public: @retval false if pushed (always) */ bool rowid_filter_push(Rowid_filter *rowid_filter); + bool can_convert_string(const Field_string* field, + const Column_definition& new_field) const; + bool can_convert_varstring(const Field_varstring* field, + const Column_definition& new_field) const; + bool can_convert_blob(const Field_blob* field, + const Column_definition& new_field) const; + protected: /** MySQL calls this method at the end of each statement. This method diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index e4f5a04f668..08e549629fd 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -131,7 +131,7 @@ static const alter_table_operations INNOBASE_ALTER_INSTANT | ALTER_COLUMN_NAME | ALTER_ADD_VIRTUAL_COLUMN | INNOBASE_FOREIGN_OPERATIONS - | ALTER_COLUMN_EQUAL_PACK_LENGTH + | ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE | ALTER_COLUMN_UNVERSIONED | ALTER_RENAME_INDEX | ALTER_DROP_VIRTUAL_COLUMN; @@ -8332,7 +8332,7 @@ ok_exit: rebuild_templ = ctx->need_rebuild() || ((ha_alter_info->handler_flags - & ALTER_COLUMN_EQUAL_PACK_LENGTH) + & ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE) && alter_templ_needs_rebuild( altered_table, ha_alter_info, ctx->new_table)); @@ -9194,7 +9194,7 @@ innobase_rename_or_enlarge_columns_try( DBUG_ENTER("innobase_rename_or_enlarge_columns_try"); if (!(ha_alter_info->handler_flags - & (ALTER_COLUMN_EQUAL_PACK_LENGTH + & (ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE | ALTER_COLUMN_NAME))) { DBUG_RETURN(false); } @@ -9242,7 +9242,7 @@ innobase_rename_or_enlarge_columns_cache( dict_table_t* user_table) { if (!(ha_alter_info->handler_flags - & (ALTER_COLUMN_EQUAL_PACK_LENGTH + & (ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE | ALTER_COLUMN_NAME))) { return; } |