diff --git a/sql/sql_table.cc b/sql/sql_table.cc index bfed754a90c..1664f94515a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3383,7 +3383,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, CHARSET_INFO *ft_key_charset=0; // for FULLTEXT for (uint column_nr=0 ; (column=cols++) ; column_nr++) { - uint length; Key_part_spec *dup_column; it.rewind(); @@ -3515,30 +3514,40 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_part_info->fieldnr= field; key_part_info->offset= (uint16) sql_field->offset; key_part_info->key_type=sql_field->pack_flag; - length= sql_field->key_length; + uint key_part_length= sql_field->key_length; if (column->length) { if (f_is_blob(sql_field->pack_flag)) { - if ((length=column->length) > max_key_length || - length > file->max_key_part_length()) + key_part_length= column->length; + /* + There is a possibility that the given prefix length is less + than the engine max key part length, but still greater + than the BLOB field max size. We handle this case + using the max_field_size variable below. + */ + uint max_field_size= sql_field->key_length * sql_field->charset->mbmaxlen; + if ((max_field_size && key_part_length > max_field_size) || + key_part_length > max_key_length || + key_part_length > file->max_key_part_length()) { - length=min(max_key_length, file->max_key_part_length()); + // Given prefix length is too large, adjust it. + key_part_length= min(max_key_length, file->max_key_part_length()); + if (max_field_size) + key_part_length= min(key_part_length, max_field_size); if (key->type == Key::MULTIPLE) { /* not a critical problem */ - char warn_buff[MYSQL_ERRMSG_SIZE]; - my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY), - length); - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TOO_LONG_KEY, warn_buff); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TOO_LONG_KEY, ER(ER_TOO_LONG_KEY), + key_part_length); /* Align key length to multibyte char boundary */ - length-= length % sql_field->charset->mbmaxlen; + key_part_length-= key_part_length % sql_field->charset->mbmaxlen; } else { - my_error(ER_TOO_LONG_KEY,MYF(0),length); + my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length); DBUG_RETURN(TRUE); } } @@ -3546,9 +3555,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, // Catch invalid use of partial keys else if (!f_is_geom(sql_field->pack_flag) && // is the key partial? - column->length != length && + column->length != key_part_length && // is prefix length bigger than field length? - (column->length > length || + (column->length > key_part_length || // can the field have a partial key? !Field::type_can_have_key_part (sql_field->sql_type) || // a packed field can't be used in a partial key @@ -3557,43 +3566,42 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) && // and is this a 'unique' key? (key_info->flags & HA_NOSAME)))) - { + { my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0)); DBUG_RETURN(TRUE); } else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS)) - length=column->length; + key_part_length= column->length; } - else if (length == 0) + else if (key_part_length == 0) { my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name.str); DBUG_RETURN(TRUE); } - if (length > file->max_key_part_length() && key->type != Key::FULLTEXT) + if (key_part_length > file->max_key_part_length() && + key->type != Key::FULLTEXT) { - length= file->max_key_part_length(); + key_part_length= file->max_key_part_length(); if (key->type == Key::MULTIPLE) { /* not a critical problem */ - char warn_buff[MYSQL_ERRMSG_SIZE]; - my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY), - length); - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TOO_LONG_KEY, warn_buff); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TOO_LONG_KEY, ER(ER_TOO_LONG_KEY), + key_part_length); /* Align key length to multibyte char boundary */ - length-= length % sql_field->charset->mbmaxlen; + key_part_length-= key_part_length % sql_field->charset->mbmaxlen; } else { - my_error(ER_TOO_LONG_KEY,MYF(0),length); + my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length); DBUG_RETURN(TRUE); } } - key_part_info->length=(uint16) length; + key_part_info->length= (uint16) key_part_length; /* Use packed keys for long strings on the first column */ if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) && !((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) && - (length >= KEY_DEFAULT_PACK_LENGTH && + (key_part_length >= KEY_DEFAULT_PACK_LENGTH && (sql_field->sql_type == MYSQL_TYPE_STRING || sql_field->sql_type == MYSQL_TYPE_VARCHAR || sql_field->pack_flag & FIELDFLAG_BLOB))) @@ -3605,10 +3613,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_info->flags|= HA_PACK_KEY; } /* Check if the key segment is partial, set the key flag accordingly */ - if (length != sql_field->key_length) + if (key_part_length != sql_field->key_length) key_info->flags|= HA_KEY_HAS_PART_KEY_SEG; - key_length+=length; + key_length+= key_part_length; key_part_info++; /* Create the key name based on the first column (if not given) */ diff --git a/sql/table.cc b/sql/table.cc index 67f7922a2e1..ba1839bb6ec 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1525,13 +1525,25 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, primary_key=key; for (i=0 ; i < keyinfo->key_parts ;i++) { - uint fieldnr= key_part[i].fieldnr; - if (!fieldnr || - share->field[fieldnr-1]->null_ptr || - share->field[fieldnr-1]->key_length() != - key_part[i].length) + DBUG_ASSERT(key_part[i].fieldnr > 0); + // Table field corresponding to the i'th key part. + Field *table_field= share->field[key_part[i].fieldnr - 1]; + + /* + If the key column is of NOT NULL BLOB type, then it + will definitly have key prefix. And if key part prefix size + is equal to the BLOB column max size, then we can promote + it to primary key. + */ + if (!table_field->real_maybe_null() && + table_field->type() == MYSQL_TYPE_BLOB && + table_field->field_length == key_part[i].length) + continue; + + if (table_field->real_maybe_null() || + table_field->key_length() != key_part[i].length) { - primary_key=MAX_KEY; // Can't be used + primary_key= MAX_KEY; // Can't be used break; } } diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 9a9ec15dba2..aa81056c135 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -2692,6 +2692,19 @@ i_s_innodb_buffer_page_fill( table_name = mem_heap_strdup(heap, index->table_name); + DBUG_EXECUTE_IF("mysql_test_print_index_type", + { + char idx_type[3]; + + ut_snprintf(idx_type, + sizeof(idx_type), + "%d", + index->type); + + index_name=mem_heap_strcat(heap, + index_name, + idx_type); + };); } mutex_exit(&dict_sys->mutex);