summaryrefslogtreecommitdiff
path: root/sql/sql_table.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r--sql/sql_table.cc64
1 files changed, 60 insertions, 4 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index dbcab9bb870..4aed06e3590 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2073,7 +2073,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
in its elements.
*/
table->table= find_table_for_mdl_upgrade(thd, table->db,
- table->table_name, false);
+ table->table_name, NULL);
if (!table->table)
DBUG_RETURN(true);
table->mdl_request.ticket= table->table->mdl_ticket;
@@ -3402,6 +3402,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
thd->change_item_tree(&sql_field->default_value->expr, item);
}
+ /* Virtual fields are always NULL */
+ if (sql_field->vcol_info)
+ sql_field->flags&= ~NOT_NULL_FLAG;
+
if (sql_field->default_value &&
sql_field->default_value->expr->basic_const_item() &&
(sql_field->sql_type == MYSQL_TYPE_SET ||
@@ -9481,8 +9485,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
Table can be found in the list of open tables in THD::all_temp_tables
list.
*/
- tbl.table= thd->find_temporary_table(&tbl);
+ if ((tbl.table= thd->find_temporary_table(&tbl)) == NULL)
+ goto err_new_table_cleanup;
new_table= tbl.table;
+ DBUG_ASSERT(new_table);
}
else
{
@@ -9495,9 +9501,59 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
alter_ctx.get_tmp_path(),
alter_ctx.new_db, alter_ctx.tmp_name,
true);
+ if (!new_table)
+ goto err_new_table_cleanup;
+
+ /*
+ Normally, an attempt to modify an FK parent table will cause
+ FK children to be prelocked, so the table-being-altered cannot
+ be modified by a cascade FK action, because ALTER holds a lock
+ and prelocking will wait.
+
+ But if a new FK is being added by this very ALTER, then the target
+ table is not locked yet (it's a temporary table). So, we have to
+ lock FK parents explicitly.
+ */
+ if (alter_info->flags & Alter_info::ADD_FOREIGN_KEY)
+ {
+ List <FOREIGN_KEY_INFO> fk_list;
+ List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list);
+ FOREIGN_KEY_INFO *fk;
+
+ /* tables_opened can be > 1 only for MERGE tables */
+ DBUG_ASSERT(tables_opened == 1);
+ DBUG_ASSERT(&table_list->next_global == thd->lex->query_tables_last);
+
+ new_table->file->get_foreign_key_list(thd, &fk_list);
+ while ((fk= fk_list_it++))
+ {
+ if (lower_case_table_names)
+ {
+ char buf[NAME_LEN];
+ uint len;
+ strmake_buf(buf, fk->referenced_db->str);
+ len = my_casedn_str(files_charset_info, buf);
+ thd->make_lex_string(fk->referenced_db, buf, len);
+ strmake_buf(buf, fk->referenced_table->str);
+ len = my_casedn_str(files_charset_info, buf);
+ thd->make_lex_string(fk->referenced_table, buf, len);
+ }
+ if (table_already_fk_prelocked(table_list, fk->referenced_db,
+ fk->referenced_table, TL_READ_NO_INSERT))
+ continue;
+
+ TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));
+ tl->init_one_table_for_prelocking(fk->referenced_db->str, fk->referenced_db->length,
+ fk->referenced_table->str, fk->referenced_table->length,
+ NULL, TL_READ_NO_INSERT, false, NULL, 0,
+ &thd->lex->query_tables_last);
+ }
+
+ if (open_tables(thd, &table_list->next_global, &tables_opened, 0,
+ &alter_prelocking_strategy))
+ goto err_new_table_cleanup;
+ }
}
- if (!new_table)
- goto err_new_table_cleanup;
/*
Note: In case of MERGE table, we do not attach children. We do not
copy data for MERGE tables. Only the children have data.