summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/ddl_log.cc201
-rw-r--r--sql/ddl_log.h21
-rw-r--r--sql/ha_partition.cc526
-rw-r--r--sql/ha_partition.h20
-rw-r--r--sql/handler.cc62
-rw-r--r--sql/handler.h21
-rw-r--r--sql/lex_string.h4
-rw-r--r--sql/partition_element.h25
-rw-r--r--sql/partition_info.h4
-rw-r--r--sql/sql_partition.cc1940
-rw-r--r--sql/sql_partition.h11
-rw-r--r--sql/sql_partition_admin.cc61
-rw-r--r--sql/sql_rename.cc2
-rw-r--r--sql/sql_table.cc84
-rw-r--r--sql/sql_table.h34
-rw-r--r--sql/sql_trigger.cc4
16 files changed, 900 insertions, 2120 deletions
diff --git a/sql/ddl_log.cc b/sql/ddl_log.cc
index 199b1df9623..e2c3271261b 100644
--- a/sql/ddl_log.cc
+++ b/sql/ddl_log.cc
@@ -85,8 +85,8 @@ uchar ddl_log_file_magic[]=
const char *ddl_log_action_name[DDL_LOG_LAST_ACTION]=
{
- "Unknown", "partitioning delete", "partitioning rename",
- "partitioning replace", "partitioning exchange",
+ "Unknown", "file delete", "file rename",
+ "file replace", "partitioning exchange",
"rename table", "rename view",
"initialize drop table", "drop table",
"drop view", "drop trigger", "drop db", "create table", "create view",
@@ -1323,7 +1323,8 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
uint entry_pos= ddl_log_entry->entry_pos;
int error= 0;
uint fn_flags= 0;
- bool frm_action= FALSE;
+ PSI_file_key key= key_file_misc;
+ const bool alter_partition= ddl_log_entry->flags & DDL_LOG_FLAG_ALTER_PARTITION;
DBUG_ENTER("ddl_log_execute_action");
mysql_mutex_assert_owner(&LOCK_gdl);
@@ -1356,12 +1357,17 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
if (!report_error)
thd->push_internal_handler(&no_such_table_handler);
- if (!strcmp(ddl_log_entry->handler_name.str, reg_ext))
- frm_action= TRUE;
- else if (ddl_log_entry->handler_name.length)
+ if (ddl_log_entry->action_type <= DDL_LOG_FILE_REPLACE_ACTION &&
+ ddl_log_entry->unique_id)
+ key= (PSI_file_key) ddl_log_entry->unique_id;
+
+ if (ddl_log_entry->handler_name.length)
{
if (!(file= create_handler(thd, mem_root, &handler_name)))
+ {
+ error= 1;
goto end;
+ }
hton= file->ht;
}
@@ -1371,65 +1377,34 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
fn_flags|= FN_TO_IS_TMP;
switch (ddl_log_entry->action_type) {
- case DDL_LOG_REPLACE_ACTION:
- case DDL_LOG_DELETE_ACTION:
+ case DDL_LOG_FILE_REPLACE_ACTION:
+ case DDL_LOG_FILE_DELETE_ACTION:
{
+ /* DDL_LOG_FILE_REPLACE_ACTION is 2 phases: delete and rename */
if (ddl_log_entry->phase == 0)
{
- if (frm_action)
- {
- strxmov(to_path, ddl_log_entry->name.str, reg_ext, NullS);
- if (unlikely((error= mysql_file_delete(key_file_frm, to_path,
- MYF(MY_WME |
- MY_IGNORE_ENOENT)))))
- break;
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- strxmov(to_path, ddl_log_entry->name.str, PAR_EXT, NullS);
- (void) mysql_file_delete(key_file_partition_ddl_log, to_path,
- MYF(0));
-#endif
- }
- else
- {
- if (unlikely((error= hton->drop_table(hton, ddl_log_entry->name.str))))
- {
- if (!non_existing_table_error(error))
- break;
- }
- }
+ if (unlikely((error= mysql_file_delete(key,
+ ddl_log_entry->name.str,
+ MYF(MY_WME | MY_IGNORE_ENOENT)))))
+ break;
if (increment_phase(entry_pos))
break;
error= 0;
- if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION)
+ if (ddl_log_entry->action_type == DDL_LOG_FILE_DELETE_ACTION)
break;
}
}
- DBUG_ASSERT(ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION);
+ DBUG_ASSERT(ddl_log_entry->action_type == DDL_LOG_FILE_REPLACE_ACTION);
/*
Fall through and perform the rename action of the replace
action. We have already indicated the success of the delete
action in the log entry by stepping up the phase.
*/
/* fall through */
- case DDL_LOG_RENAME_ACTION:
+ case DDL_LOG_FILE_RENAME_ACTION:
{
- if (frm_action)
- {
- strxmov(to_path, ddl_log_entry->name.str, reg_ext, NullS);
- strxmov(from_path, ddl_log_entry->from_name.str, reg_ext, NullS);
- error= mysql_file_rename(key_file_frm, from_path, to_path, MYF(MY_WME));
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- strxmov(to_path, ddl_log_entry->name.str, PAR_EXT, NullS);
- strxmov(from_path, ddl_log_entry->from_name.str, PAR_EXT, NullS);
- int err2= mysql_file_rename(key_file_partition_ddl_log, from_path,
- to_path, MYF(MY_WME));
- if (!error)
- error= err2;
-#endif
- }
- else
- error= file->ha_rename_table(ddl_log_entry->from_name.str,
- ddl_log_entry->name.str);
+ error= mysql_file_rename(key, ddl_log_entry->from_name.str,
+ ddl_log_entry->name.str, MYF(MY_WME));
if (increment_phase(entry_pos))
{
error= -1;
@@ -1442,7 +1417,6 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
/* We hold LOCK_gdl, so we can alter global_ddl_log.file_entry_buf */
uchar *file_entry_buf= global_ddl_log.file_entry_buf;
/* not yet implemented for frm */
- DBUG_ASSERT(!frm_action);
/*
Using a case-switch here to revert all currently done phases,
since it will fall through until the first phase is undone.
@@ -1488,11 +1462,13 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
*/
switch (ddl_log_entry->phase) {
case DDL_RENAME_PHASE_TRIGGER:
+ DBUG_ASSERT(!alter_partition);
rename_triggers(thd, ddl_log_entry, 0, fn_flags);
if (increment_phase(entry_pos))
break;
/* fall through */
case DDL_RENAME_PHASE_STAT:
+ DBUG_ASSERT(!alter_partition);
if (fn_flags & FN_TO_IS_TMP)
{
/*
@@ -1516,13 +1492,21 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
}
/* fall through */
case DDL_RENAME_PHASE_TABLE:
- /* Restore frm and table to original names */
- error= execute_rename_table(ddl_log_entry, file,
- &ddl_log_entry->db, &ddl_log_entry->name,
- &ddl_log_entry->from_db,
- &ddl_log_entry->from_name,
- fn_flags, from_path, to_path);
+ if (alter_partition)
+ {
+ error= file->ha_rename_table(ddl_log_entry->from_name.str,
+ ddl_log_entry->name.str);
+ }
+ else
+ {
+ /* Restore frm and table to original names */
+ error= execute_rename_table(ddl_log_entry, file,
+ &ddl_log_entry->db, &ddl_log_entry->name,
+ &ddl_log_entry->from_db,
+ &ddl_log_entry->from_name,
+ fn_flags, from_path, to_path);
+ }
if (ddl_log_entry->flags & DDL_LOG_FLAG_UPDATE_STAT)
{
/* Update stat tables last */
@@ -1615,7 +1599,10 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
}
}
else
+ {
+ DBUG_ASSERT(!alter_partition);
error= ha_delete_table_force(thd, path.str, &db, &table);
+ }
if (error <= 0)
{
/* Not found or already deleted. Delete .frm if it exists */
@@ -1627,14 +1614,14 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
break;
/* Fall through */
case DDL_DROP_PHASE_TRIGGER:
- Table_triggers_list::drop_all_triggers(thd, &db, &table,
- fn_flags,
- MYF(MY_WME | MY_IGNORE_ENOENT));
+ if (!alter_partition)
+ Table_triggers_list::drop_all_triggers(thd, &db, &table, fn_flags,
+ MYF(MY_WME | MY_IGNORE_ENOENT));
if (increment_phase(entry_pos))
break;
/* Fall through */
case DDL_DROP_PHASE_BINLOG:
- if (fn_flags & FN_IS_TMP)
+ if (alter_partition || (fn_flags & FN_IS_TMP))
{
/*
If new code is added here please finish this block like this:
@@ -2031,7 +2018,10 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
if (!(org_file= create_handler(thd, mem_root,
&ddl_log_entry->from_handler_name)))
+ {
+ error= 1;
goto end;
+ }
/* Handlerton of the final table and any temporary tables */
org_hton= org_file->ht;
/*
@@ -2041,7 +2031,7 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
*/
partition_hton= hton;
- if (ddl_log_entry->flags & DDL_LOG_FLAG_ALTER_PARTITION)
+ if (alter_partition)
{
/*
The from and to tables where both using the partition engine.
@@ -2343,7 +2333,10 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
Query length is stored in unique_id
*/
if (recovery_state.query.alloc((size_t) (ddl_log_entry->unique_id+1)))
+ {
+ error= 1;
goto end;
+ }
recovery_state.query.length(0);
recovery_state.db.copy(ddl_log_entry->db.str, ddl_log_entry->db.length,
system_charset_info);
@@ -2375,7 +2368,7 @@ end:
/* If error code is HA_ERR_ code we already have file object. */
DBUG_ASSERT(file);
TABLE_SHARE share;
- bzero(&share, sizeof(share));
+ share.reset();
share.db= ddl_log_entry->db;
share.table_name= ddl_log_entry->name;
share.normalized_path= ddl_log_entry->tmp_name;
@@ -3041,7 +3034,7 @@ void ddl_log_complete(DDL_LOG_STATE *state)
This is called for failed rename table, create trigger or drop trigger.
*/
-bool ddl_log_revert(THD *thd, DDL_LOG_STATE *state)
+bool ddl_log_revert(THD *thd, DDL_LOG_STATE *state, bool report_error)
{
bool res= 0;
DBUG_ENTER("ddl_log_revert");
@@ -3054,7 +3047,7 @@ bool ddl_log_revert(THD *thd, DDL_LOG_STATE *state)
{
res= ddl_log_execute_entry_no_lock(thd, state->list->entry_pos,
state->execute_entry->entry_pos,
- true);
+ report_error);
ddl_log_disable_execute_entry(&state->execute_entry);
}
ddl_log_release_entries(state);
@@ -3159,8 +3152,8 @@ bool ddl_log_update_xid(DDL_LOG_STATE *state, ulonglong xid)
Will update DDL_LOG_STATE->flags
*/
-static bool ddl_log_write(DDL_LOG_STATE *ddl_state,
- DDL_LOG_ENTRY *ddl_log_entry)
+bool ddl_log_write(DDL_LOG_STATE *ddl_state,
+ DDL_LOG_ENTRY *ddl_log_entry)
{
int error;
DDL_LOG_MEMORY_ENTRY *log_entry;
@@ -3715,27 +3708,36 @@ err:
}
-/*
- Log an delete frm file
-*/
+/**
+ Log an delete frm file and par file
-/*
- TODO: Partitioning atomic DDL refactoring: this should be replaced with
- ddl_log_create_table().
+ @param to_path Location of frm file without extension
*/
+
bool ddl_log_delete_frm(DDL_LOG_STATE *ddl_state, const char *to_path)
{
+ char to_file[FN_REFLEN + 1];
DDL_LOG_ENTRY ddl_log_entry;
DDL_LOG_MEMORY_ENTRY *log_entry;
DBUG_ENTER("ddl_log_delete_frm");
bzero(&ddl_log_entry, sizeof(ddl_log_entry));
- ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
+ ddl_log_entry.action_type= DDL_LOG_FILE_DELETE_ACTION;
ddl_log_entry.next_entry= ddl_state->list ? ddl_state->list->entry_pos : 0;
- lex_string_set(&ddl_log_entry.handler_name, reg_ext);
- lex_string_set(&ddl_log_entry.name, to_path);
-
mysql_mutex_assert_owner(&LOCK_gdl);
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ strxmov(to_file, to_path, PAR_EXT, NullS);
+ lex_string_set(&ddl_log_entry.name, to_file);
+ ddl_log_entry.unique_id= (ulonglong) key_file_partition_ddl_log;
+ if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
+ DBUG_RETURN(1);
+
+ ddl_log_add_entry(ddl_state, log_entry);
+ ddl_log_entry.next_entry= ddl_state->list->entry_pos;
+#endif
+ strxmov(to_file, to_path, reg_ext, NullS);
+ lex_string_set(&ddl_log_entry.name, to_file);
+ ddl_log_entry.unique_id= (ulonglong) key_file_frm;
if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
DBUG_RETURN(1);
@@ -3743,6 +3745,53 @@ bool ddl_log_delete_frm(DDL_LOG_STATE *ddl_state, const char *to_path)
DBUG_RETURN(0);
}
+
+/**
+ Log an rename frm file and par file
+
+ @param from_path Location of frm file without extension
+ @param to_path Location of new frm file without extension
+*/
+
+bool ddl_log_rename_frm(DDL_LOG_STATE *ddl_state,
+ const char *from_path, const char *to_path)
+{
+ char to_file[FN_REFLEN + 1], from_file[FN_REFLEN + 1];
+ DDL_LOG_ENTRY ddl_log_entry;
+ DDL_LOG_MEMORY_ENTRY *log_entry;
+ DBUG_ENTER("ddl_log_rename_frm");
+
+ bzero(&ddl_log_entry, sizeof(ddl_log_entry));
+ ddl_log_entry.action_type= DDL_LOG_FILE_RENAME_ACTION;
+ ddl_log_entry.next_entry= ddl_state->list ? ddl_state->list->entry_pos : 0;
+
+ mysql_mutex_assert_owner(&LOCK_gdl);
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ strxmov(to_file, to_path, PAR_EXT, NullS);
+ strxmov(from_file, from_path, PAR_EXT, NullS);
+ lex_string_set(&ddl_log_entry.name, to_file);
+ lex_string_set(&ddl_log_entry.from_name, from_file);
+ ddl_log_entry.unique_id= (ulonglong) key_file_partition_ddl_log;
+ if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
+ DBUG_RETURN(1);
+
+ ddl_log_add_entry(ddl_state, log_entry);
+ ddl_log_entry.next_entry= ddl_state->list->entry_pos;
+#endif
+ strxmov(to_file, to_path, reg_ext, NullS);
+ strxmov(from_file, from_path, reg_ext, NullS);
+ lex_string_set(&ddl_log_entry.name, to_file);
+ lex_string_set(&ddl_log_entry.from_name, from_file);
+ ddl_log_entry.unique_id= (ulonglong) key_file_frm;
+
+ if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
+ DBUG_RETURN(true);
+
+ ddl_log_add_entry(ddl_state, log_entry);
+ DBUG_RETURN(false);
+}
+
+
/*
Link the ddl_log_state to another (master) chain. If the master
chain is active during DDL recovery, this event will not be executed.
diff --git a/sql/ddl_log.h b/sql/ddl_log.h
index 301f6a1cfa8..ab5eadc5eee 100644
--- a/sql/ddl_log.h
+++ b/sql/ddl_log.h
@@ -59,16 +59,16 @@ enum ddl_log_action_code
DDL_LOG_UNKNOWN_ACTION= 0,
/* Delete a .frm file or a table in the partition engine */
- DDL_LOG_DELETE_ACTION= 1,
+ DDL_LOG_FILE_DELETE_ACTION= 1,
/* Rename a .frm fire a table in the partition engine */
- DDL_LOG_RENAME_ACTION= 2,
+ DDL_LOG_FILE_RENAME_ACTION= 2,
/*
Rename an entity after removing the previous entry with the
new name, that is replace this entry.
*/
- DDL_LOG_REPLACE_ACTION= 3,
+ DDL_LOG_FILE_REPLACE_ACTION= 3,
/* Exchange two entities by renaming them a -> tmp, b -> a, tmp -> b */
DDL_LOG_EXCHANGE_ACTION= 4,
@@ -263,6 +263,12 @@ bool ddl_log_close_binlogged_events(HASH *xids);
int ddl_log_execute_recovery();
/* functions for updating the ddl log */
+bool ddl_log_write(DDL_LOG_STATE *ddl_state,
+ DDL_LOG_ENTRY *ddl_log_entry);
+/*
+ TODO: MDEV-28844 don't use in exchange_name_with_ddl_log(), remove global
+ declaration
+*/
bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry,
DDL_LOG_MEMORY_ENTRY **active_entry);
@@ -271,7 +277,8 @@ bool ddl_log_write_execute_entry(uint first_entry, uint cond_entry,
bool ddl_log_disable_execute_entry(DDL_LOG_MEMORY_ENTRY **active_entry);
void ddl_log_complete(DDL_LOG_STATE *ddl_log_state);
-bool ddl_log_revert(THD *thd, DDL_LOG_STATE *ddl_log_state);
+bool ddl_log_revert(THD *thd, DDL_LOG_STATE *ddl_log_state,
+ bool report_error);
bool ddl_log_update_phase(DDL_LOG_STATE *entry, uchar phase);
bool ddl_log_add_flag(DDL_LOG_STATE *entry, uint16 flag);
@@ -282,6 +289,10 @@ bool ddl_log_disable_entry(DDL_LOG_STATE *state);
bool ddl_log_increment_phase(uint entry_pos);
void ddl_log_release_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry);
bool ddl_log_sync();
+/*
+ TODO: MDEV-28844 don't use in exchange_name_with_ddl_log(), remove global
+ declaration
+*/
bool ddl_log_execute_entry(THD *thd, uint first_entry);
void ddl_log_add_entry(DDL_LOG_STATE *state, DDL_LOG_MEMORY_ENTRY *log_entry);
@@ -356,6 +367,8 @@ bool ddl_log_alter_table(DDL_LOG_STATE *ddl_state,
bool ddl_log_store_query(THD *thd, DDL_LOG_STATE *ddl_log_state,
const char *query, size_t length);
bool ddl_log_delete_frm(DDL_LOG_STATE *ddl_state, const char *to_path);
+bool ddl_log_rename_frm(DDL_LOG_STATE *ddl_state,
+ const char *from_path, const char *to_path);
void ddl_log_link_chains(DDL_LOG_STATE *state, DDL_LOG_STATE *master_state);
extern mysql_mutex_t LOCK_gdl;
#endif /* DDL_LOG_INCLUDED */
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 0b59a5a335f..fe94d44f482 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -877,332 +877,6 @@ create_error:
}
-/*
- Drop partitions as part of ALTER TABLE of partitions
-
- SYNOPSIS
- drop_partitions()
- path Complete path of db and table name
-
- RETURN VALUE
- >0 Failure
- 0 Success
-
- DESCRIPTION
- Use part_info object on handler object to deduce which partitions to
- drop (each partition has a state attached to it)
-*/
-
-int ha_partition::drop_partitions(const char *path)
-{
- List_iterator<partition_element> part_it(m_part_info->partitions);
- char part_name_buff[FN_REFLEN + 1];
- uint num_parts= m_part_info->partitions.elements;
- uint num_subparts= m_part_info->num_subparts;
- uint i= 0;
- uint name_variant;
- int ret_error;
- int error= 0;
- DBUG_ENTER("ha_partition::drop_partitions");
-
- /*
- Assert that it works without HA_FILE_BASED and lower_case_table_name = 2.
- We use m_file[0] as long as all partitions have the same storage engine.
- */
- DBUG_ASSERT(!strcmp(path, get_canonical_filename(m_file[0], path,
- part_name_buff)));
- do
- {
- partition_element *part_elem= part_it++;
- if (part_elem->part_state == PART_TO_BE_DROPPED)
- {
- handler *file;
- /*
- This part is to be dropped, meaning the part or all its subparts.
- */
- name_variant= NORMAL_PART_NAME;
- if (m_is_sub_partitioned)
- {
- List_iterator<partition_element> sub_it(part_elem->subpartitions);
- uint j= 0, part;
- do
- {
- partition_element *sub_elem= sub_it++;
- part= i * num_subparts + j;
- if (unlikely((ret_error=
- create_subpartition_name(part_name_buff,
- sizeof(part_name_buff), path,
- part_elem->partition_name,
- sub_elem->partition_name,
- name_variant))))
- error= ret_error;
- file= m_file[part];
- DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff));
- if (unlikely((ret_error= file->delete_table(part_name_buff))))
- error= ret_error;
- if (unlikely(ddl_log_increment_phase(sub_elem->log_entry->
- entry_pos)))
- error= 1;
- } while (++j < num_subparts);
- }
- else
- {
- if ((ret_error= create_partition_name(part_name_buff,
- sizeof(part_name_buff), path,
- part_elem->partition_name, name_variant, TRUE)))
- error= ret_error;
- else
- {
- file= m_file[i];
- DBUG_PRINT("info", ("Drop partition %s", part_name_buff));
- if (unlikely((ret_error= file->delete_table(part_name_buff))))
- error= ret_error;
- if (unlikely(ddl_log_increment_phase(part_elem->log_entry->
- entry_pos)))
- error= 1;
- }
- }
- if (part_elem->part_state == PART_IS_CHANGED)
- part_elem->part_state= PART_NORMAL;
- else
- part_elem->part_state= PART_IS_DROPPED;
- }
- } while (++i < num_parts);
- (void) ddl_log_sync();
- DBUG_RETURN(error);
-}
-
-
-/*
- Rename partitions as part of ALTER TABLE of partitions
-
- SYNOPSIS
- rename_partitions()
- path Complete path of db and table name
-
- RETURN VALUE
- TRUE Failure
- FALSE Success
-
- DESCRIPTION
- When reorganising partitions, adding hash partitions and coalescing
- partitions it can be necessary to rename partitions while holding
- an exclusive lock on the table.
- Which partitions to rename is given by state of partitions found by the
- partition info struct referenced from the handler object
-*/
-
-int ha_partition::rename_partitions(const char *path)
-{
- List_iterator<partition_element> part_it(m_part_info->partitions);
- List_iterator<partition_element> temp_it(m_part_info->temp_partitions);
- char part_name_buff[FN_REFLEN + 1];
- char norm_name_buff[FN_REFLEN + 1];
- uint num_parts= m_part_info->partitions.elements;
- uint part_count= 0;
- uint num_subparts= m_part_info->num_subparts;
- uint i= 0;
- uint j= 0;
- int error= 0;
- int ret_error;
- uint temp_partitions= m_part_info->temp_partitions.elements;
- handler *file;
- partition_element *part_elem, *sub_elem;
- DBUG_ENTER("ha_partition::rename_partitions");
-
- /*
- Assert that it works without HA_FILE_BASED and lower_case_table_name = 2.
- We use m_file[0] as long as all partitions have the same storage engine.
- */
- DBUG_ASSERT(!strcmp(path, get_canonical_filename(m_file[0], path,
- norm_name_buff)));
-
- DEBUG_SYNC(ha_thd(), "before_rename_partitions");
- if (temp_partitions)
- {
- /*
- These are the reorganised partitions that have already been copied.
- We delete the partitions and log the delete by inactivating the
- delete log entry in the table log. We only need to synchronise
- these writes before moving to the next loop since there is no
- interaction among reorganised partitions, they cannot have the
- same name.
- */
- do
- {
- part_elem= temp_it++;
- if (m_is_sub_partitioned)
- {
- List_iterator<partition_element> sub_it(part_elem->subpartitions);
- j= 0;
- do
- {
- sub_elem= sub_it++;
- file= m_reorged_file[part_count++];
- if (unlikely((ret_error=
- create_subpartition_name(norm_name_buff,
- sizeof(norm_name_buff), path,
- part_elem->partition_name,
- sub_elem->partition_name,
- NORMAL_PART_NAME))))
- error= ret_error;
- DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff));
- if (unlikely((ret_error= file->delete_table(norm_name_buff))))
- error= ret_error;
- else if (unlikely(ddl_log_increment_phase(sub_elem->log_entry->
- entry_pos)))
- error= 1;
- else
- sub_elem->log_entry= NULL; /* Indicate success */
- } while (++j < num_subparts);
- }
- else
- {
- file= m_reorged_file[part_count++];
- if (unlikely((ret_error=
- create_partition_name(norm_name_buff,
- sizeof(norm_name_buff), path,
- part_elem->partition_name,
- NORMAL_PART_NAME, TRUE))))
- error= ret_error;
- else
- {
- DBUG_PRINT("info", ("Delete partition %s", norm_name_buff));
- if (unlikely((ret_error= file->delete_table(norm_name_buff))))
- error= ret_error;
- else if (unlikely(ddl_log_increment_phase(part_elem->log_entry->
- entry_pos)))
- error= 1;
- else
- part_elem->log_entry= NULL; /* Indicate success */
- }
- }
- } while (++i < temp_partitions);
- (void) ddl_log_sync();
- }
- i= 0;
- do
- {
- /*
- When state is PART_IS_CHANGED it means that we have created a new
- TEMP partition that is to be renamed to normal partition name and
- we are to delete the old partition with currently the normal name.
-
- We perform this operation by
- 1) Delete old partition with normal partition name
- 2) Signal this in table log entry
- 3) Synch table log to ensure we have consistency in crashes
- 4) Rename temporary partition name to normal partition name
- 5) Signal this to table log entry
- It is not necessary to synch the last state since a new rename
- should not corrupt things if there was no temporary partition.
-
- The only other parts we need to cater for are new parts that
- replace reorganised parts. The reorganised parts were deleted
- by the code above that goes through the temp_partitions list.
- Thus the synch above makes it safe to simply perform step 4 and 5
- for those entries.
- */
- part_elem= part_it++;
- if (part_elem->part_state == PART_IS_CHANGED ||
- part_elem->part_state == PART_TO_BE_DROPPED ||
- (part_elem->part_state == PART_IS_ADDED && temp_partitions))
- {
- if (m_is_sub_partitioned)
- {
- List_iterator<partition_element> sub_it(part_elem->subpartitions);
- uint part;
-
- j= 0;
- do
- {
- sub_elem= sub_it++;
- part= i * num_subparts + j;
- if (unlikely((ret_error=
- create_subpartition_name(norm_name_buff,
- sizeof(norm_name_buff), path,
- part_elem->partition_name,
- sub_elem->partition_name,
- NORMAL_PART_NAME))))
- error= ret_error;
- if (part_elem->part_state == PART_IS_CHANGED)
- {
- file= m_reorged_file[part_count++];
- DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff));
- if (unlikely((ret_error= file->delete_table(norm_name_buff))))
- error= ret_error;
- else if (unlikely(ddl_log_increment_phase(sub_elem->log_entry->
- entry_pos)))
- error= 1;
- (void) ddl_log_sync();
- }
- file= m_new_file[part];
- if (unlikely((ret_error=
- create_subpartition_name(part_name_buff,
- sizeof(part_name_buff), path,
- part_elem->partition_name,
- sub_elem->partition_name,
- TEMP_PART_NAME))))
- error= ret_error;
- DBUG_PRINT("info", ("Rename subpartition from %s to %s",
- part_name_buff, norm_name_buff));
- if (unlikely((ret_error= file->ha_rename_table(part_name_buff,
- norm_name_buff))))
- error= ret_error;
- else if (unlikely(ddl_log_increment_phase(sub_elem->log_entry->
- entry_pos)))
- error= 1;
- else
- sub_elem->log_entry= NULL;
- } while (++j < num_subparts);
- }
- else
- {
- if (unlikely((ret_error=
- create_partition_name(norm_name_buff,
- sizeof(norm_name_buff), path,
- part_elem->partition_name,
- NORMAL_PART_NAME, TRUE)) ||
- (ret_error= create_partition_name(part_name_buff,
- sizeof(part_name_buff),
- path,
- part_elem->
- partition_name,
- TEMP_PART_NAME, TRUE))))
- error= ret_error;
- else
- {
- if (part_elem->part_state == PART_IS_CHANGED)
- {
- file= m_reorged_file[part_count++];
- DBUG_PRINT("info", ("Delete partition %s", norm_name_buff));
- if (unlikely((ret_error= file->delete_table(norm_name_buff))))
- error= ret_error;
- else if (unlikely(ddl_log_increment_phase(part_elem->log_entry->
- entry_pos)))
- error= 1;
- (void) ddl_log_sync();
- }
- file= m_new_file[i];
- DBUG_PRINT("info", ("Rename partition from %s to %s",
- part_name_buff, norm_name_buff));
- if (unlikely((ret_error= file->ha_rename_table(part_name_buff,
- norm_name_buff))))
- error= ret_error;
- else if (unlikely(ddl_log_increment_phase(part_elem->log_entry->
- entry_pos)))
- error= 1;
- else
- part_elem->log_entry= NULL;
- }
- }
- }
- } while (++i < num_parts);
- (void) ddl_log_sync();
- DBUG_RETURN(error);
-}
-
-
#define OPTIMIZE_PARTS 1
#define ANALYZE_PARTS 2
#define CHECK_PARTS 3
@@ -1990,10 +1664,8 @@ int ha_partition::allocate_partitions()
do
{
handler **new_file= &new_file_array[part_count++];
- if (!(*new_file=
- get_new_handler(table->s,
- thd->mem_root,
- part_elem->engine_type)))
+ if (!(*new_file= ::get_new_handler(table->s, thd->mem_root,
+ part_elem->engine_type)))
{
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
}
@@ -2013,188 +1685,8 @@ int ha_partition::allocate_partitions()
} while (++i < num_parts);
m_new_file= new_file_array;
- DBUG_RETURN(0);
-}
-
-
-/*
- Implement the partition changes defined by ALTER TABLE of partitions
-
- SYNOPSIS
- change_partitions()
- create_info HA_CREATE_INFO object describing all
- fields and indexes in table
- path Complete path of db and table name
- out: copied Output parameter where number of copied
- records are added
- out: deleted Output parameter where number of deleted
- records are added
- pack_frm_data Reference to packed frm file
- pack_frm_len Length of packed frm file
-
- RETURN VALUE
- >0 Failure
- 0 Success
-
- DESCRIPTION
- Add and copy if needed a number of partitions, during this operation
- no other operation is ongoing in the server. This is used by
- ADD PARTITION all types as well as by REORGANIZE PARTITION. For
- one-phased implementations it is used also by DROP and COALESCE
- PARTITIONs.
- One-phased implementation needs the new frm file, other handlers will
- get zero length and a NULL reference here.
-*/
-
-int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
- const char *path,
- ulonglong * const copied,
- ulonglong * const deleted,
- const uchar *pack_frm_data
- __attribute__((unused)),
- size_t pack_frm_len
- __attribute__((unused)))
-{
- List_iterator<partition_element> part_it(m_part_info->partitions);
- List_iterator <partition_element> t_it(m_part_info->temp_partitions);
- char part_name_buff[FN_REFLEN + 1];
- uint num_parts= m_part_info->partitions.elements;
- uint num_subparts= m_part_info->num_subparts;
- uint i= 0;
- int error;
- uint temp_partitions= m_part_info->temp_partitions.elements;
- DBUG_ENTER("ha_partition::change_partitions");
-
- /*
- Assert that it works without HA_FILE_BASED and lower_case_table_name = 2.
- We use m_file[0] as long as all partitions have the same storage engine.
- */
- DBUG_ASSERT(!strcmp(path, get_canonical_filename(m_file[0], path,
- part_name_buff)));
-
- if ((error= allocate_partitions()))
- DBUG_RETURN(error);
- DBUG_ASSERT(m_new_file);
-
- /*
- Step 5:
- Create the new partitions and also open, lock and call external_lock
- on them to prepare them for copy phase and also for later close
- calls
- */
-
- /*
- Before creating new partitions check whether indexes are disabled
- in the partitions.
- */
-
- uint disable_non_uniq_indexes= indexes_are_disabled();
-
- part_it.rewind();
- do
- {
- partition_element *part_elem= part_it++;
- DBUG_ASSERT(i == part_elem->id);
- if (part_elem->part_state == PART_TO_BE_ADDED ||
- part_elem->part_state == PART_CHANGED)
- {
- /*
- A new partition needs to be created PART_TO_BE_ADDED means an
- entirely new partition and PART_CHANGED means a changed partition
- that will still exist with either more or less data in it.
- */
- uint name_variant= NORMAL_PART_NAME;
- if (part_elem->part_state == PART_CHANGED ||
- (part_elem->part_state == PART_TO_BE_ADDED && temp_partitions))
- name_variant= TEMP_PART_NAME;
- if (m_part_info->is_sub_partitioned())
- {
- List_iterator<partition_element> sub_it(part_elem->subpartitions);
- uint j= 0;
- do
- {
- partition_element *sub_elem= sub_it++;
- DBUG_ASSERT(part_elem == sub_elem->parent_part);
- DBUG_ASSERT(j == sub_elem->id);
- if (unlikely((error=
- create_subpartition_name(part_name_buff,
- sizeof(part_name_buff), path,
- part_elem->partition_name,
- sub_elem->partition_name,
- name_variant))))
- {
- cleanup_new_partition();
- DBUG_RETURN(error);
- }
- DBUG_PRINT("info", ("Add subpartition %s", part_name_buff));
- if (unlikely((error=
- create_partition(table, create_info,
- (const char *)part_name_buff,
- sub_elem,
- disable_non_uniq_indexes))))
- {
- cleanup_new_partition();
- DBUG_RETURN(error);
- }
- } while (++j < num_subparts);
- }
- else
- {
- if (unlikely((error=
- create_partition_name(part_name_buff,
- sizeof(part_name_buff), path,
- part_elem->partition_name,
- name_variant, TRUE))))
- {
- cleanup_new_partition();
- DBUG_RETURN(error);
- }
-
- DBUG_PRINT("info", ("Add partition %s", part_name_buff));
- if (unlikely((error=
- create_partition(table, create_info,
- (const char *)part_name_buff,
- part_elem,
- disable_non_uniq_indexes))))
- {
- cleanup_new_partition();
- DBUG_RETURN(error);
- }
- }
- }
- } while (++i < num_parts);
-
- /*
- Step 6:
- State update to prepare for next write of the frm file.
- */
- i= 0;
- part_it.rewind();
- do
- {
- partition_element *part_elem= part_it++;
- if (part_elem->part_state == PART_TO_BE_ADDED)
- part_elem->part_state= PART_IS_ADDED;
- else if (part_elem->part_state == PART_CHANGED)
- part_elem->part_state= PART_IS_CHANGED;
- else if (part_elem->part_state == PART_REORGED_DROPPED)
- part_elem->part_state= PART_TO_BE_DROPPED;
- } while (++i < num_parts);
- for (i= 0; i < temp_partitions; i++)
- {
- partition_element *part_elem= t_it++;
- DBUG_ASSERT(part_elem->part_state == PART_TO_BE_REORGED);
- part_elem->part_state= PART_TO_BE_DROPPED;
- }
- if (unlikely((error= copy_partitions(copied, deleted))))
- {
- /*
- Close and unlock the new temporary partitions.
- They will later be deleted through the ddl-log.
- */
- cleanup_new_partition();
- }
- DBUG_RETURN(error);
+ DBUG_RETURN(ERROR_INJECT("alter_partition_alloc_parts") ?
+ HA_ERR_OUT_OF_MEM : 0);
}
@@ -3057,7 +2549,7 @@ bool ha_partition::create_handlers(MEM_ROOT *mem_root)
for (i= 0; i < m_tot_parts; i++)
{
handlerton *hton= plugin_data(m_engine_array[i], handlerton*);
- if (!(m_file[i]= get_new_handler(table_share, mem_root, hton)))
+ if (!(m_file[i]= ::get_new_handler(table_share, mem_root, hton)))
DBUG_RETURN(TRUE);
DBUG_PRINT("info", ("engine_type: %u", hton->db_type));
}
@@ -3118,8 +2610,8 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root)
{
for (j= 0; j < m_part_info->num_subparts; j++)
{
- if (!(m_file[part_count++]= get_new_handler(table_share, mem_root,
- part_elem->engine_type)))
+ if (!(m_file[part_count++]= ::get_new_handler(table_share, mem_root,
+ part_elem->engine_type)))
goto error;
DBUG_PRINT("info", ("engine_type: %u",
(uint) ha_legacy_type(part_elem->engine_type)));
@@ -3127,8 +2619,8 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root)
}
else
{
- if (!(m_file[part_count++]= get_new_handler(table_share, mem_root,
- part_elem->engine_type)))
+ if (!(m_file[part_count++]= ::get_new_handler(table_share, mem_root,
+ part_elem->engine_type)))
goto error;
DBUG_PRINT("info", ("engine_type: %u",
(uint) ha_legacy_type(part_elem->engine_type)));
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 778080132b8..a4e33058c10 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -467,6 +467,20 @@ public:
{
return m_file;
}
+ handler **get_new_handlers()
+ {
+ return m_new_file;
+ }
+ handler *get_child_handler(partition_element *part_elem,
+ partition_element *sub_elem)
+ {
+ return m_file[part_elem->serial_id(sub_elem, m_part_info->num_subparts)];
+ }
+ handler *get_new_handler(partition_element *part_elem,
+ partition_element *sub_elem)
+ {
+ return m_new_file[part_elem->serial_id(sub_elem, m_part_info->num_subparts)];
+ }
ha_partition *get_clone_source()
{
return m_is_clone_of;
@@ -554,13 +568,7 @@ public:
override;
bool check_if_updates_are_ignored(const char *op) const override;
void update_create_info(HA_CREATE_INFO *create_info) override;
- int change_partitions(HA_CREATE_INFO *create_info, const char *path,
- ulonglong * const copied, ulonglong * const deleted,
- const uchar *pack_frm_data, size_t pack_frm_len)
- override;
int allocate_partitions();
- int drop_partitions(const char *path) override;
- int rename_partitions(const char *path) override;
bool get_no_parts(const char *, uint *num_parts) override
{
DBUG_ENTER("ha_partition::get_no_parts");
diff --git a/sql/handler.cc b/sql/handler.cc
index 42c5584f6e1..aa35d0c7b55 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -5475,68 +5475,6 @@ handler::ha_create_partitioning_metadata(const char *name,
/**
- Change partitions: public interface.
-
- @sa handler::change_partitions()
-*/
-
-int
-handler::ha_change_partitions(HA_CREATE_INFO *create_info,
- const char *path,
- ulonglong * const copied,
- ulonglong * const deleted,
- const uchar *pack_frm_data,
- size_t pack_frm_len)
-{
- /*
- Must have at least RDLCK or be a TMP table. Read lock is needed to read
- from current partitions and write lock will be taken on new partitions.
- */
- DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE ||
- m_lock_type != F_UNLCK);
-
- mark_trx_read_write();
-
- return change_partitions(create_info, path, copied, deleted,
- pack_frm_data, pack_frm_len);
-}
-
-
-/**
- Drop partitions: public interface.
-
- @sa handler::drop_partitions()
-*/
-
-int
-handler::ha_drop_partitions(const char *path)
-{
- DBUG_ASSERT(!table->db_stat);
-
- mark_trx_read_write();
-
- return drop_partitions(path);
-}
-
-
-/**
- Rename partitions: public interface.
-
- @sa handler::rename_partitions()
-*/
-
-int
-handler::ha_rename_partitions(const char *path)
-{
- DBUG_ASSERT(!table->db_stat);
-
- mark_trx_read_write();
-
- return rename_partitions(path);
-}
-
-
-/**
Tell the storage engine that it is allowed to "disable transaction" in the
handler. It is a hint that ACID is not required - it was used in NDB for
ALTER TABLE, for example, when data are copied to temporary table.
diff --git a/sql/handler.h b/sql/handler.h
index 3f0b97034e1..5258dc10e80 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -448,7 +448,6 @@ enum chf_create_flags {
*/
#define HA_PARTITION_FUNCTION_SUPPORTED (1UL << 12)
#define HA_FAST_CHANGE_PARTITION (1UL << 13)
-#define HA_PARTITION_ONE_PHASE (1UL << 14)
/* operations for disable/enable indexes */
#define HA_KEY_SWITCH_NONUNIQ 0
@@ -3559,15 +3558,6 @@ public:
int ha_create_partitioning_metadata(const char *name, const char *old_name,
chf_create_flags action_flag);
- int ha_change_partitions(HA_CREATE_INFO *create_info,
- const char *path,
- ulonglong * const copied,
- ulonglong * const deleted,
- const uchar *pack_frm_data,
- size_t pack_frm_len);
- int ha_drop_partitions(const char *path);
- int ha_rename_partitions(const char *path);
-
void adjust_next_insert_id_after_explicit_value(ulonglong nr);
int update_auto_increment();
virtual void print_error(int error, myf errflag);
@@ -5072,22 +5062,11 @@ public:
chf_create_flags action_flag)
{ return FALSE; }
- virtual int change_partitions(HA_CREATE_INFO *create_info,
- const char *path,
- ulonglong * const copied,
- ulonglong * const deleted,
- const uchar *pack_frm_data,
- size_t pack_frm_len)
- { return HA_ERR_WRONG_COMMAND; }
/* @return true if it's necessary to switch current statement log format from
STATEMENT to ROW if binary log format is MIXED and autoincrement values
are changed in the statement */
virtual bool autoinc_lock_mode_stmt_unsafe() const
{ return false; }
- virtual int drop_partitions(const char *path)
- { return HA_ERR_WRONG_COMMAND; }
- virtual int rename_partitions(const char *path)
- { return HA_ERR_WRONG_COMMAND; }
virtual bool set_ha_share_ref(Handler_share **arg_ha_share)
{
DBUG_ASSERT(!ha_share);
diff --git a/sql/lex_string.h b/sql/lex_string.h
index e7a732346c4..c2c9701a70c 100644
--- a/sql/lex_string.h
+++ b/sql/lex_string.h
@@ -108,4 +108,8 @@ static inline bool lex_string_eq(const LEX_CSTRING *a, const char *b, size_t b_l
return strcasecmp(a->str, b) == 0;
}
+inline LEX_CSTRING strdup_root(MEM_ROOT *root, const LEX_CSTRING str)
+{
+ return safe_lexcstrdup_root(root, str);
+}
#endif /* LEX_STRING_INCLUDED */
diff --git a/sql/partition_element.h b/sql/partition_element.h
index 2427f42534c..8e0c32b7405 100644
--- a/sql/partition_element.h
+++ b/sql/partition_element.h
@@ -32,15 +32,13 @@ enum partition_type {
enum partition_state {
PART_NORMAL= 0,
- PART_IS_DROPPED= 1,
- PART_TO_BE_DROPPED= 2,
- PART_TO_BE_ADDED= 3,
- PART_TO_BE_REORGED= 4,
- PART_REORGED_DROPPED= 5,
- PART_CHANGED= 6,
- PART_IS_CHANGED= 7,
- PART_IS_ADDED= 8,
- PART_ADMIN= 9
+ PART_IS_DROPPED= 2,
+ PART_TO_BE_DROPPED= 4,
+ PART_TO_BE_ADDED= 8,
+ PART_TO_BE_REORGED= 16,
+ PART_REORGED_DROPPED= 32,
+ PART_CHANGED= 64,
+ PART_ADMIN= 128
};
/*
@@ -111,7 +109,6 @@ public:
ha_rows part_min_rows;
longlong range_value;
const char *partition_name;
- struct st_ddl_log_memory_entry *log_entry;
const char* part_comment;
const char* data_file_name;
const char* index_file_name;
@@ -130,7 +127,7 @@ public:
partition_element()
: part_max_rows(0), part_min_rows(0), range_value(0),
partition_name(NULL),
- log_entry(NULL), part_comment(NULL),
+ part_comment(NULL),
data_file_name(NULL), index_file_name(NULL),
engine_type(NULL), connect_string(null_clex_str), part_state(PART_NORMAL),
nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE),
@@ -143,7 +140,6 @@ public:
: part_max_rows(part_elem->part_max_rows),
part_min_rows(part_elem->part_min_rows),
range_value(0), partition_name(NULL),
- log_entry(NULL),
part_comment(part_elem->part_comment),
data_file_name(part_elem->data_file_name),
index_file_name(part_elem->index_file_name),
@@ -174,6 +170,11 @@ public:
DBUG_ASSERT(!num_subparts || parent_part);
return num_subparts ? parent_part->id * num_subparts + id : id;
}
+
+ uint32 serial_id(partition_element *sub_elem, uint num_subparts) const
+ {
+ return sub_elem ? sub_elem->serial_id(num_subparts) : serial_id(num_subparts);
+ }
};
#endif /* PARTITION_ELEMENT_INCLUDED */
diff --git a/sql/partition_info.h b/sql/partition_info.h
index 46e17044b85..635f1df2736 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -32,8 +32,6 @@ typedef int (*get_part_id_func)(partition_info *part_info, uint32 *part_id,
typedef int (*get_subpart_id_func)(partition_info *part_info, uint32 *part_id);
typedef bool (*check_constants_func)(THD *thd, partition_info *part_info);
-struct st_ddl_log_memory_entry;
-
#define MAX_PART_NAME_SIZE 8
@@ -79,7 +77,7 @@ struct Vers_part_info : public Sql_alloc
partition_element *hist_part;
};
-class partition_info : public DDL_LOG_STATE, public Sql_alloc
+class partition_info : public Sql_alloc
{
public:
/*
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index a71b0fd0bb3..a330f4a9849 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -4938,7 +4938,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
without any changes at all.
*/
flags= table->file->alter_table_flags(alter_info->flags);
- if (flags & (HA_FAST_CHANGE_PARTITION | HA_PARTITION_ONE_PHASE))
+ if (flags & HA_FAST_CHANGE_PARTITION)
{
*fast_alter_table= true;
/* Force table re-open for consistency with the main case. */
@@ -4981,7 +4981,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
my_error(ER_PARTITION_FUNCTION_FAILURE, MYF(0));
goto err;
}
- if ((flags & (HA_FAST_CHANGE_PARTITION | HA_PARTITION_ONE_PHASE)) != 0)
+ if (flags & HA_FAST_CHANGE_PARTITION)
{
/*
"Fast" change of partitioning is supported in this case.
@@ -6018,534 +6018,554 @@ err:
}
-/*
- Change partitions, used to implement ALTER TABLE ADD/REORGANIZE/COALESCE
- partitions. This method is used to implement both single-phase and multi-
- phase implementations of ADD/REORGANIZE/COALESCE partitions.
-
- SYNOPSIS
- mysql_change_partitions()
- lpt Struct containing parameters
-
- RETURN VALUES
- TRUE Failure
- FALSE Success
+/**
+ DDL logger and partiton renamer
- DESCRIPTION
- Request handler to add partitions as set in states of the partition
-
- Elements of the lpt parameters used:
- create_info Create information used to create partitions
- db Database name
- table_name Table name
- copied Output parameter where number of copied
- records are added
- deleted Output parameter where number of deleted
- records are added
+ Processes DROP PARTITION action and serves to other ALTER commands as an
+ utility basis.
*/
-static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
+class Alter_partition_logger
{
- char path[FN_REFLEN+1];
- int error;
- handler *file= lpt->table->file;
- THD *thd= lpt->thd;
- DBUG_ENTER("mysql_change_partitions");
+ char path_buf[FN_REFLEN + 1];
- build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
+protected:
+ const char *path;
+ uint from_name_type; /* NORMAL_PART_NAME, TEMP_PART_NAME, RENAMED_PART_NAME */
+ uint to_name_type; /* same + SKIP_PART_NAME */
- if(mysql_trans_prepare_alter_copy_data(thd))
- DBUG_RETURN(TRUE);
+ DDL_LOG_ENTRY ddl_log_entry;
- /* TODO: test if bulk_insert would increase the performance */
+ char from_name[FN_REFLEN + 1];
+ char to_name[FN_REFLEN + 1];
+ ALTER_PARTITION_PARAM_TYPE *lpt;
+ TABLE *table;
+ partition_info *part_info;
+ DDL_LOG_STATE *rollback_chain;
+ DDL_LOG_STATE *cleanup_chain;
+ ha_partition *hp;
+
+public:
+ enum Phase
+ {
+ RENAME_TO_BACKUPS= 0,
+ LOG_DROP_BACKUPS= 2,
+ ADD_PARTITIONS= 4,
+ RENAME_ADDED_PARTS= 8,
+ CONVERT_OUT= 16,
+ CONVERT_IN= 32,
+ NO_PHASE= 255
+ } phase;
+
+ Alter_partition_logger(ALTER_PARTITION_PARAM_TYPE *lpt) :
+ path(NULL), from_name_type(SKIP_PART_NAME),
+ to_name_type(SKIP_PART_NAME),
+ lpt(lpt), table(lpt->table), part_info(lpt->part_info),
+ rollback_chain(&lpt->rollback_chain),
+ cleanup_chain(&lpt->cleanup_chain),
+ hp((ha_partition *) table->file)
+ {
+ DBUG_ASSERT(table->file->ht->db_type == DB_TYPE_PARTITION_DB);
+ build_table_filename(path_buf, sizeof(path_buf) - 1, lpt->db.str,
+ lpt->table_name.str, "", 0);
+ path= path_buf;
+ }
+
+ virtual ~Alter_partition_logger() {}
+ bool iterate(Phase phase, uint from_name_arg, uint to_name_arg,
+ List<partition_element> *parts);
+
+ /**
+ Make from_name, to_name according to from_name_type, to_name_type.
+ Set common ddl_log_entry parameters like flags, handler_name.
+ */
- if (unlikely((error= file->ha_change_partitions(lpt->create_info, path,
- &lpt->copied,
- &lpt->deleted,
- lpt->pack_frm_data,
- lpt->pack_frm_len))))
- {
- file->print_error(error, MYF(error != ER_OUTOFMEMORY ? 0 : ME_FATAL));
+ bool build_names(partition_element *part_elem, partition_element *sub_elem)
+ {
+ bzero(&ddl_log_entry, sizeof(ddl_log_entry));
+ ddl_log_entry.flags= DDL_LOG_FLAG_ALTER_PARTITION;
+
+ DBUG_ASSERT(lpt->thd->mdl_context.is_lock_owner(MDL_key::TABLE,
+ table->s->db.str,
+ table->s->table_name.str,
+ MDL_EXCLUSIVE));
+
+ handlerton *ht= part_elem->engine_type ?
+ part_elem->engine_type : part_info->default_engine_type;
+ DBUG_ASSERT(ht);
+ lex_string_set(&ddl_log_entry.handler_name,
+ ha_resolve_storage_engine_name(ht));
+ if (!sub_elem)
+ {
+ if (from_name_type != SKIP_PART_NAME &&
+ create_partition_name(from_name, sizeof(from_name), path,
+ part_elem->partition_name, from_name_type,
+ true /* translate */))
+ return true;
+ if (to_name_type != SKIP_PART_NAME &&
+ create_partition_name(to_name, sizeof(to_name), path,
+ part_elem->partition_name, to_name_type,
+ true /* translate */))
+ return true;
+ }
+ else
+ {
+ if (from_name_type != SKIP_PART_NAME &&
+ create_subpartition_name(from_name, sizeof(from_name), path,
+ part_elem->partition_name,
+ sub_elem->partition_name, from_name_type))
+ return true;
+ if (to_name_type != SKIP_PART_NAME &&
+ create_subpartition_name(to_name, sizeof(to_name), path,
+ part_elem->partition_name,
+ sub_elem->partition_name, to_name_type))
+ return true;
+ }
+
+ return false;
}
- if (mysql_trans_commit_alter_copy_data(thd))
- error= 1; /* The error has been reported */
+ /**
+ check_state() selects partitions to be processed by process_partition()
+ */
- DBUG_RETURN(MY_TEST(error));
-}
+ virtual
+ bool check_state(partition_element *part_elem)
+ {
+ return part_elem->part_state == PART_TO_BE_DROPPED;
+ }
+ /**
+ DROP PARTITION processing
-/*
- Rename partitions in an ALTER TABLE of partitions
+ Iterate phases: rename partitions marked for drop to backup partitions and
+ write rollback_chain so it reverts these operations. Write cleanup_chain so
+ it drops backup partitions, but only when rollback_chain is inactive.
+ */
- SYNOPSIS
- mysql_rename_partitions()
- lpt Struct containing parameters
+ bool rename_parts()
+ {
+ if (iterate(RENAME_TO_BACKUPS, NORMAL_PART_NAME, RENAMED_PART_NAME,
+ &part_info->partitions))
+ return true;
+ if (iterate(LOG_DROP_BACKUPS, RENAMED_PART_NAME, SKIP_PART_NAME,
+ &part_info->partitions))
+ return true;
+ return false;
+ }
- RETURN VALUES
- TRUE Failure
- FALSE Success
+ bool debug_crash_or_fail()
+ {
+#ifndef DBUG_OFF
+ switch (phase)
+ {
+ case RENAME_TO_BACKUPS:
+ if (ERROR_INJECT("alter_partition_rename_to_backup"))
+ return true;
+ break;
+ case RENAME_ADDED_PARTS:
+ if (ERROR_INJECT("alter_partition_rename_added_part"))
+ return true;
+ break;
+ case LOG_DROP_BACKUPS:
+ if (ERROR_INJECT("alter_partition_rename_drop_backup"))
+ return true;
+ break;
+ default:
+ break;
+ }
+#endif
+ return false;
+ }
- DESCRIPTION
- Request handler to rename partitions as set in states of the partition
+ void debug_assert_states(partition_element *part_elem)
+ {
+#ifndef DBUG_OFF
+ switch (phase)
+ {
+ case RENAME_TO_BACKUPS:
+ DBUG_ASSERT(from_name_type == NORMAL_PART_NAME);
+ DBUG_ASSERT(to_name_type == RENAMED_PART_NAME);
+ DBUG_ASSERT(part_elem->part_state & (
+ PART_TO_BE_DROPPED |
+ PART_TO_BE_REORGED |
+ PART_REORGED_DROPPED |
+ PART_CHANGED));
+ break;
+ case RENAME_ADDED_PARTS:
+ DBUG_ASSERT(from_name_type == TEMP_PART_NAME);
+ DBUG_ASSERT(to_name_type == NORMAL_PART_NAME);
+ break;
+ case CONVERT_OUT:
+ DBUG_ASSERT(from_name_type == NORMAL_PART_NAME);
+ DBUG_ASSERT(to_name_type == SKIP_PART_NAME);
+ DBUG_ASSERT(to_name[0]); /* to_name is external table name */
+ DBUG_ASSERT(part_elem->part_state & PART_TO_BE_DROPPED);
+ break;
+ case CONVERT_IN:
+ DBUG_ASSERT(from_name_type == SKIP_PART_NAME);
+ DBUG_ASSERT(to_name_type == NORMAL_PART_NAME);
+ DBUG_ASSERT(to_name[0]); /* to_name is external table name */
+ DBUG_ASSERT(part_elem->part_state & PART_TO_BE_ADDED);
+ break;
+ case ADD_PARTITIONS:
+ DBUG_ASSERT(to_name_type == SKIP_PART_NAME);
+ break;
+ case LOG_DROP_BACKUPS:
+ DBUG_ASSERT(from_name_type == RENAMED_PART_NAME);
+ DBUG_ASSERT(to_name_type == SKIP_PART_NAME);
+ DBUG_ASSERT(part_elem->part_state & (
+ PART_TO_BE_DROPPED |
+ PART_TO_BE_REORGED |
+ PART_REORGED_DROPPED |
+ PART_CHANGED));
+ break;
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+#endif
+ }
- Parameters used:
- db Database name
- table_name Table name
-*/
+ /**
+ The body of iteration: each partition selected by check_state() is
+ processed here.
-static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
-{
- char path[FN_REFLEN+1];
- int error;
- DBUG_ENTER("mysql_rename_partitions");
+ Do DDL logging and convey the rename. It doesn't do drop because that is
+ done by replaying cleanup_chain. Add is done by Alter_partition_add.
+ */
- build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
- if (unlikely((error= lpt->table->file->ha_rename_partitions(path))))
+ virtual
+ bool process_partition(partition_element *part_elem,
+ partition_element *sub_elem)
{
- if (error != 1)
- lpt->table->file->print_error(error, MYF(0));
- DBUG_RETURN(TRUE);
- }
- DBUG_RETURN(FALSE);
-}
+ debug_assert_states(part_elem);
+ DDL_LOG_STATE *output_chain= rollback_chain;
+ switch (phase)
+ {
+ case RENAME_TO_BACKUPS:
+ case RENAME_ADDED_PARTS:
+ case CONVERT_OUT:
+ case CONVERT_IN:
+ ddl_log_entry.action_type= DDL_LOG_RENAME_TABLE_ACTION;
+ ddl_log_entry.phase= DDL_RENAME_PHASE_TABLE;
+ ddl_log_entry.name= { from_name, strlen(from_name) };
+ ddl_log_entry.from_name= { to_name, strlen(to_name) };
+ break;
+ case ADD_PARTITIONS:
+ ddl_log_entry.action_type= DDL_LOG_DROP_TABLE_ACTION;
+ ddl_log_entry.tmp_name= { from_name, strlen(from_name) };
+ break;
+ case LOG_DROP_BACKUPS:
+ ddl_log_entry.action_type= DDL_LOG_DROP_TABLE_ACTION;
+ ddl_log_entry.tmp_name= { from_name, strlen(from_name) };
+ output_chain= cleanup_chain;
+ /* cleanup_chain cannot be executed before rollback_chain */
+ ddl_log_link_chains(cleanup_chain, rollback_chain);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ return true;
+ }
-/*
- Drop partitions in an ALTER TABLE of partitions
+ ddl_log_entry.next_entry= output_chain->list ?
+ output_chain->list->entry_pos : 0;
+ if (ddl_log_write(output_chain, &ddl_log_entry))
+ {
+ my_error(ER_DDL_LOG_ERROR, MYF(0));
+ return true;
+ }
- SYNOPSIS
- mysql_drop_partitions()
- lpt Struct containing parameters
+ if (ddl_log_entry.action_type == DDL_LOG_RENAME_TABLE_ACTION)
+ {
+ int ha_err;
+ DBUG_ASSERT(table->file->ht->db_type == DB_TYPE_PARTITION_DB);
+ handler *file= (phase & (RENAME_ADDED_PARTS|CONVERT_IN) ?
+ hp->get_new_handler(part_elem, sub_elem) :
+ hp->get_child_handler(part_elem, sub_elem));
+ ha_err= file->ha_rename_table(from_name, to_name);
+ if (ha_err ||
+ ERROR_INJECT("alter_partition_rename_table"))
+ {
+ file->print_error(ha_err, MYF(0));
+ return true;
+ }
+ }
+
+ return debug_crash_or_fail();
+ }
+};
- RETURN VALUES
- TRUE Failure
- FALSE Success
- DESCRIPTION
- Drop the partitions marked with PART_TO_BE_DROPPED state and remove
- those partitions from the list.
- Parameters used:
- table Table object
- db Database name
- table_name Table name
+/**
+ ADD PARTITION action
*/
-static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
+class Alter_partition_add : public Alter_partition_logger
{
- char path[FN_REFLEN+1];
- partition_info *part_info= lpt->table->part_info;
- List_iterator<partition_element> part_it(part_info->partitions);
- int error;
- DBUG_ENTER("mysql_drop_partitions");
+protected:
+ uint disable_non_uniq_indexes;
+ int ha_err;
- DBUG_ASSERT(lpt->thd->mdl_context.is_lock_owner(MDL_key::TABLE,
- lpt->table->s->db.str,
- lpt->table->s->table_name.str,
- MDL_EXCLUSIVE));
+public:
+ Alter_partition_add(ALTER_PARTITION_PARAM_TYPE *lpt) :
+ Alter_partition_logger(lpt)
+ {
+ disable_non_uniq_indexes= hp->indexes_are_disabled();
+ }
- build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
- if ((error= lpt->table->file->ha_drop_partitions(path)))
+ bool check_state(partition_element *part_elem)
{
- lpt->table->file->print_error(error, MYF(0));
- DBUG_RETURN(TRUE);
+ return part_elem->part_state == PART_TO_BE_ADDED;
}
- DBUG_RETURN(FALSE);
-}
+ /**
+ ADD PARTITION processing
+ */
-/*
- Convert partition to a table in an ALTER TABLE of partitions
+ bool add_parts()
+ {
+ ha_err= hp->allocate_partitions();
+ if (ha_err)
+ {
+ hp->print_error(ha_err, MYF(0));
+ return true;
+ }
+ if (iterate(ADD_PARTITIONS, NORMAL_PART_NAME, SKIP_PART_NAME,
+ &part_info->partitions))
+ return true;
+ return false;
+ }
- SYNOPSIS
- alter_partition_convert_out()
- lpt Struct containing parameters
+ bool process_partition(partition_element *part_elem,
+ partition_element *sub_elem)
+ {
+ DBUG_ASSERT(phase == ADD_PARTITIONS);
+ DBUG_ASSERT(!ha_err);
- RETURN VALUES
- TRUE Failure
- FALSE Success
+ if (Alter_partition_logger::process_partition(part_elem, sub_elem))
+ return true;
- DESCRIPTION
- Rename partition table marked with PART_TO_BE_DROPPED into a separate table
- under the name lpt->alter_ctx->(new_db, new_name).
+ ha_err= hp->create_partition(table, lpt->create_info, from_name,
+ sub_elem ? sub_elem : part_elem,
+ disable_non_uniq_indexes);
+ if (ha_err ||
+ ERROR_INJECT("alter_partition_add"))
+ {
+ hp->print_error(ha_err, MYF(0));
+ hp->cleanup_new_partition();
+ return true;
+ }
- This is ddl-logged by write_log_convert_out_partition().
+ return false;
+ }
+};
+
+
+/**
+ Change partition action
+
+ ADD HASH / COALESCE / REBUILD / REORGANIZE / CONVERT IN / CONVERT OUT
*/
-static bool alter_partition_convert_out(ALTER_PARTITION_PARAM_TYPE *lpt)
+class Alter_partition_change : public Alter_partition_add
{
- partition_info *part_info= lpt->table->part_info;
- THD *thd= lpt->thd;
- int error;
- handler *file= get_new_handler(NULL, thd->mem_root, part_info->default_engine_type);
+ uint processed_state;
- DBUG_ASSERT(lpt->thd->mdl_context.is_lock_owner(MDL_key::TABLE,
- lpt->table->s->db.str,
- lpt->table->s->table_name.str,
- MDL_EXCLUSIVE));
+public:
+ using Alter_partition_add::Alter_partition_add;
- char from_name[FN_REFLEN + 1], to_name[FN_REFLEN + 1];
- const char *path= lpt->table->s->path.str;
+ bool check_state(partition_element *part_elem)
+ {
+ return part_elem->part_state & processed_state;
+ }
- build_table_filename(to_name, sizeof(to_name) - 1, lpt->alter_ctx->new_db.str,
- lpt->alter_ctx->new_name.str, "", 0);
+ /**
+ REORGANIZE processing part 1
+ */
- for (const partition_element &e: part_info->partitions)
+ bool add_parts_and_copy_data(THD *thd)
{
- if (e.part_state != PART_TO_BE_DROPPED)
- continue;
-
- if (unlikely((error= create_partition_name(from_name, sizeof(from_name),
- path, e.partition_name,
- NORMAL_PART_NAME, FALSE))))
+ ha_err= hp->allocate_partitions();
+ if (ha_err)
{
- DBUG_ASSERT(thd->is_error());
+ hp->print_error(ha_err, MYF(0));
return true;
}
- if (DBUG_IF("error_convert_partition_00") ||
- unlikely(error= file->ha_rename_table(from_name, to_name)))
+
+ /*
+ ha_enable_transaction() must be done before ha_create():
+ Aria stores born_transactional and uses it for copy data.
+ */
+ if ((ha_err= mysql_trans_prepare_alter_copy_data(thd)))
{
- my_error(ER_ERROR_ON_RENAME, MYF(0), from_name, to_name, my_errno);
- lpt->table->file->print_error(error, MYF(0));
+ hp->print_error(ha_err, MYF(0));
return true;
}
- break;
- }
- return false;
-}
+ processed_state= (PART_TO_BE_ADDED|PART_CHANGED);
+ if (iterate(ADD_PARTITIONS, TEMP_PART_NAME, SKIP_PART_NAME,
+ &part_info->partitions))
+ {
+ (void) mysql_trans_commit_alter_copy_data(thd, true);
+ return true;
+ }
+ if (ERROR_INJECT("change_partition_add_parts_1") ||
+ (ha_err= hp->copy_partitions(&lpt->copied, &lpt->deleted)) ||
+ ERROR_INJECT("change_partition_add_parts_2") ||
+ (ha_err= mysql_trans_commit_alter_copy_data(thd, false)) ||
+ ERROR_INJECT("change_partition_add_parts_3"))
+ {
+ (void) mysql_trans_commit_alter_copy_data(thd, true);
+ hp->print_error(ha_err, MYF(0));
+ return true;
+ }
-/*
- Release all log entries for this partition info struct
- SYNOPSIS
- release_part_info_log_entries()
- first_log_entry First log entry in list to release
- RETURN VALUES
- NONE
-*/
+ return false;
+ }
-static void release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY *log_entry)
-{
- DBUG_ENTER("release_part_info_log_entries");
+ /**
+ REORGANIZE processing part 2
+ */
- while (log_entry)
+ bool rename_parts()
{
- DDL_LOG_MEMORY_ENTRY *next= log_entry->next_active_log_entry;
- ddl_log_release_memory_entry(log_entry);
- log_entry= next;
+ DEBUG_SYNC(lpt->thd, "before_rename_partitions");
+ if (part_info->temp_partitions.elements)
+ {
+ processed_state= PART_TO_BE_REORGED;
+ if (iterate(RENAME_TO_BACKUPS, NORMAL_PART_NAME, RENAMED_PART_NAME,
+ &part_info->temp_partitions))
+ return true;
+ }
+ processed_state= PART_CHANGED|PART_REORGED_DROPPED;
+ if (iterate(RENAME_TO_BACKUPS, NORMAL_PART_NAME, RENAMED_PART_NAME,
+ &part_info->partitions) ||
+ ERROR_INJECT("change_partition_rename_parts_1"))
+ return true;
+ processed_state= PART_TO_BE_ADDED|PART_CHANGED;
+ if (iterate(RENAME_ADDED_PARTS, TEMP_PART_NAME, NORMAL_PART_NAME,
+ &part_info->partitions) ||
+ ERROR_INJECT("change_partition_rename_parts_2"))
+ return true;
+ if (part_info->temp_partitions.elements)
+ {
+ processed_state= PART_TO_BE_REORGED;
+ if (iterate(LOG_DROP_BACKUPS, RENAMED_PART_NAME, SKIP_PART_NAME,
+ &part_info->temp_partitions))
+ return true;
+ }
+ processed_state= PART_CHANGED|PART_REORGED_DROPPED;
+ if (iterate(LOG_DROP_BACKUPS, RENAMED_PART_NAME, SKIP_PART_NAME,
+ &part_info->partitions))
+ return true;
+ return false;
}
- DBUG_VOID_RETURN;
-}
+ /**
+ CONVERT OUT processing
+ */
-/*
- Log an rename frm file
- SYNOPSIS
- write_log_replace_frm()
- lpt Struct for parameters
- next_entry Next reference to use in log record
- from_path Name to rename from
- to_path Name to rename to
- RETURN VALUES
- TRUE Error
- FALSE Success
- DESCRIPTION
- Support routine that writes a replace of an frm file into the
- ddl log. It also inserts an entry that keeps track of used space into
- the partition info object
-*/
+ bool convert_out()
+ {
+ build_table_filename(to_name, sizeof(to_name) - 1,
+ lpt->alter_ctx->new_db.str,
+ lpt->alter_ctx->new_name.str, "", 0);
-bool write_log_replace_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
- uint next_entry,
- const char *from_path,
- const char *to_path)
-{
- DDL_LOG_ENTRY ddl_log_entry;
- DDL_LOG_MEMORY_ENTRY *log_entry;
- DBUG_ENTER("write_log_replace_frm");
+ processed_state= PART_TO_BE_DROPPED;
+ if (iterate(CONVERT_OUT, NORMAL_PART_NAME, SKIP_PART_NAME,
+ &part_info->partitions))
+ return true;
+ return false;
+ }
- bzero(&ddl_log_entry, sizeof(ddl_log_entry));
- ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION;
- ddl_log_entry.next_entry= next_entry;
- lex_string_set(&ddl_log_entry.handler_name, reg_ext);
- lex_string_set(&ddl_log_entry.name, to_path);
- lex_string_set(&ddl_log_entry.from_name, from_path);
+ /**
+ CONVERT IN processing
+ */
- if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
+ bool convert_in()
{
- DBUG_RETURN(true);
- }
- ddl_log_add_entry(lpt->part_info, log_entry);
- DBUG_RETURN(false);
-}
+ TABLE_LIST* table_from= lpt->table_list->next_local;
+ ha_err= hp->allocate_partitions();
+ if (ha_err)
+ {
+ hp->print_error(ha_err, MYF(0));
+ return true;
+ }
-/*
- Log final partition changes in change partition
- SYNOPSIS
- write_log_changed_partitions()
- lpt Struct containing parameters
- RETURN VALUES
- TRUE Error
- FALSE Success
- DESCRIPTION
- This code is used to perform safe ADD PARTITION for HASH partitions
- and COALESCE for HASH partitions and REORGANIZE for any type of
- partitions.
- We prepare entries for all partitions except the reorganised partitions
- in REORGANIZE partition, those are handled by
- write_log_dropped_partitions. For those partitions that are replaced
- special care is needed to ensure that this is performed correctly and
- this requires a two-phased approach with this log as a helper for this.
-
- This code is closely intertwined with the code in rename_partitions in
- the partition handler.
-*/
+ build_table_filename(from_name, sizeof(from_name) - 1,
+ table_from->db.str, table_from->table_name.str,
+ "", 0);
-static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
- uint *next_entry, const char *path)
-{
- DDL_LOG_ENTRY ddl_log_entry;
- partition_info *part_info= lpt->part_info;
- DDL_LOG_MEMORY_ENTRY *log_entry;
- char tmp_path[FN_REFLEN + 1];
- char normal_path[FN_REFLEN + 1];
- List_iterator<partition_element> part_it(part_info->partitions);
- uint temp_partitions= part_info->temp_partitions.elements;
- uint num_elements= part_info->partitions.elements;
- uint i= 0;
- DBUG_ENTER("write_log_changed_partitions");
+ processed_state= PART_TO_BE_ADDED;
+ if (iterate(CONVERT_IN, SKIP_PART_NAME, NORMAL_PART_NAME,
+ &part_info->partitions))
+ return true;
+ return false;
+ }
- do
+ bool process_partition(partition_element *part_elem,
+ partition_element *sub_elem)
{
- partition_element *part_elem= part_it++;
- if (part_elem->part_state == PART_IS_CHANGED ||
- (part_elem->part_state == PART_IS_ADDED && temp_partitions))
+ switch (phase)
{
- bzero(&ddl_log_entry, sizeof(ddl_log_entry));
- if (part_info->is_sub_partitioned())
- {
- List_iterator<partition_element> sub_it(part_elem->subpartitions);
- uint num_subparts= part_info->num_subparts;
- uint j= 0;
- do
- {
- partition_element *sub_elem= sub_it++;
- ddl_log_entry.next_entry= *next_entry;
- lex_string_set(&ddl_log_entry.handler_name,
- ha_resolve_storage_engine_name(sub_elem->
- engine_type));
- if (create_subpartition_name(tmp_path, sizeof(tmp_path), path,
- part_elem->partition_name,
- sub_elem->partition_name,
- TEMP_PART_NAME) ||
- create_subpartition_name(normal_path, sizeof(normal_path), path,
- part_elem->partition_name,
- sub_elem->partition_name,
- NORMAL_PART_NAME))
- DBUG_RETURN(TRUE);
- lex_string_set(&ddl_log_entry.name, normal_path);
- lex_string_set(&ddl_log_entry.from_name, tmp_path);
- if (part_elem->part_state == PART_IS_CHANGED)
- ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION;
- else
- ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION;
- if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
- DBUG_RETURN(TRUE);
-
- *next_entry= log_entry->entry_pos;
- sub_elem->log_entry= log_entry;
- ddl_log_add_entry(part_info, log_entry);
- } while (++j < num_subparts);
- }
- else
- {
- ddl_log_entry.next_entry= *next_entry;
- lex_string_set(&ddl_log_entry.handler_name,
- ha_resolve_storage_engine_name(part_elem->engine_type));
- if (create_partition_name(tmp_path, sizeof(tmp_path), path,
- part_elem->partition_name, TEMP_PART_NAME,
- TRUE) ||
- create_partition_name(normal_path, sizeof(normal_path), path,
- part_elem->partition_name, NORMAL_PART_NAME,
- TRUE))
- DBUG_RETURN(TRUE);
- lex_string_set(&ddl_log_entry.name, normal_path);
- lex_string_set(&ddl_log_entry.from_name, tmp_path);
- if (part_elem->part_state == PART_IS_CHANGED)
- ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION;
- else
- ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION;
- if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
- {
- DBUG_RETURN(TRUE);
- }
- *next_entry= log_entry->entry_pos;
- part_elem->log_entry= log_entry;
- ddl_log_add_entry(part_info, log_entry);
- }
+ case ADD_PARTITIONS:
+ return Alter_partition_add::process_partition(part_elem, sub_elem);
+ case RENAME_TO_BACKUPS:
+ case RENAME_ADDED_PARTS:
+ case LOG_DROP_BACKUPS:
+ case CONVERT_OUT:
+ case CONVERT_IN:
+ return Alter_partition_logger::process_partition(part_elem, sub_elem);
+ default:
+ DBUG_ASSERT(0);
+ return true;
}
- } while (++i < num_elements);
- DBUG_RETURN(FALSE);
-}
-
-
-/*
- Log dropped or converted partitions
- SYNOPSIS
- log_drop_or_convert_action()
- lpt Struct containing parameters
- RETURN VALUES
- TRUE Error
- FALSE Success
-*/
-
-enum log_action_enum
-{
- ACT_DROP = 0,
- ACT_CONVERT_IN,
- ACT_CONVERT_OUT
+ return false;
+ }
};
-static bool log_drop_or_convert_action(ALTER_PARTITION_PARAM_TYPE *lpt,
- uint *next_entry, const char *path,
- const char *from_name, bool temp_list,
- const log_action_enum convert_action)
+
+bool Alter_partition_logger::iterate(Phase phase_arg,
+ uint from_name_arg, uint to_name_arg,
+ List<partition_element> *parts)
{
- DDL_LOG_ENTRY ddl_log_entry;
- DBUG_ASSERT(convert_action == ACT_DROP || (from_name != NULL));
- partition_info *part_info= lpt->part_info;
- DDL_LOG_MEMORY_ENTRY *log_entry;
- char tmp_path[FN_REFLEN + 1];
- List_iterator<partition_element> part_it(part_info->partitions);
- List_iterator<partition_element> temp_it(part_info->temp_partitions);
- uint num_temp_partitions= part_info->temp_partitions.elements;
- uint num_elements= part_info->partitions.elements;
- DBUG_ENTER("log_drop_or_convert_action");
-
- bzero(&ddl_log_entry, sizeof(ddl_log_entry));
-
- ddl_log_entry.action_type= convert_action ?
- DDL_LOG_RENAME_ACTION :
- DDL_LOG_DELETE_ACTION;
- if (temp_list)
- num_elements= num_temp_partitions;
- while (num_elements--)
- {
- partition_element *part_elem;
- if (temp_list)
- part_elem= temp_it++;
- else
- part_elem= part_it++;
- if (part_elem->part_state == PART_TO_BE_DROPPED ||
- part_elem->part_state == PART_TO_BE_ADDED ||
- part_elem->part_state == PART_CHANGED)
- {
- uint name_variant;
- if (part_elem->part_state == PART_CHANGED ||
- (part_elem->part_state == PART_TO_BE_ADDED &&
- num_temp_partitions))
- name_variant= TEMP_PART_NAME;
- else
- name_variant= NORMAL_PART_NAME;
- DBUG_ASSERT(convert_action != ACT_CONVERT_IN ||
- part_elem->part_state == PART_TO_BE_ADDED);
- DBUG_ASSERT(convert_action != ACT_CONVERT_OUT ||
- part_elem->part_state == PART_TO_BE_DROPPED);
+ phase= phase_arg;
+ from_name_type= from_name_arg;
+ to_name_type= to_name_arg;
+ List_iterator<partition_element> part_it(*parts);
+ partition_element *part_elem;
+ while ((part_elem= part_it++))
+ {
+ if (check_state(part_elem))
+ {
if (part_info->is_sub_partitioned())
{
- DBUG_ASSERT(!convert_action);
List_iterator<partition_element> sub_it(part_elem->subpartitions);
uint num_subparts= part_info->num_subparts;
uint j= 0;
do
{
partition_element *sub_elem= sub_it++;
- ddl_log_entry.next_entry= *next_entry;
- lex_string_set(&ddl_log_entry.handler_name,
- ha_resolve_storage_engine_name(sub_elem->
- engine_type));
- if (create_subpartition_name(tmp_path, sizeof(tmp_path), path,
- part_elem->partition_name,
- sub_elem->partition_name, name_variant))
- DBUG_RETURN(TRUE);
- lex_string_set(&ddl_log_entry.name, tmp_path);
- if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
- {
- DBUG_RETURN(TRUE);
- }
- *next_entry= log_entry->entry_pos;
- sub_elem->log_entry= log_entry;
- ddl_log_add_entry(part_info, log_entry);
+ if (build_names(part_elem, sub_elem))
+ return true;
+ if (process_partition(part_elem, sub_elem))
+ return true;
} while (++j < num_subparts);
}
else
{
- ddl_log_entry.next_entry= *next_entry;
- lex_string_set(&ddl_log_entry.handler_name,
- ha_resolve_storage_engine_name(part_elem->engine_type));
- if (create_partition_name(tmp_path, sizeof(tmp_path), path,
- part_elem->partition_name, name_variant,
- TRUE))
- DBUG_RETURN(TRUE);
- switch (convert_action)
- {
- case ACT_CONVERT_OUT:
- ddl_log_entry.from_name= { from_name, strlen(from_name) };
- /* fall through */
- case ACT_DROP:
- ddl_log_entry.name= { tmp_path, strlen(tmp_path) };
- break;
- case ACT_CONVERT_IN:
- ddl_log_entry.name= { from_name, strlen(from_name) };
- ddl_log_entry.from_name= { tmp_path, strlen(tmp_path) };
- }
- if (ddl_log_write_entry(&ddl_log_entry, &log_entry))
- {
- DBUG_RETURN(TRUE);
- }
- *next_entry= log_entry->entry_pos;
- part_elem->log_entry= log_entry;
- ddl_log_add_entry(part_info, log_entry);
+ if (build_names(part_elem, NULL))
+ return true;
+ if (process_partition(part_elem, NULL))
+ return true;
}
}
}
- DBUG_RETURN(FALSE);
-}
-
-
-inline
-static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
- uint *next_entry, const char *path,
- bool temp_list)
-{
- return log_drop_or_convert_action(lpt, next_entry, path, NULL, temp_list,
- ACT_DROP);
-}
-
-inline
-static bool write_log_convert_partition(ALTER_PARTITION_PARAM_TYPE *lpt,
- uint *next_entry, const char *path)
-{
- char other_table[FN_REFLEN + 1];
- const ulong f= lpt->alter_info->partition_flags;
- DBUG_ASSERT((f & ALTER_PARTITION_CONVERT_IN) || (f & ALTER_PARTITION_CONVERT_OUT));
- const log_action_enum convert_action= (f & ALTER_PARTITION_CONVERT_IN)
- ? ACT_CONVERT_IN : ACT_CONVERT_OUT;
- build_table_filename(other_table, sizeof(other_table) - 1, lpt->alter_ctx->new_db.str,
- lpt->alter_ctx->new_name.str, "", 0);
- DDL_LOG_MEMORY_ENTRY *main_entry= lpt->part_info->main_entry;
- bool res= log_drop_or_convert_action(lpt, next_entry, path, other_table,
- false, convert_action);
- /*
- NOTE: main_entry is "drop shadow frm", we have to keep it like this
- because partitioning crash-safety disables it at install shadow FRM phase.
- This is needed to avoid spurious drop action when the shadow frm is replaced
- by the backup frm and there is nothing to drop.
- */
- lpt->part_info->main_entry= main_entry;
- return res;
+ return false;
}
@@ -6565,12 +6585,11 @@ static bool write_log_convert_partition(ALTER_PARTITION_PARAM_TYPE *lpt,
*/
static bool write_log_drop_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
- DDL_LOG_STATE *drop_chain)
+ DDL_LOG_STATE *drop_chain,
+ bool drop_backup)
{
char path[FN_REFLEN + 1];
DBUG_ENTER("write_log_drop_frm");
- const DDL_LOG_STATE *main_chain= lpt->part_info;
- const bool drop_backup= (drop_chain != main_chain);
build_table_shadow_filename(path, sizeof(path) - 1, lpt, drop_backup);
mysql_mutex_lock(&LOCK_gdl);
@@ -6588,15 +6607,15 @@ static bool write_log_drop_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
}
if (ddl_log_write_execute_entry(drop_chain->list->entry_pos,
- drop_backup ?
- main_chain->execute_entry->entry_pos : 0,
+ (drop_backup ?
+ lpt->rollback_chain.execute_entry->entry_pos :
+ 0),
&drop_chain->execute_entry))
goto error;
mysql_mutex_unlock(&LOCK_gdl);
DBUG_RETURN(FALSE);
error:
- release_part_info_log_entries(drop_chain->list);
mysql_mutex_unlock(&LOCK_gdl);
drop_chain->list= NULL;
my_error(ER_DDL_LOG_ERROR, MYF(0));
@@ -6607,361 +6626,67 @@ error:
static inline
bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
{
- return write_log_drop_frm(lpt, lpt->part_info);
-}
-
-
-/*
- Log renaming of shadow frm to real frm name and dropping of old frm
- SYNOPSIS
- write_log_rename_frm()
- lpt Struct containing parameters
- RETURN VALUES
- TRUE Error
- FALSE Success
- DESCRIPTION
- Prepare an entry to ensure that we complete the renaming of the frm
- file if failure occurs in the middle of the rename process.
-*/
-
-static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
-{
- partition_info *part_info= lpt->part_info;
- DDL_LOG_MEMORY_ENTRY *log_entry;
- DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->execute_entry;
- char path[FN_REFLEN + 1];
- char shadow_path[FN_REFLEN + 1];
- DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->list;
- DBUG_ENTER("write_log_rename_frm");
-
- part_info->list= NULL;
- build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
- build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
- mysql_mutex_lock(&LOCK_gdl);
- if (write_log_replace_frm(lpt, 0UL, shadow_path, path))
- goto error;
- log_entry= part_info->list;
- part_info->main_entry= log_entry;
- if (ddl_log_write_execute_entry(log_entry->entry_pos, 0,
- &exec_log_entry))
- goto error;
- release_part_info_log_entries(old_first_log_entry);
- mysql_mutex_unlock(&LOCK_gdl);
- DBUG_RETURN(FALSE);
-
-error:
- release_part_info_log_entries(part_info->list);
- mysql_mutex_unlock(&LOCK_gdl);
- part_info->list= old_first_log_entry;
- part_info->main_entry= NULL;
- my_error(ER_DDL_LOG_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
-}
-
-
-/*
- Write the log entries to ensure that the drop partition command is completed
- even in the presence of a crash.
-
- SYNOPSIS
- write_log_drop_partition()
- lpt Struct containing parameters
- RETURN VALUES
- TRUE Error
- FALSE Success
- DESCRIPTION
- Prepare entries to the ddl log indicating all partitions to drop and to
- install the shadow frm file and remove the old frm file.
-*/
-
-static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
-{
- partition_info *part_info= lpt->part_info;
- DDL_LOG_MEMORY_ENTRY *log_entry;
- DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->execute_entry;
- char tmp_path[FN_REFLEN + 1];
- char path[FN_REFLEN + 1];
- uint next_entry= 0;
- DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->list;
- DBUG_ENTER("write_log_drop_partition");
-
- part_info->list= NULL;
- build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
- build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
- mysql_mutex_lock(&LOCK_gdl);
- if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
- FALSE))
- goto error;
- if (write_log_replace_frm(lpt, next_entry, (const char*)tmp_path,
- (const char*)path))
- goto error;
- log_entry= part_info->list;
- part_info->main_entry= log_entry;
- if (ddl_log_write_execute_entry(log_entry->entry_pos, 0,
- &exec_log_entry))
- goto error;
- release_part_info_log_entries(old_first_log_entry);
- mysql_mutex_unlock(&LOCK_gdl);
- DBUG_RETURN(FALSE);
-
-error:
- release_part_info_log_entries(part_info->list);
- mysql_mutex_unlock(&LOCK_gdl);
- part_info->list= old_first_log_entry;
- part_info->main_entry= NULL;
- my_error(ER_DDL_LOG_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
-}
-
-
-static bool write_log_convert_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
-{
- partition_info *part_info= lpt->part_info;
- char tmp_path[FN_REFLEN + 1];
- char path[FN_REFLEN + 1];
- uint next_entry= part_info->list ? part_info->list->entry_pos : 0;
-
- build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
- build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
-
- mysql_mutex_lock(&LOCK_gdl);
-
- if (write_log_convert_partition(lpt, &next_entry, (const char*)path))
- goto error;
- DBUG_ASSERT(next_entry == part_info->list->entry_pos);
- if (ddl_log_write_execute_entry(part_info->list->entry_pos, 0,
- &part_info->execute_entry))
- goto error;
- mysql_mutex_unlock(&LOCK_gdl);
- return false;
-
-error:
- mysql_mutex_unlock(&LOCK_gdl);
- part_info->main_entry= NULL;
- my_error(ER_DDL_LOG_ERROR, MYF(0));
- return true;
-}
-
-
-/*
- Write the log entries to ensure that the add partition command is not
- executed at all if a crash before it has completed
-
- SYNOPSIS
- write_log_add_change_partition()
- lpt Struct containing parameters
- RETURN VALUES
- TRUE Error
- FALSE Success
- DESCRIPTION
- Prepare entries to the ddl log indicating all partitions to drop and to
- remove the shadow frm file.
- We always inject entries backwards in the list in the ddl log since we
- don't know the entry position until we have written it.
-*/
-
-static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
-{
- partition_info *part_info= lpt->part_info;
- DDL_LOG_MEMORY_ENTRY *log_entry;
- char tmp_path[FN_REFLEN + 1];
- char path[FN_REFLEN + 1];
- uint next_entry= 0;
- DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->list;
- /* write_log_drop_shadow_frm(lpt) must have been run first */
- DBUG_ASSERT(old_first_log_entry);
- DBUG_ENTER("write_log_add_change_partition");
-
- build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
- build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
- mysql_mutex_lock(&LOCK_gdl);
-
- /* Relink the previous drop shadow frm entry */
- if (old_first_log_entry)
- next_entry= old_first_log_entry->entry_pos;
- if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
- FALSE))
- goto error;
- log_entry= part_info->list;
-
- if (ddl_log_write_execute_entry(log_entry->entry_pos, 0,
- &part_info->execute_entry))
- goto error;
- mysql_mutex_unlock(&LOCK_gdl);
- DBUG_RETURN(FALSE);
-
-error:
- release_part_info_log_entries(part_info->list);
- mysql_mutex_unlock(&LOCK_gdl);
- part_info->list= old_first_log_entry;
- my_error(ER_DDL_LOG_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
-}
-
-
-/*
- Write description of how to complete the operation after first phase of
- change partitions.
-
- SYNOPSIS
- write_log_final_change_partition()
- lpt Struct containing parameters
- RETURN VALUES
- TRUE Error
- FALSE Success
- DESCRIPTION
- We will write log entries that specify to
- 1) Install the shadow frm file.
- 2) Remove all partitions reorganized. (To be able to reorganize a partition
- to the same name. Like in REORGANIZE p0 INTO (p0, p1),
- so that the later rename from the new p0-temporary name to p0 don't
- fail because the partition already exists.
- 3) Rename others to reflect the new naming scheme.
-
- Note that it is written in the ddl log in reverse.
-*/
-
-static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
-{
- partition_info *part_info= lpt->part_info;
- DDL_LOG_MEMORY_ENTRY *log_entry;
- DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->execute_entry;
- char path[FN_REFLEN + 1];
- char shadow_path[FN_REFLEN + 1];
- DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->list;
- uint next_entry= 0;
- DBUG_ENTER("write_log_final_change_partition");
-
- /*
- Do not link any previous log entry.
- Replace the revert operations with forced retry operations.
- */
- part_info->list= NULL;
- build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
- build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
- mysql_mutex_lock(&LOCK_gdl);
- if (write_log_changed_partitions(lpt, &next_entry, (const char*)path))
- goto error;
- if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
- lpt->alter_info->partition_flags &
- ALTER_PARTITION_REORGANIZE))
- goto error;
- if (write_log_replace_frm(lpt, next_entry, shadow_path, path))
- goto error;
- log_entry= part_info->list;
- part_info->main_entry= log_entry;
- /* Overwrite the revert execute log entry with this retry execute entry */
- if (ddl_log_write_execute_entry(log_entry->entry_pos, 0,
- &exec_log_entry))
- goto error;
- release_part_info_log_entries(old_first_log_entry);
- mysql_mutex_unlock(&LOCK_gdl);
- DBUG_RETURN(FALSE);
-
-error:
- release_part_info_log_entries(part_info->list);
- mysql_mutex_unlock(&LOCK_gdl);
- part_info->list= old_first_log_entry;
- part_info->main_entry= NULL;
- my_error(ER_DDL_LOG_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
-}
-
-
-/*
- Remove entry from ddl log and release resources for others to use
-
- SYNOPSIS
- write_log_completed()
- lpt Struct containing parameters
- RETURN VALUES
- TRUE Error
- FALSE Success
-*/
-
-/*
- TODO: Partitioning atomic DDL refactoring: this should be replaced with
- ddl_log_complete().
-*/
-static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt,
- bool dont_crash)
-{
- partition_info *part_info= lpt->part_info;
- DDL_LOG_MEMORY_ENTRY *log_entry= part_info->execute_entry;
- DBUG_ENTER("write_log_completed");
-
- DBUG_ASSERT(log_entry);
- mysql_mutex_lock(&LOCK_gdl);
- if (ddl_log_disable_execute_entry(&log_entry))
- {
- /*
- Failed to write, Bad...
- We have completed the operation but have log records to REMOVE
- stuff that shouldn't be removed. What clever things could one do
- here? An error output was written to the error output by the
- above method so we don't do anything here.
- */
- ;
- }
- release_part_info_log_entries(part_info->list);
- release_part_info_log_entries(part_info->execute_entry);
- mysql_mutex_unlock(&LOCK_gdl);
- part_info->execute_entry= NULL;
- part_info->list= NULL;
- DBUG_VOID_RETURN;
+ bool res= write_log_drop_frm(lpt, &lpt->rollback_chain, false);
+ if (!res)
+ lpt->drop_shadow_frm= lpt->rollback_chain.main_entry;
+ return res;
}
-
-/*
- Release all log entries
- SYNOPSIS
- release_log_entries()
- part_info Partition info struct
- RETURN VALUES
- NONE
-*/
-
-/*
- TODO: Partitioning atomic DDL refactoring: this should be replaced with
- ddl_log_release_entries().
-*/
-static void release_log_entries(partition_info *part_info)
+static inline
+bool write_log_drop_backup_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
{
- mysql_mutex_lock(&LOCK_gdl);
- release_part_info_log_entries(part_info->list);
- release_part_info_log_entries(part_info->execute_entry);
- mysql_mutex_unlock(&LOCK_gdl);
- part_info->list= NULL;
- part_info->execute_entry= NULL;
+ return write_log_drop_frm(lpt, &lpt->cleanup_chain, true);
}
/*
- Final part of partition changes to handle things when under
- LOCK TABLES.
+ Close tables, prepare for reopening under LOCK TABLES.
SYNPOSIS
alter_partition_lock_handling()
lpt Struct carrying parameters
- RETURN VALUES
- true on error
*/
-static bool alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
+static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
{
THD *thd= lpt->thd;
if (lpt->table)
{
- /*
- Remove all instances of the table and its locks and other resources.
- */
- close_all_tables_for_name(thd, lpt->table->s, HA_EXTRA_NOT_USED, NULL);
+ TABLE *table= lpt->table;
+ if (!thd->mdl_context.is_lock_owner(MDL_key::TABLE, lpt->db.str,
+ lpt->table_name.str,
+ MDL_EXCLUSIVE) &&
+ wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ {
+ /*
+ Did not succeed in getting exclusive access to the table.
+
+ Since we have altered a cached table object (and its part_info) we need
+ at least to remove this instance so it will not be reused.
+
+ Temporarily remove it from the locked table list, so that it will get
+ reopened.
+
+ Note: tested by partition_special_myisam partition_special_innodb
+ */
+ thd->locked_tables_list.unlink_from_list(thd,
+ table->pos_in_locked_tables,
+ false);
+ /*
+ Make sure that the table is unlocked, closed and removed from
+ the table cache.
+ */
+ mysql_lock_remove(thd, thd->lock, table);
+ close_thread_table(thd, &thd->open_tables);
+ lpt->table_list->table= NULL;
+ }
+ else
+ {
+ /* Ensure the share is destroyed and reopened. */
+ close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED, NULL);
+ }
}
lpt->table= 0;
lpt->table_list->table= 0;
- if (thd->locked_tables_mode)
- return thd->locked_tables_list.reopen_tables(thd, false);
-
- return false;
}
@@ -6989,197 +6714,6 @@ static int alter_close_table(ALTER_PARTITION_PARAM_TYPE *lpt)
/**
- Handle errors for ALTER TABLE for partitioning.
-
- @param lpt Struct carrying parameters
- @param action_completed The action must be completed, NOT reverted
- @param drop_partition Partitions has not been dropped yet
- @param frm_install The shadow frm-file has not yet been installed
- @param close_table Table is still open, close it before reverting
-*/
-
-/*
- TODO: Partitioning atomic DDL refactoring: this should be replaced with
- correct combination of ddl_log_revert() / ddl_log_complete()
-*/
-static void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
- bool action_completed,
- bool drop_partition,
- bool frm_install,
- bool reopen)
-{
- THD *thd= lpt->thd;
- partition_info *part_info= lpt->part_info->get_clone(thd);
- /* TABLE is going to be released, we should not access old part_info anymore */
- lpt->part_info= part_info;
- TABLE *table= lpt->table;
- DBUG_ENTER("handle_alter_part_error");
- DBUG_ASSERT(table->needs_reopen());
-
- /*
- All instances of this table needs to be closed.
- Better to do that here, than leave the cleaning up to others.
- Acquire EXCLUSIVE mdl lock if not already acquired.
- */
- if (!thd->mdl_context.is_lock_owner(MDL_key::TABLE, lpt->db.str,
- lpt->table_name.str,
- MDL_EXCLUSIVE) &&
- wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
- {
- /*
- Did not succeed in getting exclusive access to the table.
-
- Since we have altered a cached table object (and its part_info) we need
- at least to remove this instance so it will not be reused.
-
- Temporarily remove it from the locked table list, so that it will get
- reopened.
- */
- thd->locked_tables_list.unlink_from_list(thd,
- table->pos_in_locked_tables,
- false);
- /*
- Make sure that the table is unlocked, closed and removed from
- the table cache.
- */
- mysql_lock_remove(thd, thd->lock, table);
- close_thread_table(thd, &thd->open_tables);
- lpt->table_list->table= NULL;
- }
- else
- {
- /* Ensure the share is destroyed and reopened. */
- close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED, NULL);
- }
-
- if (!reopen)
- DBUG_VOID_RETURN;
-
- if (part_info->list &&
- ddl_log_execute_entry(thd, part_info->list->entry_pos))
- {
- /*
- We couldn't recover from error, most likely manual interaction
- is required.
- */
- write_log_completed(lpt, FALSE);
- release_log_entries(part_info);
- if (!action_completed)
- {
- if (drop_partition)
- {
- /* Table is still ok, but we left a shadow frm file behind. */
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 1,
- "Operation was unsuccessful, table is still "
- "intact, but it is possible that a shadow frm "
- "file was left behind");
- }
- else
- {
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 1,
- "Operation was unsuccessful, table is still "
- "intact, but it is possible that a shadow frm "
- "file was left behind. "
- "It is also possible that temporary partitions "
- "are left behind, these could be empty or more "
- "or less filled with records");
- }
- }
- else
- {
- if (frm_install)
- {
- /*
- Failed during install of shadow frm file, table isn't intact
- and dropped partitions are still there
- */
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 1,
- "Failed during alter of partitions, table is no "
- "longer intact. "
- "The frm file is in an unknown state, and a "
- "backup is required.");
- }
- else if (drop_partition)
- {
- /*
- Table is ok, we have switched to new table but left dropped
- partitions still in their places. We remove the log records and
- ask the user to perform the action manually. We remove the log
- records and ask the user to perform the action manually.
- */
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 1,
- "Failed during drop of partitions, table is "
- "intact. "
- "Manual drop of remaining partitions is required");
- }
- else
- {
- /*
- We failed during renaming of partitions. The table is most
- certainly in a very bad state so we give user warning and disable
- the table by writing an ancient frm version into it.
- */
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 1,
- "Failed during renaming of partitions. We are now "
- "in a position where table is not reusable "
- "Table is disabled by writing ancient frm file "
- "version into it");
- }
- }
- }
- else
- {
- release_log_entries(part_info);
- if (!action_completed)
- {
- /*
- We hit an error before things were completed but managed
- to recover from the error. An error occurred and we have
- restored things to original so no need for further action.
- */
- ;
- }
- else
- {
- /*
- We hit an error after we had completed most of the operation
- and were successful in a second attempt so the operation
- actually is successful now. We need to issue a warning that
- even though we reported an error the operation was successfully
- completed.
- */
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 1,
- "Operation was successfully completed by failure "
- "handling, after failure of normal operation");
- }
- }
-
- if (thd->locked_tables_mode)
- {
- Diagnostics_area *stmt_da= NULL;
- Diagnostics_area tmp_stmt_da(true);
-
- if (unlikely(thd->is_error()))
- {
- /* reopen might fail if we have a previous error, use a temporary da. */
- stmt_da= thd->get_stmt_da();
- thd->set_stmt_da(&tmp_stmt_da);
- }
-
- /* NB: error status is not needed here, the statement fails with
- the original error. */
- if (unlikely(thd->locked_tables_list.reopen_tables(thd, false)))
- sql_print_warning("We failed to reacquire LOCKs in ALTER TABLE");
-
- if (stmt_da)
- thd->set_stmt_da(stmt_da);
- }
-
- DBUG_VOID_RETURN;
-}
-
-
-/**
Downgrade an exclusive MDL lock if under LOCK TABLE.
If we don't downgrade the lock, it will not be downgraded or released
@@ -7277,17 +6811,33 @@ static bool check_table_data(ALTER_PARTITION_PARAM_TYPE *lpt)
}
+bool alter_partition_binlog(ALTER_PARTITION_PARAM_TYPE *lpt)
+{
+ bool res;
+ THD *thd= lpt->thd;
+ if (thd->lex->no_write_to_binlog)
+ return false;
+
+ thd->binlog_xid= thd->query_id;
+ res= ERROR_INJECT("alter_partition_binlog_1") ||
+ ddl_log_update_xid(&lpt->rollback_chain, thd->binlog_xid);
+ if (!res)
+ res= ERROR_INJECT("alter_partition_binlog_2") ||
+ write_bin_log(thd, false, thd->query(), thd->query_length());
+ thd->binlog_xid= 0;
+ return res;
+}
+
+
/**
Actually perform the change requested by ALTER TABLE of partitions
previously prepared.
- @param thd Thread object
@param table Original table object with new part_info
@param alter_info ALTER TABLE info
+ @param alter_ctx ALTER TABLE context
@param create_info Create info for CREATE TABLE
@param table_list List of the table involved
- @param db Database name of new table
- @param table_name Table name of new table
@return Operation status
@retval TRUE Error
@@ -7304,25 +6854,10 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list)
{
- /*
- TODO: Partitioning atomic DDL refactoring.
-
- DDL log chain state is stored in partition_info:
-
- struct st_ddl_log_memory_entry *first_log_entry;
- struct st_ddl_log_memory_entry *exec_log_entry;
- struct st_ddl_log_memory_entry *frm_log_entry;
-
- Make it stored and used in DDL_LOG_STATE like it was done in MDEV-17567.
- This requires mysql_write_frm() refactoring (see comment there).
- */
-
/* Set-up struct used to write frm files */
partition_info *part_info;
ALTER_PARTITION_PARAM_TYPE lpt_obj;
ALTER_PARTITION_PARAM_TYPE *lpt= &lpt_obj;
- bool action_completed= FALSE;
- bool frm_install= FALSE;
MDL_ticket *mdl_ticket= table->mdl_ticket;
/* option_bits is used to mark if we should log the query with IF EXISTS */
ulonglong save_option_bits= thd->variables.option_bits;
@@ -7338,163 +6873,51 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
lpt->create_info= create_info;
lpt->db_options= create_info->table_options_with_row_type();
lpt->table= table;
- lpt->key_info_buffer= 0;
- lpt->key_count= 0;
lpt->db= alter_ctx->db;
lpt->table_name= alter_ctx->table_name;
lpt->org_tabledef_version= table->s->tabledef_version;
- lpt->copied= 0;
- lpt->deleted= 0;
- lpt->pack_frm_data= NULL;
- lpt->pack_frm_len= 0;
+
+ DDL_LOG_STATE *rollback_chain= &lpt->rollback_chain;
+ DDL_LOG_STATE *cleanup_chain= &lpt->cleanup_chain;
/* Add IF EXISTS to binlog if shared table */
if (table->file->partition_ht()->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE)
thd->variables.option_bits|= OPTION_IF_EXISTS;
- if (table->file->alter_table_flags(alter_info->flags) &
- HA_PARTITION_ONE_PHASE)
- {
- /*
- In the case where the engine supports one phase online partition
- changes it is not necessary to have any exclusive locks. The
- correctness is upheld instead by transactions being aborted if they
- access the table after its partition definition has changed (if they
- are still using the old partition definition).
-
- The handler is in this case responsible to ensure that all users
- start using the new frm file after it has changed. To implement
- one phase it is necessary for the handler to have the master copy
- of the frm file and use discovery mechanisms to renew it. Thus
- write frm will write the frm, pack the new frm and finally
- the frm is deleted and the discovery mechanisms will either restore
- back to the old or installing the new after the change is activated.
-
- Thus all open tables will be discovered that they are old, if not
- earlier as soon as they try an operation using the old table. One
- should ensure that this is checked already when opening a table,
- even if it is found in the cache of open tables.
-
- change_partitions will perform all operations and it is the duty of
- the handler to ensure that the frm files in the system gets updated
- in synch with the changes made and if an error occurs that a proper
- error handling is done.
-
- If the MySQL Server crashes at this moment but the handler succeeds
- in performing the change then the binlog is not written for the
- change. There is no way to solve this as long as the binlog is not
- transactional and even then it is hard to solve it completely.
-
- The first approach here was to downgrade locks. Now a different approach
- is decided upon. The idea is that the handler will have access to the
- Alter_info when store_lock arrives with TL_WRITE_ALLOW_READ. So if the
- handler knows that this functionality can be handled with a lower lock
- level it will set the lock level to TL_WRITE_ALLOW_WRITE immediately.
- Thus the need to downgrade the lock disappears.
- 1) Write the new frm, pack it and then delete it
- 2) Perform the change within the handler
- */
- if (mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
- mysql_change_partitions(lpt))
- {
- goto err;
- }
- }
- else if (alter_info->partition_flags & ALTER_PARTITION_DROP)
+ if (alter_info->partition_flags & ALTER_PARTITION_DROP)
{
+ Alter_partition_logger action_drop(lpt);
+
/*
- Now after all checks and setting state on dropped partitions we can
- start the actual dropping of the partitions.
-
- Drop partition is actually two things happening. The first is that
- a lot of records are deleted. The second is that the behaviour of
- subsequent updates and writes and deletes will change. The delete
- part can be handled without any particular high lock level by
- transactional engines whereas non-transactional engines need to
- ensure that this change is done with an exclusive lock on the table.
- The second part, the change of partitioning does however require
- an exclusive lock to install the new partitioning as one atomic
- operation. If this is not the case, it is possible for two
- transactions to see the change in a different order than their
- serialisation order. Thus we need an exclusive lock for both
- transactional and non-transactional engines.
-
- For LIST partitions it could be possible to avoid the exclusive lock
- (and for RANGE partitions if they didn't rearrange range definitions
- after a DROP PARTITION) if one ensured that failed accesses to the
- dropped partitions was aborted for sure (thus only possible for
- transactional engines).
-
- 0) Write an entry that removes the shadow frm file if crash occurs
- 1) Write the new frm file as a shadow frm
- 2) Get an exclusive metadata lock on the table (waits for all active
- transactions using this table). This ensures that we
- can release all other locks on the table and since no one can open
- the table, there can be no new threads accessing the table. They
- will be hanging on this exclusive lock.
- 3) Write the ddl log to ensure that the operation is completed
- even in the presence of a MySQL Server crash (the log is executed
- before any other threads are started, so there are no locking issues).
- 4) Close the table that have already been opened but didn't stumble on
- the abort locked previously. This is done as part of the
- alter_close_table call.
- 5) Old place for binary logging
- 6) Install the previously written shadow frm file
- 7) Prepare handlers for drop of partitions
- 8) Drop the partitions
- 9) Remove entries from ddl log
- 10) Reopen table if under lock tables
- 11) Write the bin log
- Unfortunately the writing of the binlog is not synchronised with
- other logging activities. So no matter in which order the binlog
- is written compared to other activities there will always be cases
- where crashes make strange things occur. In this placement it can
- happen that the ALTER TABLE DROP PARTITION gets performed in the
- master but not in the slaves if we have a crash, after writing the
- ddl log but before writing the binlog. A solution to this would
- require writing the statement first in the ddl log and then
- when recovering from the crash read the binlog and insert it into
- the binlog if not written already.
- 12) Complete query
-
- We insert Error injections at all places where it could be interesting
- to test if recovery is properly done.
+ part_info chain contains roll forward actions,
+ cleanup_chain drops shadow frm.
+
+ If cleanup_chain is active part_info chain is not executed.
*/
+
if (write_log_drop_shadow_frm(lpt) ||
ERROR_INJECT("drop_partition_1") ||
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
ERROR_INJECT("drop_partition_2") ||
wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
ERROR_INJECT("drop_partition_3") ||
- write_log_drop_partition(lpt) ||
- (action_completed= TRUE, FALSE) ||
- ERROR_INJECT("drop_partition_4") ||
alter_close_table(lpt) ||
+ ERROR_INJECT("drop_partition_4") ||
+ action_drop.rename_parts() ||
ERROR_INJECT("drop_partition_5") ||
+ write_log_drop_backup_frm(lpt) ||
ERROR_INJECT("drop_partition_6") ||
- (frm_install= TRUE, FALSE) ||
- mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
- alter_partition_log_backup(lpt) ||
- (frm_install= FALSE, FALSE) ||
+ mysql_write_frm(lpt, WFRM_BACKUP_ORIGINAL) ||
ERROR_INJECT("drop_partition_7") ||
- mysql_drop_partitions(lpt) ||
+ mysql_write_frm(lpt, WFRM_INSTALL_SHADOW|WFRM_BACKUP_ORIGINAL) ||
ERROR_INJECT("drop_partition_8") ||
- (write_log_completed(lpt, FALSE), FALSE) ||
- ((!thd->lex->no_write_to_binlog) &&
- (write_bin_log(thd, FALSE,
- thd->query(), thd->query_length()), FALSE)) ||
- ERROR_INJECT("drop_partition_9"))
- {
- handle_alter_part_error(lpt, action_completed, TRUE, frm_install, true);
- goto err;
- }
- if (alter_partition_lock_handling(lpt))
- goto err;
- }
+ alter_partition_log_backup(lpt) ||
+ alter_partition_binlog(lpt))
+ goto fail;
+ } /* DROP */
else if (alter_info->partition_flags & ALTER_PARTITION_CONVERT_OUT)
{
- DDL_LOG_STATE chain_drop_backup;
- bzero(&chain_drop_backup, sizeof(chain_drop_backup));
+ Alter_partition_change action_conv_out(lpt);
if (mysql_write_frm(lpt, WFRM_WRITE_CONVERTED_TO) ||
ERROR_INJECT("convert_partition_1") ||
@@ -7504,43 +6927,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT("convert_partition_3") ||
wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
ERROR_INJECT("convert_partition_4") ||
- write_log_convert_partition(lpt) ||
- ERROR_INJECT("convert_partition_5") ||
alter_close_table(lpt) ||
+ ERROR_INJECT("convert_partition_5") ||
+ action_conv_out.convert_out() ||
ERROR_INJECT("convert_partition_6") ||
- alter_partition_convert_out(lpt) ||
+ write_log_drop_backup_frm(lpt) ||
ERROR_INJECT("convert_partition_7") ||
- write_log_drop_frm(lpt, &chain_drop_backup) ||
+ mysql_write_frm(lpt, WFRM_BACKUP_ORIGINAL) ||
+ ERROR_INJECT("convert_partition_8") ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW|WFRM_BACKUP_ORIGINAL) ||
+ ERROR_INJECT("convert_partition_9") ||
alter_partition_log_backup(lpt) ||
- ERROR_INJECT("convert_partition_8") ||
- ((!thd->lex->no_write_to_binlog) &&
- ((thd->binlog_xid= thd->query_id),
- ddl_log_update_xid(lpt->part_info, thd->binlog_xid),
- write_bin_log(thd, false, thd->query(), thd->query_length()),
- (thd->binlog_xid= 0))) ||
- ERROR_INJECT("convert_partition_9"))
- {
- DDL_LOG_STATE main_state= *lpt->part_info;
- handle_alter_part_error(lpt, true, true, false, false);
- ddl_log_complete(&chain_drop_backup);
- (void) ddl_log_revert(thd, &main_state);
- if (thd->locked_tables_mode)
- thd->locked_tables_list.reopen_tables(thd, false);
- goto err;
- }
- ddl_log_complete(lpt->part_info);
- ERROR_INJECT("convert_partition_10");
- (void) ddl_log_revert(thd, &chain_drop_backup);
- if (alter_partition_lock_handling(lpt) ||
- ERROR_INJECT("convert_partition_11"))
- goto err;
- }
+ alter_partition_binlog(lpt))
+ goto fail;
+ } /* CONVERT OUT */
else if ((alter_info->partition_flags & ALTER_PARTITION_CONVERT_IN))
{
- DDL_LOG_STATE chain_drop_backup;
- bzero(&chain_drop_backup, sizeof(chain_drop_backup));
TABLE *table_from= table_list->next_local->table;
+ TABLE_LIST *tl_from= table_from->pos_in_locked_tables;
+ Alter_partition_change action_conv_in(lpt);
if (wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
wait_while_table_is_used(thd, table_from, HA_EXTRA_PREPARE_FOR_RENAME) ||
@@ -7550,212 +6955,113 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
check_table_data(lpt))
goto err;
+ close_all_tables_for_name(lpt->thd, table_from->s,
+ HA_EXTRA_PREPARE_FOR_RENAME, NULL);
+ if (tl_from)
+ tl_from->table= NULL;
+
if (write_log_drop_shadow_frm(lpt) ||
ERROR_INJECT("convert_partition_3") ||
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
ERROR_INJECT("convert_partition_4") ||
alter_close_table(lpt) ||
ERROR_INJECT("convert_partition_5") ||
- write_log_convert_partition(lpt) ||
+ action_conv_in.convert_in() ||
ERROR_INJECT("convert_partition_6") ||
- alter_partition_convert_in(lpt) ||
+ write_log_drop_backup_frm(lpt) ||
ERROR_INJECT("convert_partition_7") ||
- (frm_install= true, false) ||
- write_log_drop_frm(lpt, &chain_drop_backup) ||
- mysql_write_frm(lpt, WFRM_INSTALL_SHADOW|WFRM_BACKUP_ORIGINAL) ||
- log_partition_alter_to_ddl_log(lpt) ||
- (frm_install= false, false) ||
+ mysql_write_frm(lpt, WFRM_BACKUP_ORIGINAL) ||
ERROR_INJECT("convert_partition_8") ||
- ((!thd->lex->no_write_to_binlog) &&
- ((thd->binlog_xid= thd->query_id),
- ddl_log_update_xid(lpt->part_info, thd->binlog_xid),
- write_bin_log(thd, false, thd->query(), thd->query_length()),
- (thd->binlog_xid= 0))) ||
- ERROR_INJECT("convert_partition_9"))
- {
- DDL_LOG_STATE main_state= *lpt->part_info;
- handle_alter_part_error(lpt, true, true, false, false);
- ddl_log_complete(&chain_drop_backup);
- (void) ddl_log_revert(thd, &main_state);
- if (thd->locked_tables_mode)
- thd->locked_tables_list.reopen_tables(thd, false);
- goto err;
+ mysql_write_frm(lpt, WFRM_INSTALL_SHADOW|WFRM_BACKUP_ORIGINAL) ||
+ ERROR_INJECT("convert_partition_9") ||
+ alter_partition_log_backup(lpt) ||
+ alter_partition_binlog(lpt))
+ {
+ if (tl_from)
+ thd->locked_tables_list.add_back_last_deleted_lock(tl_from);
+ goto fail;
}
- ddl_log_complete(lpt->part_info);
- ERROR_INJECT("convert_partition_10");
- (void) ddl_log_revert(thd, &chain_drop_backup);
- if (alter_partition_lock_handling(lpt) ||
- ERROR_INJECT("convert_partition_11"))
- goto err;
- }
+ } /* CONVERT IN */
else if ((alter_info->partition_flags & ALTER_PARTITION_ADD) &&
(part_info->part_type == RANGE_PARTITION ||
part_info->part_type == LIST_PARTITION))
{
DBUG_ASSERT(!(alter_info->partition_flags & ALTER_PARTITION_CONVERT_IN));
- /*
- ADD RANGE/LIST PARTITIONS
- In this case there are no tuples removed and no tuples are added.
- Thus the operation is merely adding a new partition. Thus it is
- necessary to perform the change as an atomic operation. Otherwise
- someone reading without seeing the new partition could potentially
- miss updates made by a transaction serialised before it that are
- inserted into the new partition.
-
- 0) Write an entry that removes the shadow frm file if crash occurs
- 1) Write the new frm file as a shadow frm file
- 2) Get an exclusive metadata lock on the table (waits for all active
- transactions using this table). This ensures that we
- can release all other locks on the table and since no one can open
- the table, there can be no new threads accessing the table. They
- will be hanging on this exclusive lock.
- 3) Write an entry to remove the new parttions if crash occurs
- 4) Add the new partitions.
- 5) Close all instances of the table and remove them from the table cache.
- 6) Old place for write binlog
- 7) Now the change is completed except for the installation of the
- new frm file. We thus write an action in the log to change to
- the shadow frm file
- 8) Install the new frm file of the table where the partitions are
- added to the table.
- 9) Remove entries from ddl log
- 10)Reopen tables if under lock tables
- 11)Write to binlog
- 12)Complete query
- */
+ Alter_partition_add action_add(lpt);
+
if (write_log_drop_shadow_frm(lpt) ||
ERROR_INJECT("add_partition_1") ||
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
ERROR_INJECT("add_partition_2") ||
wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
ERROR_INJECT("add_partition_3") ||
- write_log_add_change_partition(lpt) ||
+ action_add.add_parts() ||
ERROR_INJECT("add_partition_4") ||
- mysql_change_partitions(lpt) ||
- ERROR_INJECT("add_partition_5") ||
alter_close_table(lpt) ||
+ ERROR_INJECT("add_partition_5") ||
+ write_log_drop_backup_frm(lpt) ||
ERROR_INJECT("add_partition_6") ||
+ mysql_write_frm(lpt, WFRM_BACKUP_ORIGINAL) ||
ERROR_INJECT("add_partition_7") ||
- write_log_rename_frm(lpt) ||
- (action_completed= TRUE, FALSE) ||
+ mysql_write_frm(lpt, WFRM_INSTALL_SHADOW|WFRM_BACKUP_ORIGINAL) ||
ERROR_INJECT("add_partition_8") ||
- (frm_install= TRUE, FALSE) ||
- mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
alter_partition_log_backup(lpt) ||
- (frm_install= FALSE, FALSE) ||
- ERROR_INJECT("add_partition_9") ||
- (write_log_completed(lpt, FALSE), FALSE) ||
- ((!thd->lex->no_write_to_binlog) &&
- (write_bin_log(thd, FALSE,
- thd->query(), thd->query_length()), FALSE)) ||
- ERROR_INJECT("add_partition_10"))
- {
- handle_alter_part_error(lpt, action_completed, FALSE, frm_install, true);
- goto err;
- }
- if (alter_partition_lock_handling(lpt))
- goto err;
- }
+ alter_partition_binlog(lpt))
+ goto fail;
+ } /* ADD */
else
{
- /*
- ADD HASH PARTITION/
- COALESCE PARTITION/
- REBUILD PARTITION/
- REORGANIZE PARTITION
-
- In this case all records are still around after the change although
- possibly organised into new partitions, thus by ensuring that all
- updates go to both the old and the new partitioning scheme we can
- actually perform this operation lock-free. The only exception to
- this is when REORGANIZE PARTITION adds/drops ranges. In this case
- there needs to be an exclusive lock during the time when the range
- changes occur.
- This is only possible if the handler can ensure double-write for a
- period. The double write will ensure that it doesn't matter where the
- data is read from since both places are updated for writes. If such
- double writing is not performed then it is necessary to perform the
- change with the usual exclusive lock. With double writes it is even
- possible to perform writes in parallel with the reorganisation of
- partitions.
-
- Without double write procedure we get the following procedure.
- The only difference with using double write is that we can downgrade
- the lock to TL_WRITE_ALLOW_WRITE. Double write in this case only
- double writes from old to new. If we had double writing in both
- directions we could perform the change completely without exclusive
- lock for HASH partitions.
- Handlers that perform double writing during the copy phase can actually
- use a lower lock level. This can be handled inside store_lock in the
- respective handler.
-
- 0) Write an entry that removes the shadow frm file if crash occurs.
- 1) Write the shadow frm file of new partitioning.
- 2) Log such that temporary partitions added in change phase are
- removed in a crash situation.
- 3) Add the new partitions.
- Copy from the reorganised partitions to the new partitions.
- 4) Get an exclusive metadata lock on the table (waits for all active
- transactions using this table). This ensures that we
- can release all other locks on the table and since no one can open
- the table, there can be no new threads accessing the table. They
- will be hanging on this exclusive lock.
- 5) Close the table.
- 6) Log that operation is completed and log all complete actions
- needed to complete operation from here.
- 7) Old place for write bin log.
- 8) Prepare handlers for rename and delete of partitions.
- 9) Rename and drop the reorged partitions such that they are no
- longer used and rename those added to their real new names.
- 10) Install the shadow frm file.
- 11) Reopen the table if under lock tables.
- 12) Write to binlog
- 13) Complete query.
- */
+ /* ADD HASH / COALESCE / REBUILD / REORGANIZE */
+ Alter_partition_change action_change(lpt);
+
if (write_log_drop_shadow_frm(lpt) ||
ERROR_INJECT("change_partition_1") ||
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
ERROR_INJECT("change_partition_2") ||
- write_log_add_change_partition(lpt) ||
+ wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
ERROR_INJECT("change_partition_3") ||
- mysql_change_partitions(lpt) ||
+ action_change.add_parts_and_copy_data(thd) ||
ERROR_INJECT("change_partition_4") ||
- wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
- ERROR_INJECT("change_partition_5") ||
alter_close_table(lpt) ||
+ ERROR_INJECT("change_partition_5") ||
+ action_change.rename_parts() ||
ERROR_INJECT("change_partition_6") ||
- write_log_final_change_partition(lpt) ||
- (action_completed= TRUE, FALSE) ||
+ write_log_drop_backup_frm(lpt) ||
ERROR_INJECT("change_partition_7") ||
+ mysql_write_frm(lpt, WFRM_BACKUP_ORIGINAL) ||
ERROR_INJECT("change_partition_8") ||
- ((frm_install= TRUE), FALSE) ||
- mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
- alter_partition_log_backup(lpt) ||
- (frm_install= FALSE, FALSE) ||
+ mysql_write_frm(lpt, WFRM_INSTALL_SHADOW|WFRM_BACKUP_ORIGINAL) ||
ERROR_INJECT("change_partition_9") ||
- mysql_drop_partitions(lpt) ||
- ERROR_INJECT("change_partition_10") ||
- mysql_rename_partitions(lpt) ||
- ERROR_INJECT("change_partition_11") ||
- (write_log_completed(lpt, FALSE), FALSE) ||
- ((!thd->lex->no_write_to_binlog) &&
- (write_bin_log(thd, FALSE,
- thd->query(), thd->query_length()), FALSE)) ||
- ERROR_INJECT("change_partition_12"))
- {
- handle_alter_part_error(lpt, action_completed, FALSE, frm_install, true);
- goto err;
- }
- if (alter_partition_lock_handling(lpt))
- goto err;
- }
+ alter_partition_log_backup(lpt) ||
+ alter_partition_binlog(lpt))
+ goto fail;
+ } /* ADD HASH / COALESCE / REBUILD / REORGANIZE */
+
+ CRASH_INJECT("done_partition_1");
+ ddl_log_complete(rollback_chain);
+ CRASH_INJECT("done_partition_2");
+ alter_partition_lock_handling(lpt);
+ (void) ddl_log_revert(thd, cleanup_chain, true);
+
+ if (thd->locked_tables_mode)
+ (void) thd->locked_tables_list.reopen_tables(thd, false);
+
thd->variables.option_bits= save_option_bits;
downgrade_mdl_if_lock_tables_mode(thd, mdl_ticket, MDL_SHARED_NO_READ_WRITE);
- /*
- A final step is to write the query to the binlog and send ok to the
- user
- */
+
DBUG_RETURN(fast_end_partition(thd, lpt->copied, lpt->deleted, table_list));
+
+fail:
+ CRASH_INJECT("fail_partition_1");
+ ddl_log_complete(cleanup_chain);
+ CRASH_INJECT("fail_partition_2");
+ /* We may fail to drop partitions due to existing locking, so must unlock first */
+ alter_partition_lock_handling(lpt);
+ (void) ddl_log_revert(thd, rollback_chain, true);
+
+ if (thd->locked_tables_mode)
+ (void) thd->locked_tables_list.reopen_tables(thd, false);
+
err:
thd->variables.option_bits= save_option_bits;
downgrade_mdl_if_lock_tables_mode(thd, mdl_ticket, MDL_SHARED_NO_READ_WRITE);
@@ -8975,6 +8281,8 @@ static const char *longest_str(const char *s1, const char *s2,
DESCRIPTION
This method is used to calculate the partition name, service routine to
the del_ren_cre_table method.
+
+ TODO: MDEV-28844 Merge create_partition_name() and create_subpartition_name()
*/
int create_partition_name(char *out, size_t outlen, const char *in1,
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index a90eaae0bae..711d7d1c196 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -23,6 +23,7 @@
#include "sql_list.h" /* List */
#include "table.h" /* TABLE_LIST */
+#include "ddl_log.h"
class Alter_info;
class Alter_table_ctx;
@@ -46,6 +47,7 @@ typedef struct st_key_range key_range;
#define NORMAL_PART_NAME 0
#define TEMP_PART_NAME 1
#define RENAMED_PART_NAME 2
+#define SKIP_PART_NAME 255
typedef struct st_lock_param_type
{
@@ -65,8 +67,16 @@ typedef struct st_lock_param_type
uint key_count;
uint db_options;
size_t pack_frm_len;
+ DDL_LOG_MEMORY_ENTRY *drop_shadow_frm;
// TODO: remove duplicate data: part_info can be accessed via table->part_info
partition_info *part_info;
+ DDL_LOG_STATE rollback_chain;
+ DDL_LOG_STATE cleanup_chain;
+
+ st_lock_param_type()
+ {
+ bzero(this, sizeof(*this));
+ }
} ALTER_PARTITION_PARAM_TYPE;
typedef struct {
@@ -285,7 +295,6 @@ bool compare_table_with_partition(THD *thd, TABLE *table,
uint part_id);
bool partition_key_modified(TABLE *table, const MY_BITMAP *fields);
bool write_log_replace_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
- uint next_entry,
const char *from_path,
const char *to_path);
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index 134a01e4e0e..09dd0c5689b 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -396,7 +396,7 @@ static bool exchange_name_with_ddl_log(THD *thd,
*/
/* call rename table from table to tmp-name */
DBUG_EXECUTE_IF("exchange_partition_fail_3",
- my_error(ER_ERROR_ON_RENAME, MYF(0), name, tmp_name, 0);
+ my_error(ER_ERROR_ON_RENAME, MYF(0), name, "#TMP", 0);
error_set= TRUE;
goto err_rename;);
DBUG_EXECUTE_IF("exchange_partition_abort_3", DBUG_SUICIDE(););
@@ -430,7 +430,7 @@ static bool exchange_name_with_ddl_log(THD *thd,
/* call rename table from tmp-nam to partition */
DBUG_EXECUTE_IF("exchange_partition_fail_7",
- my_error(ER_ERROR_ON_RENAME, MYF(0), tmp_name, from_name, 0);
+ my_error(ER_ERROR_ON_RENAME, MYF(0), "#TMP", from_name, 0);
error_set= TRUE;
goto err_rename;);
DBUG_EXECUTE_IF("exchange_partition_abort_7", DBUG_SUICIDE(););
@@ -719,13 +719,6 @@ bool Sql_cmd_alter_table_exchange_partition::
temp_file_name, table_hton)))
goto err;
- /*
- Reopen tables under LOCK TABLES. Ignore the return value for now. It's
- better to keep master/slave in consistent state. Alternative would be to
- try to revert the exchange operation and issue error.
- */
- (void) thd->locked_tables_list.reopen_tables(thd, false);
-
if (force_if_exists)
thd->variables.option_bits|= OPTION_IF_EXISTS;
@@ -753,6 +746,7 @@ bool Sql_cmd_alter_table_exchange_partition::
err:
if (thd->locked_tables_mode)
{
+ (void) thd->locked_tables_list.reopen_tables(thd, false);
if (swap_table_mdl_ticket)
swap_table_mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
if (part_table_mdl_ticket)
@@ -999,53 +993,4 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd)
DBUG_RETURN(error);
}
-
-/**
- Move a table specified in the CONVERT TABLE <table_name> TO PARTITION ...
- to the new partition.
-
- @param lpt A structure containing parameters regarding to the statement
- ALTER TABLE ... TO PARTITION ...
- @param part_file_name a file name of the partition being added
-
- @return false on success, true on error
-*/
-
-bool alter_partition_convert_in(ALTER_PARTITION_PARAM_TYPE *lpt)
-{
- char part_file_name[2*FN_REFLEN+1];
- THD *thd= lpt->thd;
- const char *path= lpt->table_list->table->s->path.str;
- TABLE_LIST *table_from= lpt->table_list->next_local;
-
- const char *partition_name=
- thd->lex->part_info->curr_part_elem->partition_name;
-
- if (create_partition_name(part_file_name, sizeof(part_file_name), path,
- partition_name, NORMAL_PART_NAME, false))
- return true;
-
- char from_file_name[FN_REFLEN+1];
-
- build_table_filename(from_file_name, sizeof(from_file_name),
- table_from->db.str, table_from->table_name.str, "", 0);
-
- handler *file= get_new_handler(nullptr, thd->mem_root,
- table_from->table->file->ht);
- if (unlikely(!file))
- return true;
-
- close_all_tables_for_name(thd, table_from->table->s,
- HA_EXTRA_PREPARE_FOR_RENAME, nullptr);
-
- bool res= file->ha_rename_table(from_file_name, part_file_name);
-
- if (res)
- my_error(ER_ERROR_ON_RENAME, MYF(0), from_file_name,
- part_file_name, my_errno);
-
- delete file;
- return res;
-}
-
#endif /* WITH_PARTITION_STORAGE_ENGINE */
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 658afd57f9b..8acdade6f9a 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -199,7 +199,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent,
else
{
/* Revert the renames of normal tables with the help of the ddl log */
- error|= ddl_log_revert(thd, &ddl_log_state);
+ error|= ddl_log_revert(thd, &ddl_log_state, false);
}
err:
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index b72f64bc691..f800564c538 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -730,6 +730,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
uint syntax_len;
partition_info *part_info= lpt->part_info;
#endif
+ DDL_LOG_STATE *rollback_chain= &lpt->rollback_chain;
DBUG_ENTER("mysql_write_frm");
/*
@@ -808,7 +809,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
create_info->db_type= work_part_info->default_engine_type;
/* NOTE: partitioned temporary tables are not supported. */
DBUG_ASSERT(!create_info->tmp_table());
- if (ddl_log_create_table(part_info, create_info->db_type, &new_path,
+ if (ddl_log_create_table(rollback_chain, create_info->db_type, &new_path,
&alter_ctx->new_db, &alter_ctx->new_name, true) ||
ERROR_INJECT("create_before_create_frm"))
DBUG_RETURN(TRUE);
@@ -828,15 +829,20 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
if (unlikely(!frm.str))
DBUG_RETURN(TRUE);
+ if (ERROR_INJECT("alter_partition_after_create_frm"))
+ {
+ my_free((void *) frm.str);
+ DBUG_RETURN(true);
+ }
+
thd->work_part_info= work_part_info;
create_info->db_type= db_type;
- ERROR_INJECT("alter_partition_after_create_frm");
-
error= writefile(frm_name, alter_ctx->new_db.str, alter_ctx->new_name.str,
create_info->tmp_table(), frm.str, frm.length);
my_free((void *) frm.str);
- if (unlikely(error) || ERROR_INJECT("alter_partition_after_write_frm"))
+ if (unlikely(error) ||
+ ERROR_INJECT("alter_partition_after_write_frm"))
{
mysql_file_delete(key_file_frm, frm_name, MYF(0));
DBUG_RETURN(TRUE);
@@ -844,7 +850,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
DBUG_RETURN(false);
}
- if (flags & WFRM_BACKUP_ORIGINAL)
+ if (flags == WFRM_BACKUP_ORIGINAL)
{
build_table_filename(path, sizeof(path) - 1, lpt->db.str,
lpt->table_name.str, "", 0);
@@ -853,19 +859,18 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
build_table_shadow_filename(bak_path, sizeof(bak_path) - 1, lpt, true);
strxmov(bak_frm_name, bak_path, reg_ext, NullS);
- DDL_LOG_MEMORY_ENTRY *main_entry= part_info->main_entry;
+ DDL_LOG_MEMORY_ENTRY *main_entry= rollback_chain->main_entry;
mysql_mutex_lock(&LOCK_gdl);
- if (write_log_replace_frm(lpt, part_info->list->entry_pos,
- (const char*) bak_path,
- (const char*) path) ||
- ddl_log_write_execute_entry(part_info->list->entry_pos, 0,
- &part_info->execute_entry))
+ if (ddl_log_rename_frm(&lpt->rollback_chain,
+ (const char*) bak_path, (const char*) path) ||
+ ddl_log_write_execute_entry(rollback_chain->list->entry_pos, 0,
+ &rollback_chain->execute_entry))
{
mysql_mutex_unlock(&LOCK_gdl);
DBUG_RETURN(TRUE);
}
mysql_mutex_unlock(&LOCK_gdl);
- part_info->main_entry= main_entry;
+ rollback_chain->main_entry= main_entry;
if (mysql_file_rename(key_file_frm, frm_name, bak_frm_name, MYF(MY_WME)))
DBUG_RETURN(TRUE);
if (lpt->table->file->ha_create_partitioning_metadata(bak_path, path,
@@ -877,9 +882,6 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
#endif /* !WITH_PARTITION_STORAGE_ENGINE */
if (flags & WFRM_INSTALL_SHADOW)
{
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- partition_info *part_info= lpt->part_info;
-#endif
/*
Build frm file name
*/
@@ -901,7 +903,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
#ifdef WITH_PARTITION_STORAGE_ENGINE
|| lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
CHF_DELETE_FLAG) ||
- ddl_log_increment_phase(part_info->main_entry->entry_pos) ||
+ ddl_log_increment_phase(rollback_chain->main_entry->entry_pos) ||
(ddl_log_sync(), FALSE)
#endif
))
@@ -953,8 +955,8 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
err:
#ifdef WITH_PARTITION_STORAGE_ENGINE
- ddl_log_increment_phase(part_info->main_entry->entry_pos);
- part_info->main_entry= NULL;
+ ddl_log_increment_phase(lpt->drop_shadow_frm->entry_pos);
+ lpt->drop_shadow_frm= NULL;
(void) ddl_log_sync();
#endif
;
@@ -4465,7 +4467,7 @@ void HA_CREATE_INFO::finalize_ddl(THD *thd, bool roll_back)
debug_crash_here("ddl_log_create_fk_fail");
ddl_log_complete(ddl_log_state_rm);
debug_crash_here("ddl_log_create_fk_fail2");
- (void) ddl_log_revert(thd, ddl_log_state_create);
+ (void) ddl_log_revert(thd, ddl_log_state_create, true);
debug_crash_here("ddl_log_create_fk_fail3");
}
else
@@ -4479,7 +4481,7 @@ void HA_CREATE_INFO::finalize_ddl(THD *thd, bool roll_back)
ddl_log_complete(ddl_log_state_create);
debug_crash_here("ddl_log_create_log_complete2");
if (is_atomic_replace())
- (void) ddl_log_revert(thd, ddl_log_state_rm);
+ (void) ddl_log_revert(thd, ddl_log_state_rm, true);
else
ddl_log_complete(ddl_log_state_rm);
debug_crash_here("ddl_log_create_log_complete3");
@@ -11389,7 +11391,7 @@ err_with_mdl:
Prepare the transaction for the alter table's copy phase.
*/
-bool mysql_trans_prepare_alter_copy_data(THD *thd)
+int mysql_trans_prepare_alter_copy_data(THD *thd)
{
DBUG_ENTER("mysql_trans_prepare_alter_copy_data");
/*
@@ -11406,9 +11408,9 @@ bool mysql_trans_prepare_alter_copy_data(THD *thd)
Commit the copy phase of the alter table.
*/
-bool mysql_trans_commit_alter_copy_data(THD *thd)
+int mysql_trans_commit_alter_copy_data(THD *thd, bool rollback)
{
- bool error= FALSE;
+ int error= 0;
uint save_unsafe_rollback_flags;
DBUG_ENTER("mysql_trans_commit_alter_copy_data");
@@ -11417,19 +11419,29 @@ bool mysql_trans_commit_alter_copy_data(THD *thd)
DEBUG_SYNC(thd, "alter_table_copy_trans_commit");
- if (ha_enable_transaction(thd, TRUE))
- DBUG_RETURN(TRUE);
+ if ((error= ha_enable_transaction(thd, TRUE)))
+ DBUG_RETURN(error);
- /*
- Ensure that the new table is saved properly to disk before installing
- the new .frm.
- And that InnoDB's internal latches are released, to avoid deadlock
- when waiting on other instances of the table before rename (Bug#54747).
- */
- if (trans_commit_stmt(thd))
- error= TRUE;
- if (trans_commit_implicit(thd))
- error= TRUE;
+ if (!rollback)
+ {
+ /*
+ Ensure that the new table is saved properly to disk before installing
+ the new .frm.
+ And that InnoDB's internal latches are released, to avoid deadlock
+ when waiting on other instances of the table before rename (Bug#54747).
+ */
+ if (trans_commit_stmt(thd))
+ error= HA_ERR_COMMIT_ERROR;
+ if (trans_commit_implicit(thd))
+ error= HA_ERR_COMMIT_ERROR;
+ }
+ else
+ {
+ if (trans_rollback_stmt(thd))
+ error= HA_ERR_COMMIT_ERROR;
+ if (trans_rollback_implicit(thd))
+ error= HA_ERR_COMMIT_ERROR;
+ }
thd->transaction->stmt.m_unsafe_rollback_flags= save_unsafe_rollback_flags;
DBUG_RETURN(error);
@@ -11784,7 +11796,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
if (backup_reset_alter_copy_lock(thd))
error= 1;
- if (unlikely(mysql_trans_commit_alter_copy_data(thd)))
+ if (unlikely(mysql_trans_commit_alter_copy_data(thd, false)))
error= 1;
err:
diff --git a/sql/sql_table.h b/sql/sql_table.h
index 56c69b955c3..0e721c99b92 100644
--- a/sql/sql_table.h
+++ b/sql/sql_table.h
@@ -18,11 +18,35 @@
#define SQL_TABLE_INCLUDED
#include <my_sys.h> // pthread_mutex_t
+#include "mysqld_error.h"
#include "m_string.h" // LEX_CUSTRING
-#define ERROR_INJECT(code) \
- ((DBUG_IF("crash_" code) && (DBUG_SUICIDE(), 0)) || \
- (DBUG_IF("fail_" code) && (my_error(ER_UNKNOWN_ERROR, MYF(0)), 1)))
+#ifndef DBUG_OFF
+void sql_print_error(const char *format, ...);
+
+inline bool _error_inject(const char *crash_kw, const char *fail_kw)
+{
+ if (DBUG_IF(crash_kw))
+ {
+ sql_print_error("Crashing at %s", crash_kw);
+ DBUG_SUICIDE();
+ return false;
+ }
+ if (DBUG_IF(fail_kw))
+ {
+ sql_print_error("Failing at %s", fail_kw);
+ my_error(ER_UNKNOWN_ERROR, MYF(0));
+ return true;
+ }
+ DBUG_PRINT("ddl_log", ("Passing %s", fail_kw));
+ return false;
+}
+#define ERROR_INJECT(code) (_error_inject("crash_" code, "fail_" code))
+#define CRASH_INJECT(code) (_error_inject("crash_" code, "crash_" code))
+#else
+#define ERROR_INJECT(code) false
+#define CRASH_INJECT(code) do { } while(0)
+#endif
class Alter_info;
class Alter_table_ctx;
@@ -126,8 +150,8 @@ bool mysql_prepare_alter_table(THD *thd, TABLE *table,
HA_CREATE_INFO *create_info,
Alter_info *alter_info,
Alter_table_ctx *alter_ctx);
-bool mysql_trans_prepare_alter_copy_data(THD *thd);
-bool mysql_trans_commit_alter_copy_data(THD *thd);
+int mysql_trans_prepare_alter_copy_data(THD *thd);
+int mysql_trans_commit_alter_copy_data(THD *thd, bool rollback);
bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
const LEX_CSTRING *new_name,
HA_CREATE_INFO *create_info,
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 6fe0d5384a9..1b0c9f1b8c7 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -704,7 +704,7 @@ end:
ddl_log_complete(&ddl_log_state);
debug_crash_here("ddl_log_drop_before_delete_tmp");
/* delete any created log files */
- result|= ddl_log_revert(thd, &ddl_log_state_tmp_file);
+ result|= ddl_log_revert(thd, &ddl_log_state_tmp_file, true);
if (mdl_request_for_trn.ticket)
thd->mdl_context.release_lock(mdl_request_for_trn.ticket);
@@ -1118,7 +1118,7 @@ err:
}
/* Recover the old .TRN and .TRG files & delete backup files */
- ddl_log_revert(thd, ddl_log_state);
+ ddl_log_revert(thd, ddl_log_state, true);
/* All backup files are now deleted */
ddl_log_complete(ddl_log_state_tmp_file);
DBUG_RETURN(true);