mirror of
https://github.com/MariaDB/server.git
synced 2025-12-24 11:21:21 +03:00
* bzr merge -rtag:mariadb-10.0.9 maria/10.0
* Fix for post-merge build failures.
This commit is contained in:
474
sql/sql_table.cc
474
sql/sql_table.cc
@@ -2031,33 +2031,29 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
|
||||
bool error;
|
||||
Drop_table_error_handler err_handler;
|
||||
TABLE_LIST *table;
|
||||
|
||||
DBUG_ENTER("mysql_rm_table");
|
||||
|
||||
/* Disable drop of enabled log tables, must be done before name locking */
|
||||
for (table= tables; table; table= table->next_local)
|
||||
{
|
||||
if (check_if_log_table(table->db_length, table->db,
|
||||
table->table_name_length, table->table_name, true))
|
||||
{
|
||||
my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
|
||||
if (check_if_log_table(table, TRUE, "DROP"))
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_bootstrap)
|
||||
{
|
||||
for (table= tables; table; table= table->next_local)
|
||||
{
|
||||
LEX_STRING db_name= { table->db, table->db_length };
|
||||
LEX_STRING table_name= { table->table_name, table->table_name_length };
|
||||
if (table->open_type == OT_BASE_ONLY || !find_temporary_table(thd, table))
|
||||
(void) delete_statistics_for_table(thd, &db_name, &table_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!drop_temporary)
|
||||
{
|
||||
if (!in_bootstrap)
|
||||
{
|
||||
for (table= tables; table; table= table->next_local)
|
||||
{
|
||||
LEX_STRING db_name= { table->db, table->db_length };
|
||||
LEX_STRING table_name= { table->table_name, table->table_name_length };
|
||||
if (table->open_type == OT_BASE_ONLY ||
|
||||
!find_temporary_table(thd, table))
|
||||
(void) delete_statistics_for_table(thd, &db_name, &table_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!thd->locked_tables_mode)
|
||||
{
|
||||
if (lock_table_names(thd, tables, NULL,
|
||||
@@ -2107,7 +2103,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
|
||||
/* mark for close and remove all cached entries */
|
||||
thd->push_internal_handler(&err_handler);
|
||||
error= mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary,
|
||||
false, false);
|
||||
false, false, false);
|
||||
thd->pop_internal_handler();
|
||||
|
||||
if (error)
|
||||
@@ -2172,6 +2168,8 @@ static uint32 comment_length(THD *thd, uint32 comment_pos,
|
||||
@param drop_view Allow to delete VIEW .frm
|
||||
@param dont_log_query Don't write query to log files. This will also not
|
||||
generate warnings if the handler files doesn't exists
|
||||
@param dont_free_locks Don't do automatic UNLOCK TABLE if no more locked
|
||||
tables
|
||||
|
||||
@retval 0 ok
|
||||
@retval 1 Error
|
||||
@@ -2194,7 +2192,8 @@ static uint32 comment_length(THD *thd, uint32 comment_pos,
|
||||
|
||||
int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
bool drop_temporary, bool drop_view,
|
||||
bool dont_log_query)
|
||||
bool dont_log_query,
|
||||
bool dont_free_locks)
|
||||
{
|
||||
TABLE_LIST *table;
|
||||
char path[FN_REFLEN + 1], wrong_tables_buff[160], *alias= NULL;
|
||||
@@ -2208,6 +2207,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
|
||||
bool non_tmp_table_deleted= 0;
|
||||
bool is_drop_tmp_if_exists_added= 0;
|
||||
bool one_table= tables->next_local == 0;
|
||||
bool was_view= 0;
|
||||
String built_query;
|
||||
String built_trans_tmp_query, built_non_trans_tmp_query;
|
||||
DBUG_ENTER("mysql_rm_table_no_locks");
|
||||
@@ -2286,7 +2287,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
|
||||
for (table= tables; table; table= table->next_local)
|
||||
{
|
||||
bool is_trans;
|
||||
bool is_trans= 0;
|
||||
char *db=table->db;
|
||||
size_t db_length= table->db_length;
|
||||
handlerton *table_type= 0;
|
||||
@@ -2311,12 +2312,16 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
. 1 - a temporary table was not found.
|
||||
. -1 - a temporary table is used by an outer statement.
|
||||
*/
|
||||
if (table->open_type == OT_BASE_ONLY)
|
||||
if (table->open_type == OT_BASE_ONLY || !is_temporary_table(table))
|
||||
error= 1;
|
||||
else if ((error= drop_temporary_table(thd, table, &is_trans)) == -1)
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(thd->in_sub_stmt);
|
||||
goto err;
|
||||
if ((error= drop_temporary_table(thd, table->table, &is_trans)) == -1)
|
||||
{
|
||||
DBUG_ASSERT(thd->in_sub_stmt);
|
||||
goto err;
|
||||
}
|
||||
table->table= 0;
|
||||
}
|
||||
|
||||
if ((drop_temporary && if_exists) || !error)
|
||||
@@ -2384,7 +2389,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
This handles the case where a "DROP" was executed and a regular
|
||||
table "may be" dropped as drop_temporary is FALSE and error is
|
||||
TRUE. If the error was FALSE a temporary table was dropped and
|
||||
regardless of the status of drop_tempoary a "DROP TEMPORARY"
|
||||
regardless of the status of drop_temporary a "DROP TEMPORARY"
|
||||
must be used.
|
||||
*/
|
||||
if (!dont_log_query)
|
||||
@@ -2412,15 +2417,15 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
}
|
||||
DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table");
|
||||
error= 0;
|
||||
if ((drop_temporary || !ha_table_exists(thd, db, alias, &table_type) ||
|
||||
(!drop_view && table_type == view_pseudo_hton)))
|
||||
if (drop_temporary ||
|
||||
(ha_table_exists(thd, db, alias, &table_type) == 0 && table_type == 0) ||
|
||||
(!drop_view && (was_view= (table_type == view_pseudo_hton))))
|
||||
{
|
||||
/*
|
||||
One of the following cases happened:
|
||||
. "DROP TEMPORARY" but a temporary table was not found.
|
||||
. "DROP" but table was not found on disk and table can't be
|
||||
created from engine.
|
||||
. ./sql/datadict.cc +32 /Alfranio - TODO: We need to test this.
|
||||
. "DROP" but table was not found
|
||||
. "DROP TABLE" statement, but it's a view.
|
||||
*/
|
||||
if (if_exists)
|
||||
{
|
||||
@@ -2544,7 +2549,10 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
err:
|
||||
if (wrong_tables.length())
|
||||
{
|
||||
if (!foreign_key_error)
|
||||
if (one_table && was_view)
|
||||
my_printf_error(ER_IT_IS_A_VIEW, ER(ER_IT_IS_A_VIEW), MYF(0),
|
||||
wrong_tables.c_ptr_safe());
|
||||
else if (!foreign_key_error)
|
||||
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
|
||||
wrong_tables.c_ptr_safe());
|
||||
else
|
||||
@@ -2610,7 +2618,8 @@ err:
|
||||
*/
|
||||
if (thd->locked_tables_mode)
|
||||
{
|
||||
if (thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0)
|
||||
if (thd->lock && thd->lock->table_count == 0 &&
|
||||
non_temp_tables_count > 0 && !dont_free_locks)
|
||||
{
|
||||
thd->locked_tables_list.unlock_locked_tables(thd);
|
||||
goto end;
|
||||
@@ -3793,7 +3802,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
with length (unlike blobs, where ft code takes data length from a
|
||||
data prefix, ignoring column->length).
|
||||
*/
|
||||
column->length=test(f_is_blob(sql_field->pack_flag));
|
||||
column->length= MY_TEST(f_is_blob(sql_field->pack_flag));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4517,12 +4526,13 @@ err:
|
||||
way to ensure that concurrent operations won't intervene.
|
||||
mysql_create_table() is a wrapper that can be used for this.
|
||||
|
||||
@retval false OK
|
||||
@retval true error
|
||||
@retval 0 OK
|
||||
@retval 1 error
|
||||
@retval -1 table existed but IF EXISTS was used
|
||||
*/
|
||||
|
||||
static
|
||||
bool create_table_impl(THD *thd,
|
||||
int create_table_impl(THD *thd,
|
||||
const char *db, const char *table_name,
|
||||
const char *path,
|
||||
HA_CREATE_INFO *create_info,
|
||||
@@ -4535,7 +4545,7 @@ bool create_table_impl(THD *thd,
|
||||
{
|
||||
const char *alias;
|
||||
handler *file= 0;
|
||||
bool error= TRUE;
|
||||
int error= 1;
|
||||
bool frm_only= create_table_mode == C_ALTER_TABLE_FRM_ONLY;
|
||||
bool internal_tmp_table= create_table_mode == C_ALTER_TABLE || frm_only;
|
||||
DBUG_ENTER("mysql_create_table_no_lock");
|
||||
@@ -4565,22 +4575,74 @@ bool create_table_impl(THD *thd,
|
||||
/* Check if table exists */
|
||||
if (create_info->tmp_table())
|
||||
{
|
||||
if (find_temporary_table(thd, db, table_name))
|
||||
TABLE *tmp_table;
|
||||
if ((tmp_table= find_temporary_table(thd, db, table_name)))
|
||||
{
|
||||
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
||||
if (create_info->options & HA_LEX_CREATE_REPLACE)
|
||||
{
|
||||
bool is_trans;
|
||||
/*
|
||||
We are using CREATE OR REPLACE on an existing temporary table
|
||||
Remove the old table so that we can re-create it.
|
||||
*/
|
||||
if (drop_temporary_table(thd, tmp_table, &is_trans))
|
||||
goto err;
|
||||
}
|
||||
else if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
||||
goto warn;
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
|
||||
goto err;
|
||||
else
|
||||
{
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if (!internal_tmp_table && ha_table_exists(thd, db, table_name))
|
||||
{
|
||||
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
||||
if (create_info->options & HA_LEX_CREATE_REPLACE)
|
||||
{
|
||||
TABLE_LIST table_list;
|
||||
table_list.init_one_table(db, strlen(db), table_name,
|
||||
strlen(table_name), table_name,
|
||||
TL_WRITE_ALLOW_WRITE);
|
||||
table_list.table= create_info->table;
|
||||
|
||||
if (check_if_log_table(&table_list, TRUE, "CREATE OR REPLACE"))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
Rollback the empty transaction started in mysql_create_table()
|
||||
call to open_and_lock_tables() when we are using LOCK TABLES.
|
||||
*/
|
||||
(void) trans_rollback_stmt(thd);
|
||||
/* Remove normal table without logging. Keep tables locked */
|
||||
if (mysql_rm_table_no_locks(thd, &table_list, 0, 0, 0, 1, 1))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
We have to log this query, even if it failed later to ensure the
|
||||
drop is done.
|
||||
*/
|
||||
thd->variables.option_bits|= OPTION_KEEP_LOG;
|
||||
thd->log_current_statement= 1;
|
||||
|
||||
/*
|
||||
The test of query_tables is to ensure we have any tables in the
|
||||
select part
|
||||
*/
|
||||
if (thd->lex->query_tables &&
|
||||
restart_trans_for_tables(thd, thd->lex->query_tables->next_global))
|
||||
goto err;
|
||||
}
|
||||
else if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
||||
goto warn;
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
|
||||
goto err;
|
||||
else
|
||||
{
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4702,14 +4764,14 @@ bool create_table_impl(THD *thd,
|
||||
}
|
||||
#endif
|
||||
|
||||
error= FALSE;
|
||||
error= 0;
|
||||
err:
|
||||
THD_STAGE_INFO(thd, stage_after_create);
|
||||
delete file;
|
||||
DBUG_RETURN(error);
|
||||
|
||||
warn:
|
||||
error= FALSE;
|
||||
error= -1;
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
|
||||
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
|
||||
alias);
|
||||
@@ -4720,7 +4782,8 @@ warn:
|
||||
Simple wrapper around create_table_impl() to be used
|
||||
in various version of CREATE TABLE statement.
|
||||
*/
|
||||
bool mysql_create_table_no_lock(THD *thd,
|
||||
|
||||
int mysql_create_table_no_lock(THD *thd,
|
||||
const char *db, const char *table_name,
|
||||
HA_CREATE_INFO *create_info,
|
||||
Alter_info *alter_info, bool *is_trans,
|
||||
@@ -4728,6 +4791,7 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
{
|
||||
KEY *not_used_1;
|
||||
uint not_used_2;
|
||||
int res;
|
||||
char path[FN_REFLEN + 1];
|
||||
LEX_CUSTRING frm= {0,0};
|
||||
|
||||
@@ -4747,9 +4811,9 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
}
|
||||
}
|
||||
|
||||
bool res= create_table_impl(thd, db, table_name, path, create_info,
|
||||
alter_info, create_table_mode, is_trans,
|
||||
¬_used_1, ¬_used_2, &frm);
|
||||
res= create_table_impl(thd, db, table_name, path, create_info,
|
||||
alter_info, create_table_mode, is_trans,
|
||||
¬_used_1, ¬_used_2, &frm);
|
||||
my_free(const_cast<uchar*>(frm.str));
|
||||
return res;
|
||||
}
|
||||
@@ -4771,16 +4835,23 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
|
||||
const char *db= create_table->db;
|
||||
const char *table_name= create_table->table_name;
|
||||
bool is_trans= FALSE;
|
||||
bool result= 0;
|
||||
int create_table_mode;
|
||||
TABLE_LIST *pos_in_locked_tables= 0;
|
||||
DBUG_ENTER("mysql_create_table");
|
||||
|
||||
DBUG_ASSERT(create_table == thd->lex->query_tables);
|
||||
|
||||
/* Open or obtain an exclusive metadata lock on table being created */
|
||||
if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0))
|
||||
{
|
||||
/* is_error() may be 0 if table existed and we generated a warning */
|
||||
DBUG_RETURN(thd->is_error());
|
||||
}
|
||||
|
||||
/* The following is needed only in case of lock tables */
|
||||
if ((create_info->table= thd->lex->query_tables->table))
|
||||
pos_in_locked_tables= create_info->table->pos_in_locked_tables;
|
||||
|
||||
/* Got lock. */
|
||||
DEBUG_SYNC(thd, "locked_table_name");
|
||||
|
||||
@@ -4791,15 +4862,42 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
|
||||
|
||||
promote_first_timestamp_column(&alter_info->create_list);
|
||||
if (mysql_create_table_no_lock(thd, db, table_name, create_info, alter_info,
|
||||
&is_trans, create_table_mode))
|
||||
DBUG_RETURN(1);
|
||||
&is_trans, create_table_mode) > 0)
|
||||
{
|
||||
result= 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
Check if we are doing CREATE OR REPLACE TABLE under LOCK TABLES
|
||||
on a non temporary table
|
||||
*/
|
||||
if (thd->locked_tables_mode && pos_in_locked_tables &&
|
||||
(create_info->options & HA_LEX_CREATE_REPLACE))
|
||||
{
|
||||
/*
|
||||
Add back the deleted table and re-created table as a locked table
|
||||
This should always work as we have a meta lock on the table.
|
||||
*/
|
||||
thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables);
|
||||
if (thd->locked_tables_list.reopen_tables(thd))
|
||||
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
|
||||
else
|
||||
{
|
||||
TABLE *table= pos_in_locked_tables->table;
|
||||
table->mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
/* In RBR we don't need to log CREATE TEMPORARY TABLE */
|
||||
if (thd->is_current_stmt_binlog_format_row() && create_info->tmp_table())
|
||||
DBUG_RETURN(0);
|
||||
|
||||
bool result;
|
||||
result= write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans);
|
||||
DBUG_RETURN(result);
|
||||
/* Write log if no error or if we already deleted a table */
|
||||
if (!result || thd->log_current_statement)
|
||||
if (write_bin_log(thd, result ? FALSE : TRUE, thd->query(),
|
||||
thd->query_length(), is_trans))
|
||||
result= 1;
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
@@ -4986,15 +5084,19 @@ mysql_rename_table(handlerton *base, const char *old_db,
|
||||
TRUE error
|
||||
*/
|
||||
|
||||
bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
|
||||
TABLE_LIST* src_table,
|
||||
HA_CREATE_INFO *create_info)
|
||||
{
|
||||
HA_CREATE_INFO local_create_info;
|
||||
TABLE_LIST *pos_in_locked_tables= 0;
|
||||
Alter_info local_alter_info;
|
||||
Alter_table_ctx local_alter_ctx; // Not used
|
||||
bool res= TRUE;
|
||||
bool is_trans= FALSE;
|
||||
bool do_logging= FALSE;
|
||||
uint not_used;
|
||||
int create_res;
|
||||
DBUG_ENTER("mysql_create_like_table");
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
@@ -5038,7 +5140,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
String query(buf, sizeof(buf), system_charset_info);
|
||||
query.length(0); // Have to zero it since constructor doesn't
|
||||
|
||||
(void) store_create_info(thd, &tbl, &query, NULL, TRUE);
|
||||
(void) store_create_info(thd, &tbl, &query, NULL, TRUE, FALSE);
|
||||
WSREP_DEBUG("TMP TABLE: %s", query.ptr());
|
||||
|
||||
thd->wsrep_TOI_pre_query= query.ptr();
|
||||
@@ -5068,6 +5170,18 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
res= thd->is_error();
|
||||
goto err;
|
||||
}
|
||||
/* Ensure we don't try to create something from which we select from */
|
||||
if ((create_info->options & HA_LEX_CREATE_REPLACE) &&
|
||||
!create_info->tmp_table())
|
||||
{
|
||||
TABLE_LIST *duplicate;
|
||||
if ((duplicate= unique_table(thd, table, src_table, 0)))
|
||||
{
|
||||
update_non_unique_table_error(src_table, "CREATE", duplicate);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
src_table->table->use_all_columns();
|
||||
|
||||
DEBUG_SYNC(thd, "create_table_like_after_open");
|
||||
@@ -5095,7 +5209,9 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
if (src_table->schema_table)
|
||||
local_create_info.max_rows= 0;
|
||||
/* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */
|
||||
local_create_info.options|= create_info->options&HA_LEX_CREATE_IF_NOT_EXISTS;
|
||||
local_create_info.options|= (create_info->options &
|
||||
(HA_LEX_CREATE_IF_NOT_EXISTS |
|
||||
HA_LEX_CREATE_REPLACE));
|
||||
/* Replace type of source table with one specified in the statement. */
|
||||
local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
|
||||
local_create_info.options|= create_info->tmp_table();
|
||||
@@ -5107,19 +5223,54 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
*/
|
||||
local_create_info.data_file_name= local_create_info.index_file_name= NULL;
|
||||
|
||||
if ((res= mysql_create_table_no_lock(thd, table->db, table->table_name,
|
||||
&local_create_info, &local_alter_info,
|
||||
&is_trans, C_ORDINARY_CREATE)))
|
||||
/* The following is needed only in case of lock tables */
|
||||
if ((local_create_info.table= thd->lex->query_tables->table))
|
||||
pos_in_locked_tables= local_create_info.table->pos_in_locked_tables;
|
||||
|
||||
res= ((create_res=
|
||||
mysql_create_table_no_lock(thd, table->db, table->table_name,
|
||||
&local_create_info, &local_alter_info,
|
||||
&is_trans, C_ORDINARY_CREATE)) > 0);
|
||||
/* Remember to log if we deleted something */
|
||||
do_logging= thd->log_current_statement;
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
Ensure that we have an exclusive lock on target table if we are creating
|
||||
non-temporary table.
|
||||
Check if we are doing CREATE OR REPLACE TABLE under LOCK TABLES
|
||||
on a non temporary table
|
||||
*/
|
||||
DBUG_ASSERT((create_info->tmp_table()) ||
|
||||
thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
|
||||
table->table_name,
|
||||
MDL_EXCLUSIVE));
|
||||
if (thd->locked_tables_mode && pos_in_locked_tables &&
|
||||
(create_info->options & HA_LEX_CREATE_REPLACE))
|
||||
{
|
||||
/*
|
||||
Add back the deleted table and re-created table as a locked table
|
||||
This should always work as we have a meta lock on the table.
|
||||
*/
|
||||
thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables);
|
||||
if (thd->locked_tables_list.reopen_tables(thd))
|
||||
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
|
||||
else
|
||||
{
|
||||
/*
|
||||
Get pointer to the newly opened table. We need this to ensure we
|
||||
don't reopen the table when doing statment logging below.
|
||||
*/
|
||||
table->table= pos_in_locked_tables->table;
|
||||
table->table->mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Ensure that we have an exclusive lock on target table if we are creating
|
||||
non-temporary table.
|
||||
*/
|
||||
DBUG_ASSERT((create_info->tmp_table()) ||
|
||||
thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
|
||||
table->table_name,
|
||||
MDL_EXCLUSIVE));
|
||||
}
|
||||
|
||||
DEBUG_SYNC(thd, "create_table_like_before_binlog");
|
||||
|
||||
@@ -5138,7 +5289,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
Case Target Source Write to binary log
|
||||
==== ========= ========= ==============================
|
||||
1 normal normal Original statement
|
||||
2 normal temporary Generated statement
|
||||
2 normal temporary Generated statement if the table
|
||||
was created.
|
||||
3 temporary normal Nothing
|
||||
4 temporary temporary Nothing
|
||||
==== ========= ========= ==============================
|
||||
@@ -5153,36 +5305,59 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
|
||||
bool new_table= FALSE; // Whether newly created table is open.
|
||||
|
||||
if (create_res != 0)
|
||||
{
|
||||
/*
|
||||
Table or view with same name already existed and we where using
|
||||
IF EXISTS. Continue without logging anything.
|
||||
*/
|
||||
goto err;
|
||||
}
|
||||
if (!table->table)
|
||||
{
|
||||
TABLE_LIST::enum_open_strategy save_open_strategy;
|
||||
int open_res;
|
||||
/* Force the newly created table to be opened */
|
||||
save_open_strategy= table->open_strategy;
|
||||
table->open_strategy= TABLE_LIST::OPEN_NORMAL;
|
||||
|
||||
/*
|
||||
In order for store_create_info() to work we need to open
|
||||
destination table if it is not already open (i.e. if it
|
||||
has not existed before). We don't need acquire metadata
|
||||
lock in order to do this as we already hold exclusive
|
||||
lock on this table. The table will be closed by
|
||||
close_thread_table() at the end of this branch.
|
||||
*/
|
||||
open_res= open_table(thd, table, thd->mem_root, &ot_ctx);
|
||||
/* Restore */
|
||||
table->open_strategy= save_open_strategy;
|
||||
if (open_res)
|
||||
{
|
||||
res= 1;
|
||||
goto err;
|
||||
}
|
||||
new_table= TRUE;
|
||||
}
|
||||
/*
|
||||
The condition avoids a crash as described in BUG#48506. Other
|
||||
binlogging problems related to CREATE TABLE IF NOT EXISTS LIKE
|
||||
when the existing object is a view will be solved by BUG 47442.
|
||||
We have to re-test if the table was a view as the view may not
|
||||
have been opened until just above.
|
||||
*/
|
||||
if (!table->view)
|
||||
{
|
||||
if (!table->table)
|
||||
{
|
||||
|
||||
/*
|
||||
In order for store_create_info() to work we need to open
|
||||
destination table if it is not already open (i.e. if it
|
||||
has not existed before). We don't need acquire metadata
|
||||
lock in order to do this as we already hold exclusive
|
||||
lock on this table. The table will be closed by
|
||||
close_thread_table() at the end of this branch.
|
||||
*/
|
||||
if (open_table(thd, table, thd->mem_root, &ot_ctx))
|
||||
goto err;
|
||||
new_table= TRUE;
|
||||
}
|
||||
|
||||
int result __attribute__((unused))=
|
||||
store_create_info(thd, table, &query,
|
||||
create_info, FALSE /* show_database */);
|
||||
create_info, FALSE /* show_database */,
|
||||
MY_TEST(create_info->options &
|
||||
HA_LEX_CREATE_REPLACE));
|
||||
|
||||
DBUG_ASSERT(result == 0); // store_create_info() always return 0
|
||||
do_logging= FALSE;
|
||||
if (write_bin_log(thd, TRUE, query.ptr(), query.length()))
|
||||
{
|
||||
res= 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (new_table)
|
||||
{
|
||||
@@ -5197,17 +5372,20 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
}
|
||||
}
|
||||
else // Case 1
|
||||
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
|
||||
goto err;
|
||||
do_logging= TRUE;
|
||||
}
|
||||
/*
|
||||
Case 3 and 4 does nothing under RBR
|
||||
*/
|
||||
}
|
||||
else if (write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans))
|
||||
goto err;
|
||||
else
|
||||
do_logging= TRUE;
|
||||
|
||||
err:
|
||||
if (do_logging &&
|
||||
write_bin_log(thd, res ? FALSE : TRUE, thd->query(),
|
||||
thd->query_length(), is_trans))
|
||||
res= 1;
|
||||
DBUG_RETURN(res);
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
@@ -5365,7 +5543,8 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
|
||||
{
|
||||
alter_info->flags&= ~Alter_info::ALTER_ADD_COLUMN;
|
||||
if (alter_info->key_list.is_empty())
|
||||
alter_info->flags&= ~Alter_info::ALTER_ADD_INDEX;
|
||||
alter_info->flags&= ~(Alter_info::ALTER_ADD_INDEX |
|
||||
Alter_info::ADD_FOREIGN_KEY);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5440,13 +5619,32 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
|
||||
else /* Alter_drop::KEY */
|
||||
{
|
||||
uint n_key;
|
||||
for (n_key=0; n_key < table->s->keys; n_key++)
|
||||
if (drop->type != Alter_drop::FOREIGN_KEY)
|
||||
{
|
||||
if (my_strcasecmp(system_charset_info,
|
||||
drop->name, table->key_info[n_key].name) == 0)
|
||||
for (n_key=0; n_key < table->s->keys; n_key++)
|
||||
{
|
||||
remove_drop= FALSE;
|
||||
break;
|
||||
if (my_strcasecmp(system_charset_info,
|
||||
drop->name, table->key_info[n_key].name) == 0)
|
||||
{
|
||||
remove_drop= FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
List <FOREIGN_KEY_INFO> fk_child_key_list;
|
||||
FOREIGN_KEY_INFO *f_key;
|
||||
table->file->get_foreign_key_list(thd, &fk_child_key_list);
|
||||
List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list);
|
||||
while ((f_key= fk_key_it++))
|
||||
{
|
||||
if (my_strcasecmp(system_charset_info, f_key->foreign_id->str,
|
||||
drop->name) == 0)
|
||||
{
|
||||
remove_drop= FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5458,7 +5656,8 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
|
||||
drop_it.remove();
|
||||
if (alter_info->drop_list.is_empty())
|
||||
alter_info->flags&= ~(Alter_info::ALTER_DROP_COLUMN |
|
||||
Alter_info::ALTER_DROP_INDEX);
|
||||
Alter_info::ALTER_DROP_INDEX |
|
||||
Alter_info::DROP_FOREIGN_KEY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5469,6 +5668,7 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
|
||||
Key *key;
|
||||
List_iterator<Key> key_it(alter_info->key_list);
|
||||
uint n_key;
|
||||
bool remove_key;
|
||||
const char *keyname;
|
||||
while ((key=key_it++))
|
||||
{
|
||||
@@ -5485,24 +5685,48 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
|
||||
if (keyname == NULL)
|
||||
continue;
|
||||
}
|
||||
for (n_key=0; n_key < table->s->keys; n_key++)
|
||||
remove_key= FALSE;
|
||||
if (key->type != Key::FOREIGN_KEY)
|
||||
{
|
||||
if (my_strcasecmp(system_charset_info,
|
||||
keyname, table->key_info[n_key].name) == 0)
|
||||
for (n_key=0; n_key < table->s->keys; n_key++)
|
||||
{
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
|
||||
ER_DUP_KEYNAME, ER(ER_DUP_KEYNAME), keyname);
|
||||
key_it.remove();
|
||||
if (key->type == Key::FOREIGN_KEY)
|
||||
if (my_strcasecmp(system_charset_info,
|
||||
keyname, table->key_info[n_key].name) == 0)
|
||||
{
|
||||
/* ADD FOREIGN KEY appends two items. */
|
||||
key_it.remove();
|
||||
remove_key= TRUE;
|
||||
break;
|
||||
}
|
||||
if (alter_info->key_list.is_empty())
|
||||
alter_info->flags&= ~Alter_info::ALTER_ADD_INDEX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
List <FOREIGN_KEY_INFO> fk_child_key_list;
|
||||
FOREIGN_KEY_INFO *f_key;
|
||||
table->file->get_foreign_key_list(thd, &fk_child_key_list);
|
||||
List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list);
|
||||
while ((f_key= fk_key_it++))
|
||||
{
|
||||
if (my_strcasecmp(system_charset_info, f_key->foreign_id->str,
|
||||
key->name.str) == 0)
|
||||
remove_key= TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (remove_key)
|
||||
{
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
|
||||
ER_DUP_KEYNAME, ER(ER_DUP_KEYNAME), keyname);
|
||||
key_it.remove();
|
||||
if (key->type == Key::FOREIGN_KEY)
|
||||
{
|
||||
/* ADD FOREIGN KEY appends two items. */
|
||||
key_it.remove();
|
||||
}
|
||||
if (alter_info->key_list.is_empty())
|
||||
alter_info->flags&= ~(Alter_info::ALTER_ADD_INDEX |
|
||||
Alter_info::ADD_FOREIGN_KEY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5732,9 +5956,6 @@ static bool fill_alter_inplace_info(THD *thd,
|
||||
|
||||
if (new_field)
|
||||
{
|
||||
ha_alter_info->create_info->fields_option_struct[f_ptr - table->field]=
|
||||
new_field->option_struct;
|
||||
|
||||
/* Field is not dropped. Evaluate changes bitmap for it. */
|
||||
|
||||
/*
|
||||
@@ -5846,6 +6067,15 @@ static bool fill_alter_inplace_info(THD *thd,
|
||||
if (new_field->column_format() != field->column_format())
|
||||
ha_alter_info->handler_flags|=
|
||||
Alter_inplace_info::ALTER_COLUMN_COLUMN_FORMAT;
|
||||
|
||||
if (engine_options_differ(field->option_struct, new_field->option_struct,
|
||||
table->file->ht->field_options))
|
||||
{
|
||||
ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_OPTION;
|
||||
ha_alter_info->create_info->fields_option_struct[f_ptr - table->field]=
|
||||
new_field->option_struct;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -7226,7 +7456,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
|
||||
key= new Key(key_type, key_name, strlen(key_name),
|
||||
&key_create_info,
|
||||
test(key_info->flags & HA_GENERATED_KEY),
|
||||
MY_TEST(key_info->flags & HA_GENERATED_KEY),
|
||||
key_parts, key_info->option_list, FALSE);
|
||||
new_key_list.push_back(key);
|
||||
}
|
||||
@@ -7798,9 +8028,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
it is the case.
|
||||
TODO: this design is obsolete and will be removed.
|
||||
*/
|
||||
int table_kind= check_if_log_table(table_list->db_length, table_list->db,
|
||||
table_list->table_name_length,
|
||||
table_list->table_name, false);
|
||||
int table_kind= check_if_log_table(table_list, FALSE, NullS);
|
||||
|
||||
if (table_kind)
|
||||
{
|
||||
@@ -8841,7 +9069,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
|
||||
DBUG_ENTER("copy_data_between_tables");
|
||||
|
||||
/* Two or 3 stages; Sorting, copying data and update indexes */
|
||||
thd_progress_init(thd, 2 + test(order));
|
||||
thd_progress_init(thd, 2 + MY_TEST(order));
|
||||
|
||||
if (mysql_trans_prepare_alter_copy_data(thd))
|
||||
DBUG_RETURN(-1);
|
||||
@@ -9342,7 +9570,7 @@ static bool check_engine(THD *thd, const char *db_name,
|
||||
handlerton **new_engine= &create_info->db_type;
|
||||
handlerton *req_engine= *new_engine;
|
||||
bool no_substitution=
|
||||
test(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION);
|
||||
MY_TEST(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION);
|
||||
if (!(*new_engine= ha_checktype(thd, ha_legacy_type(req_engine),
|
||||
no_substitution, 1)))
|
||||
DBUG_RETURN(true);
|
||||
|
||||
Reference in New Issue
Block a user