mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-33087 ALTER TABLE...ALGORITHM=COPY should build indexes more efficiently
- During copy algorithm, InnoDB should use bulk insert operation for row by row insert operation. By doing this, copy algorithm can effectively build indexes. This optimization is disabled for temporary table, versioning table and table which has foreign key relation. Introduced the variable innodb_alter_copy_bulk to allow the bulk insert operation for copy alter operation inside InnoDB. This is enabled by default ha_innobase::extra(): HA_EXTRA_END_ALTER_COPY mode tries to apply the buffered bulk insert operation, updates the non-persistent table stats. row_merge_bulk_t::write_to_index(): Update stat_n_rows after applying the bulk insert operation row_ins_clust_index_entry_low(): In case of copy algorithm, switch to bulk insert operation. copy_data_error_ignore(): Handles the error while copying the data from source to target file.
This commit is contained in:
122
sql/sql_table.cc
122
sql/sql_table.cc
@ -11766,6 +11766,59 @@ bool mysql_trans_commit_alter_copy_data(THD *thd)
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
/** Handle the error when copying data from source to target table.
|
||||
@param error error code
|
||||
@param ignore alter ignore statement
|
||||
@param to target table handler
|
||||
@param thd Mysql Thread
|
||||
@param alter_ctx Runtime context for alter statement
|
||||
@retval false in case of error
|
||||
@retval true in case of skipping the row and continue alter operation */
|
||||
static bool
|
||||
copy_data_error_ignore(int &error, bool ignore, TABLE *to,
|
||||
THD *thd, Alter_table_ctx *alter_ctx)
|
||||
{
|
||||
if (to->file->is_fatal_error(error, HA_CHECK_DUP))
|
||||
{
|
||||
/* Not a duplicate key error. */
|
||||
to->file->print_error(error, MYF(0));
|
||||
error= 1;
|
||||
return false;
|
||||
}
|
||||
/* Duplicate key error. */
|
||||
if (unlikely(alter_ctx->fk_error_if_delete_row))
|
||||
{
|
||||
/* We are trying to omit a row from the table which serves
|
||||
as parent in a foreign key. This might have broken
|
||||
referential integrity so emit an error. Note that we
|
||||
can't ignore this error even if we are
|
||||
executing ALTER IGNORE TABLE. IGNORE allows to skip rows, but
|
||||
doesn't allow to break unique or foreign key constraints, */
|
||||
my_error(ER_FK_CANNOT_DELETE_PARENT, MYF(0),
|
||||
alter_ctx->fk_error_id,
|
||||
alter_ctx->fk_error_table);
|
||||
return false;
|
||||
}
|
||||
if (ignore)
|
||||
return true;
|
||||
/* Ordinary ALTER TABLE. Report duplicate key error. */
|
||||
uint key_nr= to->file->get_dup_key(error);
|
||||
if (key_nr <= MAX_KEY)
|
||||
{
|
||||
const char *err_msg= ER_THD(thd, ER_DUP_ENTRY_WITH_KEY_NAME);
|
||||
if (key_nr == 0 && to->s->keys > 0 &&
|
||||
(to->key_info[0].key_part[0].field->flags &
|
||||
AUTO_INCREMENT_FLAG))
|
||||
err_msg= ER_THD(thd, ER_DUP_ENTRY_AUTOINCREMENT_CASE);
|
||||
print_keydup_error(to,
|
||||
key_nr >= to->s->keys ? NULL :
|
||||
&to->key_info[key_nr],
|
||||
err_msg, MYF(0));
|
||||
}
|
||||
else
|
||||
to->file->print_error(error, MYF(0));
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool ignore,
|
||||
@ -12027,58 +12080,11 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool ignore,
|
||||
to->auto_increment_field_not_null= FALSE;
|
||||
if (unlikely(error))
|
||||
{
|
||||
if (to->file->is_fatal_error(error, HA_CHECK_DUP))
|
||||
{
|
||||
/* Not a duplicate key error. */
|
||||
to->file->print_error(error, MYF(0));
|
||||
error= 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Duplicate key error. */
|
||||
if (unlikely(alter_ctx->fk_error_if_delete_row))
|
||||
{
|
||||
/*
|
||||
We are trying to omit a row from the table which serves as parent
|
||||
in a foreign key. This might have broken referential integrity so
|
||||
emit an error. Note that we can't ignore this error even if we are
|
||||
executing ALTER IGNORE TABLE. IGNORE allows to skip rows, but
|
||||
doesn't allow to break unique or foreign key constraints,
|
||||
*/
|
||||
my_error(ER_FK_CANNOT_DELETE_PARENT, MYF(0),
|
||||
alter_ctx->fk_error_id,
|
||||
alter_ctx->fk_error_table);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ignore)
|
||||
{
|
||||
/* This ALTER IGNORE TABLE. Simply skip row and continue. */
|
||||
to->file->restore_auto_increment(prev_insert_id);
|
||||
delete_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Ordinary ALTER TABLE. Report duplicate key error. */
|
||||
uint key_nr= to->file->get_dup_key(error);
|
||||
if ((int) key_nr >= 0)
|
||||
{
|
||||
const char *err_msg= ER_THD(thd, ER_DUP_ENTRY_WITH_KEY_NAME);
|
||||
if (key_nr == 0 && to->s->keys > 0 &&
|
||||
(to->key_info[0].key_part[0].field->flags &
|
||||
AUTO_INCREMENT_FLAG))
|
||||
err_msg= ER_THD(thd, ER_DUP_ENTRY_AUTOINCREMENT_CASE);
|
||||
print_keydup_error(to,
|
||||
key_nr >= to->s->keys ? NULL :
|
||||
&to->key_info[key_nr],
|
||||
err_msg, MYF(0));
|
||||
}
|
||||
else
|
||||
to->file->print_error(error, MYF(0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!copy_data_error_ignore(error, ignore, to, thd, alter_ctx))
|
||||
break;
|
||||
DBUG_ASSERT(ignore);
|
||||
to->file->restore_auto_increment(prev_insert_id);
|
||||
delete_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -12105,9 +12111,15 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool ignore,
|
||||
error= 1;
|
||||
}
|
||||
bulk_insert_started= 0;
|
||||
if (!ignore)
|
||||
to->file->extra(HA_EXTRA_END_ALTER_COPY);
|
||||
|
||||
if (!ignore && error <= 0)
|
||||
{
|
||||
int alt_error= to->file->extra(HA_EXTRA_END_ALTER_COPY);
|
||||
if (alt_error > 0)
|
||||
{
|
||||
error= alt_error;
|
||||
copy_data_error_ignore(error, false, to, thd, alter_ctx);
|
||||
}
|
||||
}
|
||||
cleanup_done= 1;
|
||||
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
|
||||
|
||||
|
Reference in New Issue
Block a user