Added ALTER ONLINE TABLE, which will give an error if the change can't be done 'instantly' (without a table copy)
mysql-test/r/alter_table_online.result: Test new feature mysql-test/t/alter_table_online.test: Test new feature sql/handler.cc: Added comment sql/lex.h: Added ONLINE keyword sql/mysql_priv.h: Added option to alter table to require online operation sql/share/errmsg.txt: Added error message if ONLINE can't be done sql/sql_lex.h: Added online option sql/sql_parse.cc: Added online option to mysql_alter_table() sql/sql_table.cc: Added test that gives error if table can't be done instantly when requsted to be online. Fixed wrong test if table includes a VARCHAR Fixed wrong (but unlikely) handling of error conditions in ALTER table sql/sql_yacc.yy: Added ALTER ONLINE TABLE syntax storage/maria/ha_maria.cc: Fixed bug where 'start_bulk_insert' used too small buffer if used with unknown number of rows
This commit is contained in:
parent
6da8ac5f71
commit
2721e912ba
74
mysql-test/r/alter_table_online.result
Normal file
74
mysql-test/r/alter_table_online.result
Normal file
@ -0,0 +1,74 @@
|
||||
drop table if exists t1,t2,t3;
|
||||
create table t1 (a int not null primary key, b int, c varchar(80), e enum('a','b'));
|
||||
insert into t1 (a) values (1),(2),(3);
|
||||
alter online table t1 modify b int default 5;
|
||||
alter online table t1 change b new_name int;
|
||||
alter online table t1 modify e enum('a','b','c');
|
||||
alter online table t1 comment "new comment";
|
||||
alter online table t1 rename to t2;
|
||||
alter online table t2 rename to t1;
|
||||
drop table t1;
|
||||
create temporary table t1 (a int not null primary key, b int, c varchar(80), e enum('a','b'));
|
||||
insert into t1 (a) values (1),(2),(3);
|
||||
alter online table t1 modify b int default 5;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 change b new_name int;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 modify e enum('a','b','c');
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 comment "new comment";
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 rename to t2;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
drop table t1;
|
||||
create table t1 (a int not null primary key, b int, c varchar(80), e enum('a','b'));
|
||||
insert into t1 (a) values (1),(2),(3);
|
||||
alter online table t1 drop column b, add b int;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 modify b bigint;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 modify e enum('c','a','b');
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 modify c varchar(50);
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 modify c varchar(100);
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 add f int;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 engine=memory;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter table t1 engine=innodb;
|
||||
alter table t1 add index (b);
|
||||
alter online table t1 add index c (c);
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 drop index b;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
drop table t1;
|
||||
create temporary table t1 (a int not null primary key, b int, c varchar(80), e enum('a','b'));
|
||||
insert into t1 (a) values (1),(2),(3);
|
||||
alter online table t1 drop column b, add b int;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 modify b bigint;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 modify e enum('c','a','b');
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 modify c varchar(50);
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 modify c varchar(100);
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 add f int;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 engine=memory;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter table t1 engine=innodb;
|
||||
alter table t1 add index (b);
|
||||
alter online table t1 add index c (c);
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
alter online table t1 drop index b;
|
||||
ERROR HY000: Can't execute the given 'ALTER' command as online
|
||||
drop table t1;
|
||||
create table t1 (a int not null primary key, b int, c varchar(80));
|
||||
create table t2 (a int not null primary key, b int, c varchar(80));
|
||||
create table t3 (a int not null primary key, b int, c varchar(80)) engine=merge UNION=(t1);
|
||||
alter online table t3 union=(t1,t2);
|
||||
drop table t1,t2,t3;
|
108
mysql-test/t/alter_table_online.test
Normal file
108
mysql-test/t/alter_table_online.test
Normal file
@ -0,0 +1,108 @@
|
||||
#
|
||||
# Test of alter online table
|
||||
#
|
||||
|
||||
--source include/have_innodb.inc
|
||||
--disable_warnings
|
||||
drop table if exists t1,t2,t3;
|
||||
--enable_warnings
|
||||
#
|
||||
# Test of things that can be done online
|
||||
#
|
||||
|
||||
create table t1 (a int not null primary key, b int, c varchar(80), e enum('a','b'));
|
||||
insert into t1 (a) values (1),(2),(3);
|
||||
|
||||
alter online table t1 modify b int default 5;
|
||||
alter online table t1 change b new_name int;
|
||||
alter online table t1 modify e enum('a','b','c');
|
||||
alter online table t1 comment "new comment";
|
||||
alter online table t1 rename to t2;
|
||||
alter online table t2 rename to t1;
|
||||
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# temporary tables always require a copy
|
||||
#
|
||||
|
||||
create temporary table t1 (a int not null primary key, b int, c varchar(80), e enum('a','b'));
|
||||
insert into t1 (a) values (1),(2),(3);
|
||||
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 modify b int default 5;
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 change b new_name int;
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 modify e enum('a','b','c');
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 comment "new comment";
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 rename to t2;
|
||||
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Test of things that is not possible to do online
|
||||
#
|
||||
|
||||
create table t1 (a int not null primary key, b int, c varchar(80), e enum('a','b'));
|
||||
insert into t1 (a) values (1),(2),(3);
|
||||
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 drop column b, add b int;
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 modify b bigint;
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 modify e enum('c','a','b');
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 modify c varchar(50);
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 modify c varchar(100);
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 add f int;
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 engine=memory;
|
||||
|
||||
alter table t1 engine=innodb;
|
||||
alter table t1 add index (b);
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 add index c (c);
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 drop index b;
|
||||
drop table t1;
|
||||
|
||||
create temporary table t1 (a int not null primary key, b int, c varchar(80), e enum('a','b'));
|
||||
insert into t1 (a) values (1),(2),(3);
|
||||
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 drop column b, add b int;
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 modify b bigint;
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 modify e enum('c','a','b');
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 modify c varchar(50);
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 modify c varchar(100);
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 add f int;
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 engine=memory;
|
||||
|
||||
alter table t1 engine=innodb;
|
||||
alter table t1 add index (b);
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 add index c (c);
|
||||
--error ER_CANT_DO_ONLINE
|
||||
alter online table t1 drop index b;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Test merge tables
|
||||
#
|
||||
create table t1 (a int not null primary key, b int, c varchar(80));
|
||||
create table t2 (a int not null primary key, b int, c varchar(80));
|
||||
create table t3 (a int not null primary key, b int, c varchar(80)) engine=merge UNION=(t1);
|
||||
alter online table t3 union=(t1,t2);
|
||||
drop table t1,t2,t3;
|
@ -3532,6 +3532,9 @@ handler::ha_delete_table(const char *name)
|
||||
Drop table in the engine: public interface.
|
||||
|
||||
@sa handler::drop_table()
|
||||
|
||||
The difference between this and delete_table() is that the table is open in
|
||||
drop_table().
|
||||
*/
|
||||
|
||||
void
|
||||
|
@ -378,6 +378,7 @@ static SYMBOL symbols[] = {
|
||||
{ "ON", SYM(ON)},
|
||||
{ "ONE", SYM(ONE_SYM)},
|
||||
{ "ONE_SHOT", SYM(ONE_SHOT_SYM)},
|
||||
{ "ONLINE", SYM(ONLINE_SYM)},
|
||||
{ "OPEN", SYM(OPEN_SYM)},
|
||||
{ "OPTIMIZE", SYM(OPTIMIZE)},
|
||||
{ "OPTIONS", SYM(OPTIONS_SYM)},
|
||||
|
@ -1312,7 +1312,8 @@ bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
|
||||
HA_CREATE_INFO *create_info,
|
||||
TABLE_LIST *table_list,
|
||||
Alter_info *alter_info,
|
||||
uint order_num, ORDER *order, bool ignore);
|
||||
uint order_num, ORDER *order, bool ignore,
|
||||
bool require_online);
|
||||
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list);
|
||||
bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
|
||||
TABLE_LIST *src_table,
|
||||
|
@ -6249,3 +6249,6 @@ ER_UNKNOWN_OPTION
|
||||
eng "Unknown option '%-.64s'"
|
||||
ER_BAD_OPTION_VALUE
|
||||
eng "Incorrect value '%-.64s' for option '%-.64s'"
|
||||
ER_CANT_DO_ONLINE
|
||||
eng "Can't execute the given '%s' command as online"
|
||||
|
||||
|
@ -1745,7 +1745,7 @@ typedef struct st_lex : public Query_tables_list
|
||||
|
||||
uint8 context_analysis_only;
|
||||
bool safe_to_cache_query;
|
||||
bool subqueries, ignore;
|
||||
bool subqueries, ignore, online;
|
||||
st_parsing_options parsing_options;
|
||||
Alter_info alter_info;
|
||||
/* Prepared statements SQL syntax:*/
|
||||
|
@ -2801,7 +2801,7 @@ end_with_restore_list:
|
||||
|
||||
res= mysql_alter_table(thd, first_table->db, first_table->table_name,
|
||||
&create_info, first_table, &alter_info,
|
||||
0, (ORDER*) 0, 0);
|
||||
0, (ORDER*) 0, 0, 0);
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_REPLICATION
|
||||
@ -2918,7 +2918,7 @@ end_with_restore_list:
|
||||
&alter_info,
|
||||
select_lex->order_list.elements,
|
||||
(ORDER *) select_lex->order_list.first,
|
||||
lex->ignore);
|
||||
lex->ignore, lex->online);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_RENAME_TABLE:
|
||||
|
@ -5741,8 +5741,8 @@ is_index_maintenance_unique (TABLE *table, Alter_info *alter_info)
|
||||
that need to be dropped and/or (re-)created.
|
||||
|
||||
RETURN VALUES
|
||||
TRUE error
|
||||
FALSE success
|
||||
TRUE The tables are not compatible; We have to do a full alter table
|
||||
FALSE The tables are compatible; We only have to modify the .frm
|
||||
*/
|
||||
|
||||
static
|
||||
@ -5882,6 +5882,9 @@ compare_tables(TABLE *table,
|
||||
DBUG_ASSERT(i < table->s->fields);
|
||||
create_info->fileds_option_struct[i]= tmp_new_field->option_struct;
|
||||
|
||||
/* reset common markers of how field changed */
|
||||
field->flags&= ~(FIELD_IS_RENAMED | FIELD_IN_ADD_INDEX);
|
||||
|
||||
/* Make sure we have at least the default charset in use. */
|
||||
if (!new_field->charset)
|
||||
new_field->charset= create_info->default_table_charset;
|
||||
@ -5916,7 +5919,6 @@ compare_tables(TABLE *table,
|
||||
create_info->table_options|= HA_OPTION_PACK_RECORD;
|
||||
|
||||
/* Check if field was renamed */
|
||||
field->flags&= ~FIELD_IS_RENAMED;
|
||||
if (my_strcasecmp(system_charset_info,
|
||||
field->field_name,
|
||||
tmp_new_field->field_name))
|
||||
@ -5929,8 +5931,6 @@ compare_tables(TABLE *table,
|
||||
new_field->field_name));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
// Clear indexed marker
|
||||
field->flags&= ~FIELD_IN_ADD_INDEX;
|
||||
changes|= tmp;
|
||||
}
|
||||
|
||||
@ -6244,7 +6244,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
|
||||
{
|
||||
Alter_drop *drop;
|
||||
if (field->type() == MYSQL_TYPE_STRING)
|
||||
if (field->type() == MYSQL_TYPE_VARCHAR)
|
||||
create_info->varchar= TRUE;
|
||||
/* Check if field should be dropped */
|
||||
drop_it.rewind();
|
||||
@ -6570,6 +6570,7 @@ err:
|
||||
order_num How many ORDER BY fields has been specified.
|
||||
order List of fields to ORDER BY.
|
||||
ignore Whether we have ALTER IGNORE TABLE
|
||||
require_online Give an error if we can't do operation online
|
||||
|
||||
DESCRIPTION
|
||||
This is a veery long function and is everything but the kitchen sink :)
|
||||
@ -6600,7 +6601,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
HA_CREATE_INFO *create_info,
|
||||
TABLE_LIST *table_list,
|
||||
Alter_info *alter_info,
|
||||
uint order_num, ORDER *order, bool ignore)
|
||||
uint order_num, ORDER *order, bool ignore,
|
||||
bool require_online)
|
||||
{
|
||||
TABLE *table, *new_table= 0, *name_lock= 0;
|
||||
int error= 0;
|
||||
@ -7400,10 +7402,23 @@ view_err:
|
||||
*/
|
||||
}
|
||||
|
||||
/* Check if we can do the ALTER TABLE as online */
|
||||
if (require_online)
|
||||
{
|
||||
if (index_add_count || index_drop_count ||
|
||||
(new_table &&
|
||||
!(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER)))
|
||||
{
|
||||
my_error(ER_CANT_DO_ONLINE, MYF(0), "ALTER");
|
||||
goto close_table_and_return_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the data if necessary. */
|
||||
thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
|
||||
thd->cuted_fields=0L;
|
||||
copied=deleted=0;
|
||||
|
||||
/*
|
||||
We do not copy data for MERGE tables. Only the children have data.
|
||||
MERGE tables have HA_NO_COPY_ON_ALTER set.
|
||||
@ -7435,6 +7450,8 @@ view_err:
|
||||
error= 1;
|
||||
}
|
||||
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
|
||||
if (error)
|
||||
goto close_table_and_return_error;
|
||||
|
||||
/* If we did not need to copy, we might still need to add/drop indexes. */
|
||||
if (! new_table)
|
||||
@ -7528,11 +7545,11 @@ view_err:
|
||||
}
|
||||
/*end of if (! new_table) for add/drop index*/
|
||||
|
||||
DBUG_ASSERT(error == 0);
|
||||
|
||||
if (table->s->tmp_table != NO_TMP_TABLE)
|
||||
{
|
||||
/* We changed a temporary table */
|
||||
if (error)
|
||||
goto err1;
|
||||
/* Close lock if this is a transactional table */
|
||||
if (thd->lock)
|
||||
{
|
||||
@ -7567,12 +7584,6 @@ view_err:
|
||||
}
|
||||
DEBUG_SYNC(thd, "alter_table_before_rename_result_table");
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
if (error)
|
||||
{
|
||||
VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
Data is copied. Now we:
|
||||
@ -7745,6 +7756,16 @@ end_temporary:
|
||||
thd->some_tables_deleted=0;
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
close_table_and_return_error:
|
||||
if (new_table && table->s->tmp_table == NO_TMP_TABLE)
|
||||
{
|
||||
/* This is not a temporary table, so close it the normal way */
|
||||
new_table->s->deleting= TRUE;
|
||||
intern_close_table(new_table);
|
||||
my_free(new_table,MYF(0));
|
||||
new_table= 0; // This forces call to quick_rm_table() below
|
||||
}
|
||||
|
||||
err1:
|
||||
if (new_table)
|
||||
{
|
||||
@ -8098,7 +8119,7 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
|
||||
alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
|
||||
DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
|
||||
table_list, &alter_info, 0,
|
||||
(ORDER *) 0, 0));
|
||||
(ORDER *) 0, 0, 0));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1042,6 +1042,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
%token ON /* SQL-2003-R */
|
||||
%token ONE_SHOT_SYM
|
||||
%token ONE_SYM
|
||||
%token ONLINE_SYM
|
||||
%token OPEN_SYM /* SQL-2003-R */
|
||||
%token OPTIMIZE
|
||||
%token OPTIONS_SYM
|
||||
@ -5865,7 +5866,7 @@ string_list:
|
||||
*/
|
||||
|
||||
alter:
|
||||
ALTER opt_ignore TABLE_SYM table_ident
|
||||
ALTER alter_options TABLE_SYM table_ident
|
||||
{
|
||||
THD *thd= YYTHD;
|
||||
LEX *lex= thd->lex;
|
||||
@ -6432,6 +6433,25 @@ opt_ignore:
|
||||
| IGNORE_SYM { Lex->ignore= 1;}
|
||||
;
|
||||
|
||||
alter_options:
|
||||
{ Lex->ignore= Lex->online= 0;} alter_options_part2
|
||||
;
|
||||
|
||||
alter_options_part2:
|
||||
/* empty */
|
||||
| alter_option_list
|
||||
;
|
||||
|
||||
alter_option_list:
|
||||
alter_option_list alter_option
|
||||
| alter_option
|
||||
;
|
||||
|
||||
alter_option:
|
||||
IGNORE_SYM { Lex->ignore= 1;}
|
||||
| ONLINE_SYM { Lex->online= 1;}
|
||||
|
||||
|
||||
opt_restrict:
|
||||
/* empty */ { Lex->drop_mode= DROP_DEFAULT; }
|
||||
| RESTRICT { Lex->drop_mode= DROP_RESTRICT; }
|
||||
@ -12077,6 +12097,7 @@ keyword_sp:
|
||||
| OLD_PASSWORD {}
|
||||
| ONE_SHOT_SYM {}
|
||||
| ONE_SYM {}
|
||||
| ONLINE_SYM {}
|
||||
| PACK_KEYS_SYM {}
|
||||
| PAGE_SYM {}
|
||||
| PARTIAL {}
|
||||
|
@ -1961,15 +1961,26 @@ void ha_maria::start_bulk_insert(ha_rows rows)
|
||||
{
|
||||
DBUG_ENTER("ha_maria::start_bulk_insert");
|
||||
THD *thd= table->in_use;
|
||||
ulong size= min(thd->variables.read_buff_size,
|
||||
(ulong) (table->s->avg_row_length * rows));
|
||||
MARIA_SHARE *share= file->s;
|
||||
DBUG_PRINT("info", ("start_bulk_insert: rows %lu size %lu",
|
||||
(ulong) rows, size));
|
||||
DBUG_PRINT("info", ("start_bulk_insert: rows %lu", (ulong) rows));
|
||||
|
||||
/* don't enable row cache if too few rows */
|
||||
if (!rows || (rows > MARIA_MIN_ROWS_TO_USE_WRITE_CACHE))
|
||||
{
|
||||
size_t size= thd->variables.read_buff_size;
|
||||
if (rows)
|
||||
{
|
||||
if (file->state->records)
|
||||
{
|
||||
MARIA_INFO maria_info;
|
||||
maria_status(file, &maria_info, HA_STATUS_NO_LOCK |HA_STATUS_VARIABLE);
|
||||
set_if_smaller(size, maria_info.mean_reclength * rows);
|
||||
}
|
||||
else if (table->s->avg_row_length)
|
||||
set_if_smaller(size, (size_t) (table->s->avg_row_length * rows));
|
||||
}
|
||||
maria_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &size);
|
||||
}
|
||||
|
||||
can_enable_indexes= (maria_is_all_keys_active(share->state.key_map,
|
||||
share->base.keys));
|
||||
|
Loading…
x
Reference in New Issue
Block a user