|
|
@ -1,6 +1,6 @@ |
|
|
|
/*****************************************************************************
|
|
|
|
|
|
|
|
Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved. |
|
|
|
Copyright (c) 2005, 2015, Oracle and/or its affiliates. All Rights Reserved. |
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under |
|
|
|
the terms of the GNU General Public License as published by the Free Software |
|
|
@ -28,6 +28,7 @@ Smart ALTER TABLE |
|
|
|
#include <mysql/innodb_priv.h>
|
|
|
|
#include <sql_alter.h>
|
|
|
|
#include <sql_class.h>
|
|
|
|
#include <sql_table.h>
|
|
|
|
|
|
|
|
#include "dict0crea.h"
|
|
|
|
#include "dict0dict.h"
|
|
|
@ -465,12 +466,9 @@ ha_innobase::check_if_supported_inplace_alter( |
|
|
|
} else if (((ha_alter_info->handler_flags |
|
|
|
& Alter_inplace_info::ADD_PK_INDEX) |
|
|
|
|| innobase_need_rebuild(ha_alter_info)) |
|
|
|
&& (innobase_fulltext_exist(altered_table) |
|
|
|
|| (prebuilt->table->flags2 |
|
|
|
& DICT_TF2_FTS_HAS_DOC_ID))) { |
|
|
|
&& (innobase_fulltext_exist(altered_table))) { |
|
|
|
/* Refuse to rebuild the table online, if
|
|
|
|
fulltext indexes are to survive the rebuild, |
|
|
|
or if the table contains a hidden FTS_DOC_ID column. */ |
|
|
|
fulltext indexes are to survive the rebuild. */ |
|
|
|
online = false; |
|
|
|
/* If the table already contains fulltext indexes,
|
|
|
|
refuse to rebuild the table natively altogether. */ |
|
|
@ -828,10 +826,8 @@ innobase_get_foreign_key_info( |
|
|
|
char* tbl_namep = NULL; |
|
|
|
ulint db_name_len = 0; |
|
|
|
ulint tbl_name_len = 0; |
|
|
|
#ifdef __WIN__
|
|
|
|
char db_name[MAX_DATABASE_NAME_LEN]; |
|
|
|
char tbl_name[MAX_TABLE_NAME_LEN]; |
|
|
|
#endif
|
|
|
|
|
|
|
|
fk_key = static_cast<Foreign_key*>(key); |
|
|
|
|
|
|
@ -884,24 +880,29 @@ innobase_get_foreign_key_info( |
|
|
|
add_fk[num_fk] = dict_mem_foreign_create(); |
|
|
|
|
|
|
|
#ifndef __WIN__
|
|
|
|
tbl_namep = fk_key->ref_table.str; |
|
|
|
tbl_name_len = fk_key->ref_table.length; |
|
|
|
db_namep = fk_key->ref_db.str; |
|
|
|
db_name_len = fk_key->ref_db.length; |
|
|
|
if(fk_key->ref_db.str) { |
|
|
|
tablename_to_filename(fk_key->ref_db.str, db_name, |
|
|
|
MAX_DATABASE_NAME_LEN); |
|
|
|
db_namep = db_name; |
|
|
|
db_name_len = strlen(db_name); |
|
|
|
} |
|
|
|
if (fk_key->ref_table.str) { |
|
|
|
tablename_to_filename(fk_key->ref_table.str, tbl_name, |
|
|
|
MAX_TABLE_NAME_LEN); |
|
|
|
tbl_namep = tbl_name; |
|
|
|
tbl_name_len = strlen(tbl_name); |
|
|
|
} |
|
|
|
#else
|
|
|
|
ut_ad(fk_key->ref_table.str); |
|
|
|
|
|
|
|
memcpy(tbl_name, fk_key->ref_table.str, |
|
|
|
fk_key->ref_table.length); |
|
|
|
tbl_name[fk_key->ref_table.length] = 0; |
|
|
|
tablename_to_filename(fk_key->ref_table.str, tbl_name, |
|
|
|
MAX_TABLE_NAME_LEN); |
|
|
|
innobase_casedn_str(tbl_name); |
|
|
|
tbl_name_len = strlen(tbl_name); |
|
|
|
tbl_namep = &tbl_name[0]; |
|
|
|
|
|
|
|
if (fk_key->ref_db.str != NULL) { |
|
|
|
memcpy(db_name, fk_key->ref_db.str, |
|
|
|
fk_key->ref_db.length); |
|
|
|
db_name[fk_key->ref_db.length] = 0; |
|
|
|
tablename_to_filename(fk_key->ref_db.str, db_name, |
|
|
|
MAX_DATABASE_NAME_LEN); |
|
|
|
innobase_casedn_str(db_name); |
|
|
|
db_name_len = strlen(db_name); |
|
|
|
db_namep = &db_name[0]; |
|
|
@ -3209,58 +3210,72 @@ innobase_check_foreign_key_index( |
|
|
|
ulint n_drop_fk) /*!< in: Number of foreign keys
|
|
|
|
to drop */ |
|
|
|
{ |
|
|
|
dict_foreign_t* foreign; |
|
|
|
ut_ad(index != NULL); |
|
|
|
ut_ad(indexed_table != NULL); |
|
|
|
|
|
|
|
/* Check if the index is referenced. */ |
|
|
|
foreign = dict_table_get_referenced_constraint(indexed_table, index); |
|
|
|
|
|
|
|
ut_ad(!foreign || indexed_table |
|
|
|
== foreign->referenced_table); |
|
|
|
|
|
|
|
if (foreign |
|
|
|
&& !dict_foreign_find_index( |
|
|
|
indexed_table, col_names, |
|
|
|
foreign->referenced_col_names, |
|
|
|
foreign->n_fields, index, |
|
|
|
/*check_charsets=*/TRUE, |
|
|
|
/*check_null=*/FALSE) |
|
|
|
&& !innobase_find_equiv_index( |
|
|
|
foreign->referenced_col_names, |
|
|
|
foreign->n_fields, |
|
|
|
ha_alter_info->key_info_buffer, |
|
|
|
ha_alter_info->index_add_buffer, |
|
|
|
ha_alter_info->index_add_count) |
|
|
|
) { |
|
|
|
trx->error_info = index; |
|
|
|
return(true); |
|
|
|
const dict_foreign_set* fks = &indexed_table->referenced_set; |
|
|
|
|
|
|
|
/* Check for all FK references from other tables to the index. */ |
|
|
|
for (dict_foreign_set::const_iterator it = fks->begin(); |
|
|
|
it != fks->end(); ++it) { |
|
|
|
|
|
|
|
dict_foreign_t* foreign = *it; |
|
|
|
if (foreign->referenced_index != index) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
ut_ad(indexed_table == foreign->referenced_table); |
|
|
|
|
|
|
|
if (NULL == dict_foreign_find_index( |
|
|
|
indexed_table, col_names, |
|
|
|
foreign->referenced_col_names, |
|
|
|
foreign->n_fields, index, |
|
|
|
/*check_charsets=*/TRUE, |
|
|
|
/*check_null=*/FALSE) |
|
|
|
&& NULL == innobase_find_equiv_index( |
|
|
|
foreign->referenced_col_names, |
|
|
|
foreign->n_fields, |
|
|
|
ha_alter_info->key_info_buffer, |
|
|
|
ha_alter_info->index_add_buffer, |
|
|
|
ha_alter_info->index_add_count)) { |
|
|
|
|
|
|
|
/* Index cannot be dropped. */ |
|
|
|
trx->error_info = index; |
|
|
|
return(true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Check if this index references some
|
|
|
|
other table */ |
|
|
|
foreign = dict_table_get_foreign_constraint( |
|
|
|
indexed_table, index); |
|
|
|
|
|
|
|
ut_ad(!foreign || indexed_table |
|
|
|
== foreign->foreign_table); |
|
|
|
|
|
|
|
if (foreign |
|
|
|
&& !innobase_dropping_foreign( |
|
|
|
foreign, drop_fk, n_drop_fk) |
|
|
|
&& !dict_foreign_find_index( |
|
|
|
indexed_table, col_names, |
|
|
|
foreign->foreign_col_names, |
|
|
|
foreign->n_fields, index, |
|
|
|
/*check_charsets=*/TRUE, |
|
|
|
/*check_null=*/FALSE) |
|
|
|
&& !innobase_find_equiv_index( |
|
|
|
foreign->foreign_col_names, |
|
|
|
foreign->n_fields, |
|
|
|
ha_alter_info->key_info_buffer, |
|
|
|
ha_alter_info->index_add_buffer, |
|
|
|
ha_alter_info->index_add_count) |
|
|
|
) { |
|
|
|
trx->error_info = index; |
|
|
|
return(true); |
|
|
|
fks = &indexed_table->foreign_set; |
|
|
|
|
|
|
|
/* Check for all FK references in current table using the index. */ |
|
|
|
for (dict_foreign_set::const_iterator it = fks->begin(); |
|
|
|
it != fks->end(); ++it) { |
|
|
|
|
|
|
|
dict_foreign_t* foreign = *it; |
|
|
|
if (foreign->foreign_index != index) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
ut_ad(indexed_table == foreign->foreign_table); |
|
|
|
|
|
|
|
if (!innobase_dropping_foreign( |
|
|
|
foreign, drop_fk, n_drop_fk) |
|
|
|
&& NULL == dict_foreign_find_index( |
|
|
|
indexed_table, col_names, |
|
|
|
foreign->foreign_col_names, |
|
|
|
foreign->n_fields, index, |
|
|
|
/*check_charsets=*/TRUE, |
|
|
|
/*check_null=*/FALSE) |
|
|
|
&& NULL == innobase_find_equiv_index( |
|
|
|
foreign->foreign_col_names, |
|
|
|
foreign->n_fields, |
|
|
|
ha_alter_info->key_info_buffer, |
|
|
|
ha_alter_info->index_add_buffer, |
|
|
|
ha_alter_info->index_add_count)) { |
|
|
|
|
|
|
|
/* Index cannot be dropped. */ |
|
|
|
trx->error_info = index; |
|
|
|
return(true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return(false); |
|
|
@ -3483,6 +3498,19 @@ check_if_ok_to_rename: |
|
|
|
if (index->type & DICT_FTS) { |
|
|
|
DBUG_ASSERT(index->type == DICT_FTS |
|
|
|
|| (index->type & DICT_CORRUPT)); |
|
|
|
|
|
|
|
/* We need to drop any corrupted fts indexes
|
|
|
|
before we add a new fts index. */ |
|
|
|
if (add_fts_idx && index->type & DICT_CORRUPT) { |
|
|
|
ib_errf(user_thd, IB_LOG_LEVEL_ERROR, |
|
|
|
ER_INNODB_INDEX_CORRUPT, |
|
|
|
"Fulltext index '%s' is corrupt. " |
|
|
|
"you should drop this index first.", |
|
|
|
index->name); |
|
|
|
|
|
|
|
goto err_exit_no_heap; |
|
|
|
} |
|
|
|
|
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|