Commit 2721e912 authored by Michael Widenius's avatar Michael Widenius

Added ALTER ONLINE TABLE, which will give an error if the change can't be done...

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
parent 6da8ac5f
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;
#
# 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));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment