summaryrefslogtreecommitdiff
path: root/storage/innobase/handler
diff options
context:
space:
mode:
authorEugene Kosov <claprix@yandex.ru>2019-06-17 16:54:47 +0300
committerEugene Kosov <claprix@yandex.ru>2019-06-22 14:09:12 +0300
commita82e42fd133949b560790c9b74a4072f899baee4 (patch)
tree644d04d14fd58e03105fb486f0e90eb29ce136d1 /storage/innobase/handler
parent854c219a7f0e1878517d5a821992f650342380dd (diff)
downloadmariadb-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.cc146
-rw-r--r--storage/innobase/handler/ha_innodb.h7
-rw-r--r--storage/innobase/handler/handler0alter.cc8
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;
}