Commit b5328a7d authored by marko@hundin.mysql.fi's avatar marko@hundin.mysql.fi

InnoDB: Prevent ALTER TABLE ... ENGINE=...

if there are foreign key constraints on the table. (Bug #5574)
parent 699c35c8
...@@ -4789,6 +4789,32 @@ ha_innobase::get_foreign_key_create_info(void) ...@@ -4789,6 +4789,32 @@ ha_innobase::get_foreign_key_create_info(void)
return(str); return(str);
} }
/*********************************************************************
Checks if ALTER TABLE may change the storage engine of the table.
Changing storage engines is not allowed for tables for which there
are foreign key constraints (parent or child tables). */
bool
ha_innobase::can_switch_engines(void)
/*=================================*/
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
bool can_switch;
DBUG_ENTER("ha_innobase::can_switch_engines");
prebuilt->trx->op_info =
"determining if there are foreign key constraints";
row_mysql_lock_data_dictionary(prebuilt->trx);
can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
&& !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
row_mysql_unlock_data_dictionary(prebuilt->trx);
prebuilt->trx->op_info = "";
DBUG_RETURN(can_switch);
}
/*********************************************************************** /***********************************************************************
Checks if a table is referenced by a foreign key. The MySQL manual states that Checks if a table is referenced by a foreign key. The MySQL manual states that
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
......
...@@ -161,6 +161,7 @@ class ha_innobase: public handler ...@@ -161,6 +161,7 @@ class ha_innobase: public handler
int check(THD* thd, HA_CHECK_OPT* check_opt); int check(THD* thd, HA_CHECK_OPT* check_opt);
char* update_table_comment(const char* comment); char* update_table_comment(const char* comment);
char* get_foreign_key_create_info(); char* get_foreign_key_create_info();
bool can_switch_engines();
uint referenced_by_foreign_key(); uint referenced_by_foreign_key();
void free_foreign_key_create_info(char* str); void free_foreign_key_create_info(char* str);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
......
...@@ -450,6 +450,8 @@ public: ...@@ -450,6 +450,8 @@ public:
virtual void append_create_info(String *packet) {} virtual void append_create_info(String *packet) {}
virtual char* get_foreign_key_create_info() virtual char* get_foreign_key_create_info()
{ return(NULL);} /* gets foreign key create string from InnoDB */ { return(NULL);} /* gets foreign key create string from InnoDB */
/* used in ALTER TABLE; 1 if changing storage engine is allowed */
virtual bool can_switch_engines() { return 1; }
/* used in REPLACE; is > 0 if table is referred by a FOREIGN KEY */ /* used in REPLACE; is > 0 if table is referred by a FOREIGN KEY */
virtual uint referenced_by_foreign_key() { return 0;} virtual uint referenced_by_foreign_key() { return 0;}
virtual void init_table_handle_for_HANDLER() virtual void init_table_handle_for_HANDLER()
......
...@@ -3109,6 +3109,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -3109,6 +3109,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
/* Safety fix for innodb */ /* Safety fix for innodb */
if (lower_case_table_names) if (lower_case_table_names)
my_casedn_str(files_charset_info, tmp_name); my_casedn_str(files_charset_info, tmp_name);
if (new_db_type != old_db_type && !table->file->can_switch_engines()) {
my_error(ER_ROW_IS_REFERENCED, MYF(0));
goto err;
}
create_info->db_type=new_db_type; create_info->db_type=new_db_type;
if (!create_info->comment) if (!create_info->comment)
create_info->comment=table->comment; create_info->comment=table->comment;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment