Commit 85ec87a0 authored by ingo@mysql.com's avatar ingo@mysql.com

Worklog#1563 - Support of on-line CREATE/DROP INDEX.

This is to enable table handlers to implement online create/drop index.
It consists of some parts:
- New default handler methods in handler.h
- Split of mysql_alter_table. It decides if only one kind of
  alteration is to be done (e.g. only create indexes or only drop
  indexes etc.) It then calls the specialized new handler method if
  the handler implements it. Otherwise it calls real_alter_table.
- The parser sets flags for each alter operation detected in a
  command. These are used by mysql_alter_table for the decision.
- mysql_prepare_table is pulled out of mysql_create_table. This is
  also used by mysql_create_index to prepare the key structure array
  for the handler. It is also used by mysql_create_index and
  mysql_drop_index to prepare a call to mysql_create_frm.
- mysql_create_frm is pulled out of rea_create_table for use by
  mysql_create_index and mysql_drop_index after the index is
  created/dropped.
Thanks to Antony who supplied most of the changes.
parent 6a636a4d
...@@ -89,6 +89,20 @@ ...@@ -89,6 +89,20 @@
#define HA_NOT_READ_PREFIX_LAST 32 /* No support for index_read_last() */ #define HA_NOT_READ_PREFIX_LAST 32 /* No support for index_read_last() */
#define HA_KEY_READ_ONLY 64 /* Support HA_EXTRA_KEYREAD */ #define HA_KEY_READ_ONLY 64 /* Support HA_EXTRA_KEYREAD */
/*
Bits in index_ddl_flags(KEY *wanted_index)
for what ddl you can do with index
If none is set, the wanted type of index is not supported
by the handler at all. See WorkLog 1563.
*/
#define HA_DDL_SUPPORT 1 /* Supported by handler */
#define HA_DDL_WITH_LOCK 2 /* Can create/drop with locked table */
#define HA_DDL_ONLINE 4 /* Can create/drop without lock */
/* Return value for ddl methods */
#define HA_DDL_NOT_IMPLEMENTED -1
/* /*
Parameters for open() (in register form->filestat) Parameters for open() (in register form->filestat)
HA_GET_INFO does an implicit HA_ABORT_IF_LOCKED HA_GET_INFO does an implicit HA_ABORT_IF_LOCKED
...@@ -354,6 +368,20 @@ class handler :public Sql_alloc ...@@ -354,6 +368,20 @@ class handler :public Sql_alloc
{ {
return (HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_KEY_READ_ONLY); return (HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_KEY_READ_ONLY);
} }
virtual ulong index_ddl_flags(KEY *wanted_index) const
{
return (HA_DDL_SUPPORT);
}
virtual int add_index(TABLE *table, KEY *key_info, uint num_of_keys)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "online add index");
return (HA_DDL_NOT_IMPLEMENTED);
}
virtual int drop_index(TABLE *table, uint *key_num, uint num_of_keys)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "online drop index");
return (HA_DDL_NOT_IMPLEMENTED);
}
virtual uint max_record_length() const =0; virtual uint max_record_length() const =0;
virtual uint max_keys() const =0; virtual uint max_keys() const =0;
virtual uint max_key_parts() const =0; virtual uint max_key_parts() const =0;
......
...@@ -493,6 +493,11 @@ int mysql_handle_derived(LEX *lex); ...@@ -493,6 +493,11 @@ int mysql_handle_derived(LEX *lex);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field, Item ***copy_func, Field **from_field,
bool group,bool modify_item); bool group,bool modify_item);
int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
List<create_field> &fields,
List<Key> &keys, uint &db_options,
handler *file, KEY *&key_info_buffer,
uint &key_count, int select_field_count);
int mysql_create_table(THD *thd,const char *db, const char *table_name, int mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
List<create_field> &fields, List<Key> &keys, List<create_field> &fields, List<Key> &keys,
...@@ -509,11 +514,23 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name, ...@@ -509,11 +514,23 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name,
List<create_field> &fields, List<create_field> &fields,
List<Key> &keys,List<Alter_drop> &drop_list, List<Key> &keys,List<Alter_drop> &drop_list,
List<Alter_column> &alter_list, List<Alter_column> &alter_list,
uint order_num, ORDER *order, uint order_num, ORDER *order, int alter_flags,
enum enum_duplicates handle_duplicates, enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS, enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS,
enum tablespace_op_type tablespace_op=NO_TABLESPACE_OP, enum tablespace_op_type tablespace_op=NO_TABLESPACE_OP,
bool simple_alter=0); bool simple_alter=0);
int real_alter_table(THD *thd, char *new_db, char *new_name,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
TABLE *table,
List<create_field> &fields,
List<Key> &keys,List<Alter_drop> &drop_list,
List<Alter_column> &alter_list,
uint order_num, ORDER *order, int alter_flags,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS,
enum tablespace_op_type tablespace_op=NO_TABLESPACE_OP,
bool simple_alter=0);
int mysql_create_like_table(THD *thd, TABLE_LIST *table, int mysql_create_like_table(THD *thd, TABLE_LIST *table,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
Table_ident *src_table); Table_ident *src_table);
...@@ -525,6 +542,10 @@ bool mysql_rename_table(enum db_type base, ...@@ -525,6 +542,10 @@ bool mysql_rename_table(enum db_type base,
int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys); int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
int mysql_drop_index(THD *thd, TABLE_LIST *table_list, int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list); List<Alter_drop> &drop_list);
int mysql_add_column(THD *thd, TABLE_LIST *table_list,
List<create_field> &fields);
int mysql_drop_column(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &values,COND *conds, List<Item> &values,COND *conds,
uint order_num, ORDER *order, ha_rows limit, uint order_num, ORDER *order, ha_rows limit,
...@@ -927,6 +948,9 @@ void unlock_table_names(THD *thd, TABLE_LIST *table_list, ...@@ -927,6 +948,9 @@ void unlock_table_names(THD *thd, TABLE_LIST *table_list,
void unireg_init(ulong options); void unireg_init(ulong options);
void unireg_end(void); void unireg_end(void);
int mysql_create_frm(THD *thd, my_string file_name,HA_CREATE_INFO *create_info,
List<create_field> &create_field,
uint key_count,KEY *key_info,handler *db_type);
int rea_create_table(THD *thd, my_string file_name,HA_CREATE_INFO *create_info, int rea_create_table(THD *thd, my_string file_name,HA_CREATE_INFO *create_info,
List<create_field> &create_field, List<create_field> &create_field,
uint key_count,KEY *key_info); uint key_count,KEY *key_info);
......
...@@ -2497,45 +2497,6 @@ static void mysql_rm_tmp_tables(void) ...@@ -2497,45 +2497,6 @@ static void mysql_rm_tmp_tables(void)
} }
/*
CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
the proper arguments. This isn't very fast but it should work for most
cases.
One should normally create all indexes with CREATE TABLE or ALTER TABLE.
*/
int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
{
List<create_field> fields;
List<Alter_drop> drop;
List<Alter_column> alter;
HA_CREATE_INFO create_info;
DBUG_ENTER("mysql_create_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
create_info.default_table_charset= thd->variables.collation_database;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
fields, keys, drop, alter, 0, (ORDER*)0,
DUP_ERROR));
}
int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
{
List<create_field> fields;
List<Key> keys;
List<Alter_column> alter;
HA_CREATE_INFO create_info;
DBUG_ENTER("mysql_drop_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
create_info.default_table_charset= thd->variables.collation_database;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
fields, keys, drop, alter, 0, (ORDER*)0,
DUP_ERROR));
}
/***************************************************************************** /*****************************************************************************
unireg support functions unireg support functions
......
...@@ -508,6 +508,14 @@ class st_select_lex: public st_select_lex_node ...@@ -508,6 +508,14 @@ class st_select_lex: public st_select_lex_node
}; };
typedef class st_select_lex SELECT_LEX; typedef class st_select_lex SELECT_LEX;
#define ALTER_ADD_COLUMN 1
#define ALTER_DROP_COLUMN 2
#define ALTER_CHANGE_COLUMN 4
#define ALTER_ADD_INDEX 8
#define ALTER_DROP_INDEX 16
#define ALTER_RENAME 32
#define ALTER_ORDER 64
#define ALTER_OPTIONS 128
/* The state of the lex parsing. This is saved in the THD struct */ /* The state of the lex parsing. This is saved in the THD struct */
...@@ -578,6 +586,7 @@ typedef struct st_lex ...@@ -578,6 +586,7 @@ typedef struct st_lex
uint grant, grant_tot_col, which_columns; uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option; uint fk_delete_opt, fk_update_opt, fk_match_option;
uint slave_thd_opt; uint slave_thd_opt;
uint alter_flags;
uint8 describe; uint8 describe;
bool drop_if_exists, drop_temporary, local_file; bool drop_if_exists, drop_temporary, local_file;
bool in_comment, ignore_space, verbose, simple_alter, no_write_to_binlog; bool in_comment, ignore_space, verbose, simple_alter, no_write_to_binlog;
......
...@@ -2355,6 +2355,7 @@ mysql_execute_command(THD *thd) ...@@ -2355,6 +2355,7 @@ mysql_execute_command(THD *thd)
lex->key_list, lex->drop_list, lex->alter_list, lex->key_list, lex->drop_list, lex->alter_list,
select_lex->order_list.elements, select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first, (ORDER *) select_lex->order_list.first,
lex->alter_flags,
lex->duplicates, lex->duplicates,
lex->alter_keys_onoff, lex->alter_keys_onoff,
lex->tablespace_op, lex->tablespace_op,
...@@ -2503,7 +2504,7 @@ mysql_execute_command(THD *thd) ...@@ -2503,7 +2504,7 @@ mysql_execute_command(THD *thd)
res= mysql_alter_table(thd, NullS, NullS, &create_info, res= mysql_alter_table(thd, NullS, NullS, &create_info,
tables, lex->create_list, tables, lex->create_list,
lex->key_list, lex->drop_list, lex->alter_list, lex->key_list, lex->drop_list, lex->alter_list,
0, (ORDER *) 0, 0, (ORDER *) 0, 0,
DUP_ERROR); DUP_ERROR);
} }
else else
......
This diff is collapsed.
...@@ -1441,10 +1441,29 @@ attribute: ...@@ -1441,10 +1441,29 @@ attribute:
| DEFAULT signed_literal { Lex->default_value=$2; } | DEFAULT signed_literal { Lex->default_value=$2; }
| AUTO_INC { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; } | AUTO_INC { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; }
| SERIAL_SYM DEFAULT VALUE_SYM | SERIAL_SYM DEFAULT VALUE_SYM
{ Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNIQUE_FLAG; } {
| opt_primary KEY_SYM { Lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG; } LEX *lex=Lex;
| UNIQUE_SYM { Lex->type|= UNIQUE_FLAG; } lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNIQUE_FLAG;
| UNIQUE_SYM KEY_SYM { Lex->type|= UNIQUE_KEY_FLAG; } lex->alter_flags|= ALTER_ADD_INDEX;
}
| opt_primary KEY_SYM
{
LEX *lex=Lex;
lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG;
lex->alter_flags|= ALTER_ADD_INDEX;
}
| UNIQUE_SYM
{
LEX *lex=Lex;
lex->type|= UNIQUE_FLAG;
lex->alter_flags|= ALTER_ADD_INDEX;
}
| UNIQUE_SYM KEY_SYM
{
LEX *lex=Lex;
lex->type|= UNIQUE_KEY_FLAG;
lex->alter_flags|= ALTER_ADD_INDEX;
}
| COMMENT_SYM TEXT_STRING_sys { Lex->comment= &$2; } | COMMENT_SYM TEXT_STRING_sys { Lex->comment= &$2; }
| COLLATE_SYM collation_name | COLLATE_SYM collation_name
{ {
...@@ -1697,6 +1716,7 @@ alter: ...@@ -1697,6 +1716,7 @@ alter:
lex->alter_keys_onoff=LEAVE_AS_IS; lex->alter_keys_onoff=LEAVE_AS_IS;
lex->tablespace_op=NO_TABLESPACE_OP; lex->tablespace_op=NO_TABLESPACE_OP;
lex->simple_alter=1; lex->simple_alter=1;
lex->alter_flags=0;
} }
alter_list alter_list
{} {}
...@@ -1715,16 +1735,28 @@ alter_list: ...@@ -1715,16 +1735,28 @@ alter_list:
| alter_list ',' alter_list_item; | alter_list ',' alter_list_item;
add_column: add_column:
ADD opt_column { Lex->change=0; }; ADD opt_column
{
LEX *lex=Lex;
lex->change=0;
lex->alter_flags|= ALTER_ADD_COLUMN;
};
alter_list_item: alter_list_item:
add_column column_def opt_place { Lex->simple_alter=0; } add_column column_def opt_place { Lex->simple_alter=0; }
| ADD key_def { Lex->simple_alter=0; } | ADD key_def
{
LEX *lex=Lex;
lex->simple_alter=0;
lex->alter_flags|= ALTER_ADD_INDEX;
}
| add_column '(' field_list ')' { Lex->simple_alter=0; } | add_column '(' field_list ')' { Lex->simple_alter=0; }
| CHANGE opt_column field_ident | CHANGE opt_column field_ident
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->change= $3.str; lex->simple_alter=0; lex->change= $3.str;
lex->simple_alter=0;
lex->alter_flags|= ALTER_CHANGE_COLUMN;
} }
field_spec opt_place field_spec opt_place
| MODIFY_SYM opt_column field_ident | MODIFY_SYM opt_column field_ident
...@@ -1735,6 +1767,7 @@ alter_list_item: ...@@ -1735,6 +1767,7 @@ alter_list_item:
lex->comment=0; lex->comment=0;
lex->charset= NULL; lex->charset= NULL;
lex->simple_alter=0; lex->simple_alter=0;
lex->alter_flags|= ALTER_CHANGE_COLUMN;
} }
type opt_attribute type opt_attribute
{ {
...@@ -1752,7 +1785,9 @@ alter_list_item: ...@@ -1752,7 +1785,9 @@ alter_list_item:
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->drop_list.push_back(new Alter_drop(Alter_drop::COLUMN, lex->drop_list.push_back(new Alter_drop(Alter_drop::COLUMN,
$3.str)); lex->simple_alter=0; $3.str));
lex->simple_alter=0;
lex->alter_flags|= ALTER_DROP_COLUMN;
} }
| DROP FOREIGN KEY_SYM opt_ident { Lex->simple_alter=0; } | DROP FOREIGN KEY_SYM opt_ident { Lex->simple_alter=0; }
| DROP PRIMARY_SYM KEY_SYM | DROP PRIMARY_SYM KEY_SYM
...@@ -1761,6 +1796,7 @@ alter_list_item: ...@@ -1761,6 +1796,7 @@ alter_list_item:
lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY, lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
primary_key_name)); primary_key_name));
lex->simple_alter=0; lex->simple_alter=0;
lex->alter_flags|= ALTER_DROP_INDEX;
} }
| DROP key_or_index field_ident | DROP key_or_index field_ident
{ {
...@@ -1768,6 +1804,7 @@ alter_list_item: ...@@ -1768,6 +1804,7 @@ alter_list_item:
lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY, lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str)); $3.str));
lex->simple_alter=0; lex->simple_alter=0;
lex->alter_flags|= ALTER_DROP_INDEX;
} }
| DISABLE_SYM KEYS { Lex->alter_keys_onoff=DISABLE; } | DISABLE_SYM KEYS { Lex->alter_keys_onoff=DISABLE; }
| ENABLE_SYM KEYS { Lex->alter_keys_onoff=ENABLE; } | ENABLE_SYM KEYS { Lex->alter_keys_onoff=ENABLE; }
...@@ -1776,21 +1813,34 @@ alter_list_item: ...@@ -1776,21 +1813,34 @@ alter_list_item:
LEX *lex=Lex; LEX *lex=Lex;
lex->alter_list.push_back(new Alter_column($3.str,$6)); lex->alter_list.push_back(new Alter_column($3.str,$6));
lex->simple_alter=0; lex->simple_alter=0;
lex->alter_flags|= ALTER_CHANGE_COLUMN;
} }
| ALTER opt_column field_ident DROP DEFAULT | ALTER opt_column field_ident DROP DEFAULT
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->alter_list.push_back(new Alter_column($3.str,(Item*) 0)); lex->alter_list.push_back(new Alter_column($3.str,(Item*) 0));
lex->simple_alter=0; lex->simple_alter=0;
lex->alter_flags|= ALTER_CHANGE_COLUMN;
} }
| RENAME opt_to table_ident | RENAME opt_to table_ident
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->select_lex.db=$3->db.str; lex->select_lex.db=$3->db.str;
lex->name= $3->table.str; lex->name= $3->table.str;
lex->alter_flags|= ALTER_RENAME;
} }
| create_table_options_space_separated { Lex->simple_alter=0; } | create_table_options_space_separated
| order_clause { Lex->simple_alter=0; }; {
LEX *lex=Lex;
lex->simple_alter=0;
lex->alter_flags|= ALTER_OPTIONS;
}
| order_clause
{
LEX *lex=Lex;
lex->simple_alter=0;
lex->alter_flags|= ALTER_ORDER;
};
opt_column: opt_column:
/* empty */ {} /* empty */ {}
......
...@@ -47,10 +47,11 @@ static bool make_empty_rec(int file, enum db_type table_type, ...@@ -47,10 +47,11 @@ static bool make_empty_rec(int file, enum db_type table_type,
uint reclength,uint null_fields); uint reclength,uint null_fields);
int rea_create_table(THD *thd, my_string file_name, int mysql_create_frm(THD *thd, my_string file_name,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
List<create_field> &create_fields, List<create_field> &create_fields,
uint keys, KEY *key_info) uint keys, KEY *key_info,
handler *db_file)
{ {
uint reclength,info_length,screens,key_info_length,maxlength,null_fields; uint reclength,info_length,screens,key_info_length,maxlength,null_fields;
File file; File file;
...@@ -58,13 +59,13 @@ int rea_create_table(THD *thd, my_string file_name, ...@@ -58,13 +59,13 @@ int rea_create_table(THD *thd, my_string file_name,
uchar fileinfo[64],forminfo[288],*keybuff; uchar fileinfo[64],forminfo[288],*keybuff;
TYPELIB formnames; TYPELIB formnames;
uchar *screen_buff; uchar *screen_buff;
handler *db_file;
DBUG_ENTER("rea_create_table"); DBUG_ENTER("rea_create_table");
formnames.type_names=0; formnames.type_names=0;
if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0))) if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0)))
DBUG_RETURN(1); DBUG_RETURN(1);
db_file=get_new_handler((TABLE*) 0, create_info->db_type); if (db_file == NULL)
db_file=get_new_handler((TABLE*) 0, create_info->db_type);
if (pack_header(forminfo, create_info->db_type,create_fields,info_length, if (pack_header(forminfo, create_info->db_type,create_fields,info_length,
screens, create_info->table_options, db_file)) screens, create_info->table_options, db_file))
{ {
...@@ -155,8 +156,7 @@ int rea_create_table(THD *thd, my_string file_name, ...@@ -155,8 +156,7 @@ int rea_create_table(THD *thd, my_string file_name,
if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) && if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
my_sync(file, MYF(MY_WME))) my_sync(file, MYF(MY_WME)))
goto err2; goto err2;
if (my_close(file,MYF(MY_WME)) || if (my_close(file,MYF(MY_WME)))
ha_create_table(file_name,create_info,0))
goto err3; goto err3;
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -166,6 +166,23 @@ int rea_create_table(THD *thd, my_string file_name, ...@@ -166,6 +166,23 @@ int rea_create_table(THD *thd, my_string file_name,
err2: err2:
VOID(my_close(file,MYF(MY_WME))); VOID(my_close(file,MYF(MY_WME)));
err3: err3:
DBUG_RETURN(1);
} /* mysql_create_frm */
int rea_create_table(THD *thd, my_string file_name,
HA_CREATE_INFO *create_info,
List<create_field> &create_fields,
uint keys, KEY *key_info)
{
DBUG_ENTER("rea_create_table");
if (mysql_create_frm(thd, file_name, create_info,
create_fields, keys, key_info, NULL) ||
ha_create_table(file_name,create_info,0))
goto err;
DBUG_RETURN(0);
err:
my_delete(file_name,MYF(0)); my_delete(file_name,MYF(0));
DBUG_RETURN(1); DBUG_RETURN(1);
} /* rea_create_table */ } /* rea_create_table */
......
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