diff options
Diffstat (limited to 'storage/innobase/handler/ha_innodb.cc')
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 164 |
1 files changed, 110 insertions, 54 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 347cf6f21b7..1096e8ea097 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1945,7 +1945,7 @@ convert_error_code_to_mysql( /*========================*/ dberr_t error, /*!< in: InnoDB error code */ ulint flags, /*!< in: InnoDB table flags, or 0 */ - THD* thd) /*!< in: user thread handle or NULL */ + THD* thd, size_t n_fields = 0) /*!< in: user thread handle or NULL */ { switch (error) { case DB_SUCCESS: @@ -2065,33 +2065,11 @@ convert_error_code_to_mysql( return(HA_ERR_TABLESPACE_MISSING); case DB_TOO_BIG_RECORD: { - /* If prefix is true then a 768-byte prefix is stored - locally for BLOB fields. Refer to dict_table_get_format(). - We limit max record size to 16k for 64k page size. */ - bool prefix = (dict_tf_get_format(flags) == UNIV_FORMAT_A); - bool comp = !!(flags & DICT_TF_COMPACT); - ulint free_space = page_get_free_space_of_empty(comp) / 2; - - if (free_space >= ulint(comp ? COMPRESSED_REC_MAX_DATA_SIZE : - REDUNDANT_REC_MAX_DATA_SIZE)) { - free_space = (comp ? COMPRESSED_REC_MAX_DATA_SIZE : - REDUNDANT_REC_MAX_DATA_SIZE) - 1; - } - - my_printf_error(ER_TOO_BIG_ROWSIZE, - "Row size too large (> " ULINTPF "). Changing some columns " - "to TEXT or BLOB %smay help. In current row " - "format, BLOB prefix of %d bytes is stored inline.", - MYF(0), - free_space, - prefix - ? "or using ROW_FORMAT=DYNAMIC or" - " ROW_FORMAT=COMPRESSED " - : "", - prefix - ? DICT_MAX_FIXED_COL_LEN - : 0); - return(HA_ERR_TO_BIG_ROW); + ut_ad(n_fields != 0); + std::string err_msg + = format_too_big_row_error_message(flags, n_fields); + my_printf_error(ER_TOO_BIG_ROWSIZE, err_msg.c_str(), MYF(0)); + return (HA_ERR_TO_BIG_ROW); } case DB_TOO_BIG_INDEX_COL: @@ -5579,7 +5557,7 @@ normalize_table_name_c_low( create_table_info_t::create_table_info_t( THD* thd, - TABLE* form, + const TABLE* form, HA_CREATE_INFO* create_info, char* table_name, char* remote_path, @@ -8379,8 +8357,17 @@ report_error: table->s->table_name.str); } - error_result = convert_error_code_to_mysql( - error, m_prebuilt->table->flags, m_user_thd); + if (error == DB_TOO_BIG_RECORD) { + // Let's hope that we failed to insert a record into a clustered + // index. Otherwise n_fields and thus error message returnted to + // user will be incorrect. + error_result = convert_error_code_to_mysql( + error, m_prebuilt->table->flags, m_user_thd, + dict_table_get_first_index(m_prebuilt->table)->n_fields); + } else { + error_result = convert_error_code_to_mysql( + error, m_prebuilt->table->flags, m_user_thd); + } #ifdef WITH_WSREP if (!error_result @@ -12741,14 +12728,90 @@ int create_table_info_t::create_table(bool create_fk) innobase_table = dict_table_open_on_name( m_table_name, TRUE, FALSE, DICT_ERR_IGNORE_NONE); + ut_ad(innobase_table); - if (innobase_table != NULL) { - dict_table_close(innobase_table, TRUE, FALSE); + for (dict_index_t* index = dict_table_get_first_index(innobase_table); + index; index = dict_table_get_next_index(index)) { + + if (!row_size_is_acceptable(index)) { + std::string err_msg = format_too_big_row_error_message( + m_flags, index->n_fields); + my_printf_error(ER_TOO_BIG_ROWSIZE, err_msg.c_str(), + MYF(0)); + dict_table_close(innobase_table, true, false); + DBUG_RETURN(HA_ERR_TO_BIG_ROW); + } } + dict_table_close(innobase_table, TRUE, FALSE); + DBUG_RETURN(0); } +bool create_table_info_t::row_size_is_acceptable( + const dict_table_t* table) const +{ + ut_ad(table); + + for (dict_index_t* index = dict_table_get_first_index(table); index; + index = dict_table_get_next_index(index)) { + + if (!row_size_is_acceptable(index)) { + return false; + } + } + + return true; +} + +bool create_table_info_t::row_size_is_acceptable( + const dict_index_t* index) const +{ + if (index->type & DICT_FTS) { + return true; + } + // Not always system tables have sane maximux size. But user don't have + // to know about that. + if (index->table->is_system_db) { + return true; + } + + bool strict = THDVAR(m_thd, strict_mode); + + dict_index_t::record_size_info_t info = index->record_size_info(); + + if (info.row_too_big()) { + int idx = info.get_first_overrun_field_index(); + if (idx != INT_MAX) { + ut_ad(info.get_overrun_size() != 0); + ut_ad(info.max_leaf_size != 0); + + const dict_field_t* field + = dict_index_get_nth_field(index, idx); + + ib::error_or_warn(strict) + << "After adding field " << field->name + << " in table " << index->table->name + << " row size occupies " << info.get_overrun_size() + << " bytes, which is greater than maximum " + "allowed size (" + << info.max_leaf_size + << " bytes) for a record on index leaf page."; + } + + if (strict) { + return false; + } + + std::string err_msg = format_too_big_row_error_message( + index->table->flags, index->n_fields); + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, + HA_ERR_TO_BIG_ROW, err_msg.c_str()); + } + + return true; +} + /** Update a new table in an InnoDB database. @return error number */ int @@ -22142,30 +22205,23 @@ innobase_convert_to_system_charset( cs2, to, static_cast<uint>(len), errors))); } -/********************************************************************** -Issue a warning that the row is too big. */ -void -ib_warn_row_too_big(const dict_table_t* table) +std::string format_too_big_row_error_message(unsigned flags, size_t n_fields) { /* If prefix is true then a 768-byte prefix is stored locally for BLOB fields. Refer to dict_table_get_format() */ - const bool prefix = (dict_tf_get_format(table->flags) - == UNIV_FORMAT_A); - - const ulint free_space = page_get_free_space_of_empty( - table->flags & DICT_TF_COMPACT) / 2; - - THD* thd = current_thd; - - push_warning_printf( - thd, Sql_condition::WARN_LEVEL_WARN, HA_ERR_TO_BIG_ROW, - "Row size too large (> " ULINTPF ")." - " Changing some columns to TEXT" - " or BLOB %smay help. In current row format, BLOB prefix of" - " %d bytes is stored inline.", free_space - , prefix ? "or using ROW_FORMAT=DYNAMIC or" - " ROW_FORMAT=COMPRESSED ": "" - , prefix ? DICT_MAX_FIXED_COL_LEN : 0); + const bool prefix = (dict_tf_get_format(flags) == UNIV_FORMAT_A); + const size_t prefix_len = prefix ? DICT_MAX_FIXED_COL_LEN : 0; + const size_t max_record_size = get_max_record_size_leaf_page( + flags & DICT_TF_COMPACT, dict_tf_get_page_size(flags), n_fields); + + std::stringstream ss; + ss << "Row size is greater than " << max_record_size + << ". Changing some columns to TEXT or BLOB " + << (prefix ? "or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED " + : "") + << "may help. In current row format, BLOB prefix of " << prefix_len + << " bytes is stored inline."; + return ss.str(); } /** Validate the requested buffer pool size. Also, reserve the necessary |