Commit e2646f09 authored by unknown's avatar unknown

row0mysql.c:

  Allow always DROPping of a table which is only referenced by FOREIGN KEY constraints from the same table
Many files:
  Do not let REPLACE to perform internally an UPDATE if the table is referenced by a FOREIGN KEY: the manual says that REPLACE must resolve a duplicate key error semantically with DELETE(s) + INSERT, and not by an UPDATE; the internal update caused foreign key checks and cascaded operations to behave in a semantically wrong way


sql/ha_innodb.cc:
  Do not let REPLACE to perform internally an UPDATE if the table is referenced by a FOREIGN KEY: the manual says that REPLACE must resolve a duplicate key error semantically with DELETE(s) + INSERT, and not by an UPDATE; the internal update caused foreign key checks and cascaded operations to behave in a semantically wrong way
sql/sql_insert.cc:
  Do not let REPLACE to perform internally an UPDATE if the table is referenced by a FOREIGN KEY: the manual says that REPLACE must resolve a duplicate key error semantically with DELETE(s) + INSERT, and not by an UPDATE; the internal update caused foreign key checks and cascaded operations to behave in a semantically wrong way
sql/ha_innodb.h:
  Do not let REPLACE to perform internally an UPDATE if the table is referenced by a FOREIGN KEY: the manual says that REPLACE must resolve a duplicate key error semantically with DELETE(s) + INSERT, and not by an UPDATE; the internal update caused foreign key checks and cascaded operations to behave in a semantically wrong way
sql/handler.h:
  Do not let REPLACE to perform internally an UPDATE if the table is referenced by a FOREIGN KEY: the manual says that REPLACE must resolve a duplicate key error semantically with DELETE(s) + INSERT, and not by an UPDATE; the internal update caused foreign key checks and cascaded operations to behave in a semantically wrong way
innobase/dict/dict0dict.c:
  Do not let REPLACE to perform internally an UPDATE if the table is referenced by a FOREIGN KEY: the manual says that REPLACE must resolve a duplicate key error semantically with DELETE(s) + INSERT, and not by an UPDATE; the internal update caused foreign key checks and cascaded operations to behave in a semantically wrong way
innobase/include/dict0dict.h:
  Do not let REPLACE to perform internally an UPDATE if the table is referenced by a FOREIGN KEY: the manual says that REPLACE must resolve a duplicate key error semantically with DELETE(s) + INSERT, and not by an UPDATE; the internal update caused foreign key checks and cascaded operations to behave in a semantically wrong way
innobase/row/row0mysql.c:
  Allow always DROPping of a table which is only referenced by FOREIGN KEY constraints from the same table
parent 17d4afc6
...@@ -1845,6 +1845,24 @@ dict_index_build_internal_non_clust( ...@@ -1845,6 +1845,24 @@ dict_index_build_internal_non_clust(
/*====================== FOREIGN KEY PROCESSING ========================*/ /*====================== FOREIGN KEY PROCESSING ========================*/
/*************************************************************************
Checks if a table is referenced by foreign keys. */
ibool
dict_table_referenced_by_foreign_key(
/*=================================*/
/* out: TRUE if table is referenced by a
foreign key */
dict_table_t* table) /* in: InnoDB table */
{
if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
return(TRUE);
}
return(FALSE);
}
/************************************************************************* /*************************************************************************
Frees a foreign key struct. */ Frees a foreign key struct. */
static static
......
...@@ -206,6 +206,15 @@ dict_foreign_add_to_cache( ...@@ -206,6 +206,15 @@ dict_foreign_add_to_cache(
/* out: DB_SUCCESS or error code */ /* out: DB_SUCCESS or error code */
dict_foreign_t* foreign); /* in, own: foreign key constraint */ dict_foreign_t* foreign); /* in, own: foreign key constraint */
/************************************************************************* /*************************************************************************
Checks if a table is referenced by foreign keys. */
ibool
dict_table_referenced_by_foreign_key(
/*=================================*/
/* out: TRUE if table is referenced by a
foreign key */
dict_table_t* table); /* in: InnoDB table */
/*************************************************************************
Scans a table create SQL string and adds to the data dictionary Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function the foreign key constraints declared in the string. This function
should be called after the indexes for a table have been created. should be called after the indexes for a table have been created.
......
...@@ -1997,8 +1997,15 @@ row_drop_table_for_mysql( ...@@ -1997,8 +1997,15 @@ row_drop_table_for_mysql(
goto funct_exit; goto funct_exit;
} }
/* Check if the table is referenced by foreign key constraints from
some other table (not the table itself) */
foreign = UT_LIST_GET_FIRST(table->referenced_list); foreign = UT_LIST_GET_FIRST(table->referenced_list);
while (foreign && foreign->foreign_table == table) {
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
}
if (foreign && trx->check_foreigns) { if (foreign && trx->check_foreigns) {
char* buf = dict_foreign_err_buf; char* buf = dict_foreign_err_buf;
......
...@@ -4291,6 +4291,27 @@ ha_innobase::get_foreign_key_create_info(void) ...@@ -4291,6 +4291,27 @@ ha_innobase::get_foreign_key_create_info(void)
return(str); return(str);
} }
/***********************************************************************
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
delete is then allowed internally to resolve a duplicate key conflict in
REPLACE, not an update. */
uint
ha_innobase::referenced_by_foreign_key(void)
/*========================================*/
/* out: > 0 if referenced by a FOREIGN KEY */
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
if (dict_table_referenced_by_foreign_key(prebuilt->table)) {
return(1);
}
return(0);
}
/*********************************************************************** /***********************************************************************
Frees the foreign key create info for a table stored in InnoDB, if it is Frees the foreign key create info for a table stored in InnoDB, if it is
non-NULL. */ non-NULL. */
......
...@@ -179,6 +179,7 @@ class ha_innobase: public handler ...@@ -179,6 +179,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();
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,
enum thr_lock_type lock_type); enum thr_lock_type lock_type);
......
...@@ -319,6 +319,8 @@ public: ...@@ -319,6 +319,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 */
virtual uint referenced_by_foreign_key() { return 0;} /* used in REPLACE;
is > 0 if table is referred by a FOREIGN KEY */
virtual void init_table_handle_for_HANDLER() virtual void init_table_handle_for_HANDLER()
{ return; } /* prepare InnoDB for HANDLER */ { return; } /* prepare InnoDB for HANDLER */
virtual void free_foreign_key_create_info(char* str) {} virtual void free_foreign_key_create_info(char* str) {}
......
...@@ -442,7 +442,15 @@ int write_record(TABLE *table,COPY_INFO *info) ...@@ -442,7 +442,15 @@ int write_record(TABLE *table,COPY_INFO *info)
HA_READ_KEY_EXACT)))) HA_READ_KEY_EXACT))))
goto err; goto err;
} }
if (last_uniq_key(table,key_nr)) /*
The manual defines the REPLACE semantics that it is either an INSERT or
DELETE(s) + INSERT; FOREIGN KEY checks do not function in the defined
way if we allow MySQL to convert the latter operation internally to an
UPDATE.
*/
if (last_uniq_key(table,key_nr)
&& !table->file->referenced_by_foreign_key())
{ {
if ((error=table->file->update_row(table->record[1],table->record[0]))) if ((error=table->file->update_row(table->record[1],table->record[0])))
goto err; goto err;
......
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