Below is the list of changes that have just been committed into a local
5.1 repository of kostja. When kostja does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-05-21 19:07:52+04:00, kostja@vajra.(none) +10 -0
Commit for work in progress.
sql/mysql_priv.h@stripped, 2007-05-21 19:07:46+04:00, kostja@vajra.(none) +8 -10
Commit for work in progress.
sql/sql_class.h@stripped, 2007-05-21 19:07:46+04:00, kostja@vajra.(none) +11 -11
Commit for work in progress.
sql/sql_insert.cc@stripped, 2007-05-21 19:07:46+04:00, kostja@vajra.(none) +8 -9
Commit for work in progress.
sql/sql_lex.cc@stripped, 2007-05-21 19:07:46+04:00, kostja@vajra.(none) +11 -3
Commit for work in progress.
sql/sql_lex.h@stripped, 2007-05-21 19:07:46+04:00, kostja@vajra.(none) +43 -8
Commit for work in progress.
sql/sql_list.h@stripped, 2007-05-21 19:07:46+04:00, kostja@vajra.(none) +59 -9
Commit for work in progress.
sql/sql_parse.cc@stripped, 2007-05-21 19:07:46+04:00, kostja@vajra.(none) +127 -117
Commit for work in progress.
sql/sql_partition.cc@stripped, 2007-05-21 19:07:47+04:00, kostja@vajra.(none) +3 -3
Commit for work in progress.
sql/sql_table.cc@stripped, 2007-05-21 19:07:47+04:00, kostja@vajra.(none) +126 -228
Commit for work in progress.
sql/sql_yacc.yy@stripped, 2007-05-21 19:07:47+04:00, kostja@vajra.(none) +30 -26
Commit for work in progress.
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: kostja
# Host: vajra.(none)
# Root: /opt/local/work/mysql-5.1-4968-new
--- 1.507/sql/mysql_priv.h 2007-05-15 18:03:51 +04:00
+++ 1.508/sql/mysql_priv.h 2007-05-21 19:07:46 +04:00
@@ -961,14 +961,12 @@ int prepare_create_field(create_field *s
bool mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
List<create_field> &fields, List<Key> &keys,
- bool tmp_table, uint select_field_count,
- bool use_copy_create_info);
+ bool tmp_table, uint select_field_count);
bool mysql_create_table_no_lock(THD *thd, const char *db,
const char *table_name,
HA_CREATE_INFO *create_info,
List<create_field> &fields, List<Key> &keys,
- bool tmp_table, uint select_field_count,
- bool use_copy_create_info);
+ bool tmp_table, uint select_field_count);
bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
HA_CREATE_INFO *create_info,
@@ -976,8 +974,8 @@ bool mysql_alter_table(THD *thd, char *n
List<create_field> &fields,
List<Key> &keys,
uint order_num, ORDER *order, bool ignore,
- ALTER_INFO *alter_info, bool do_send_ok);
-bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
+ Alter_info *alter_info);
+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list);
bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
HA_CREATE_INFO *create_info,
Table_ident *src_table);
@@ -986,7 +984,7 @@ bool mysql_rename_table(handlerton *base
const char * new_name, uint flags);
bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
bool mysql_drop_index(THD *thd, TABLE_LIST *table_list,
- ALTER_INFO *alter_info);
+ Alter_info *alter_info);
bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
Item **conds, uint order_num, ORDER *order);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
@@ -1307,14 +1305,14 @@ char *make_default_log_name(char *buff,c
#ifdef WITH_PARTITION_STORAGE_ENGINE
uint fast_alter_partition_table(THD *thd, TABLE *table,
- ALTER_INFO *alter_info,
+ Alter_info *alter_info,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
List<create_field> *create_list,
List<Key> *key_list, char *db,
const char *table_name,
uint fast_alter_partition);
-uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
+uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
HA_CREATE_INFO *create_info,
handlerton *old_db_type,
bool *partition_changed,
@@ -1346,7 +1344,7 @@ typedef struct st_lock_param_type
ulonglong deleted;
THD *thd;
HA_CREATE_INFO *create_info;
- ALTER_INFO *alter_info;
+ Alter_info *alter_info;
List<create_field> *create_list;
List<create_field> new_create_list;
List<Key> *key_list;
--- 1.360/sql/sql_class.h 2007-05-15 18:03:51 +04:00
+++ 1.361/sql/sql_class.h 2007-05-21 19:07:46 +04:00
@@ -1944,20 +1944,20 @@ class select_insert :public select_resul
class select_create: public select_insert {
ORDER *group;
TABLE_LIST *create_table;
- List<create_field> *extra_fields;
- List<Key> *keys;
HA_CREATE_INFO *create_info;
+ Alter_info *alter_info;
Field **field;
public:
- select_create (TABLE_LIST *table_arg,
- HA_CREATE_INFO *create_info_par,
- List<create_field> &fields_par,
- List<Key> &keys_par,
- List<Item> &select_fields,enum_duplicates duplic, bool ignore)
- :select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore),
- create_table(table_arg), extra_fields(&fields_par),keys(&keys_par),
- create_info(create_info_par)
- {}
+ select_create(TABLE_LIST *table_arg,
+ HA_CREATE_INFO *create_info_arg,
+ Alter_info *alter_info_arg,
+ List<Item> &select_fields,
+ enum_duplicates duplic, bool ignore)
+ :select_insert(NULL, NULL, &select_fields, 0, 0, duplic, ignore),
+ create_table(table_arg),
+ create_info(create_info_arg),
+ alter_info(alter_info_arg)
+ {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
void binlog_show_create_table(TABLE **tables, uint count);
--- 1.268/sql/sql_insert.cc 2007-05-16 11:50:47 +04:00
+++ 1.269/sql/sql_insert.cc 2007-05-21 19:07:46 +04:00
@@ -3138,11 +3138,11 @@ bool select_insert::send_eof()
temporary table flag)
create_table in Pointer to TABLE_LIST object providing database
and name for table to be created or to be open
- extra_fields in/out Initial list of fields for table to be created
- keys in List of keys for table to be created
+ alter_info in/out Initial list of columns and indexes for the table
+ to be created
items in List of items which should be used to produce rest
of fields for the table (corresponding fields will
- be added to the end of 'extra_fields' list)
+ be added to the end of alter_info->create_list)
lock out Pointer to the MYSQL_LOCK object for table created
(or open temporary table) will be returned in this
parameter. Since this table is not included in
@@ -3171,8 +3171,7 @@ bool select_insert::send_eof()
static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
TABLE_LIST *create_table,
- List<create_field> *extra_fields,
- List<Key> *keys,
+ Alter_info *alter_info,
List<Item> *items,
MYSQL_LOCK **lock,
TABLEOP_HOOKS *hooks)
@@ -3236,7 +3235,7 @@ static TABLE *create_table_from_items(TH
DBUG_RETURN(0);
if (item->maybe_null)
cr_field->flags &= ~NOT_NULL_FLAG;
- extra_fields->push_back(cr_field);
+ alter_info->create_list.push_back(cr_field);
}
DBUG_EXECUTE_IF("sleep_create_select_before_create", my_sleep(6000000););
@@ -3261,8 +3260,8 @@ static TABLE *create_table_from_items(TH
tmp_disable_binlog(thd);
if (!mysql_create_table_no_lock(thd, create_table->db,
create_table->table_name,
- create_info, *extra_fields, *keys, 0,
- select_field_count, 0))
+ create_info, alter_info->create_list, alter_info->key_list, 0,
+ select_field_count))
{
if (create_info->table_existed &&
@@ -3388,7 +3387,7 @@ select_create::prepare(List<Item> &value
}
if (!(table= create_table_from_items(thd, create_info, create_table,
- extra_fields, keys, &values,
+ alter_info, &values,
&thd->extra_lock, hook_ptr)))
DBUG_RETURN(-1); // abort() deletes table
--- 1.241/sql/sql_lex.cc 2007-05-15 17:44:39 +04:00
+++ 1.242/sql/sql_lex.cc 2007-05-21 19:07:46 +04:00
@@ -1118,6 +1118,17 @@ int MYSQLlex(void *arg, void *yythd)
}
+Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
+ :drop_list(rhs.drop_list, mem_root),
+ alter_list(rhs.alter_list, mem_root),
+ key_list(rhs.key_list, mem_root),
+ create_list(rhs.create_list, mem_root),
+ flags(rhs.flags),
+ keys_onoff(rhs.keys_onoff),
+ tablespace_op(rhs.tablespace_op)
+{}
+
+
/*
Skip comment in the end of statement.
@@ -1786,9 +1797,6 @@ st_lex::st_lex()
:result(0), yacc_yyss(0), yacc_yyvs(0),
sql_command(SQLCOM_END)
{
- /* Check that plugins_static_buffer is declared immediately after plugins */
- compile_time_assert((&plugins + 1) == (DYNAMIC_ARRAY*)plugins_static_buffer);
-
my_init_dynamic_array2(&plugins, sizeof(plugin_ref),
plugins_static_buffer,
INITIAL_LEX_PLUGIN_LIST_SIZE,
--- 1.276/sql/sql_lex.h 2007-05-16 10:13:51 +04:00
+++ 1.277/sql/sql_lex.h 2007-05-21 19:07:46 +04:00
@@ -830,26 +830,63 @@ inline bool st_select_lex_unit::is_union
#define ALTER_REMOVE_PARTITIONING (1L << 25)
#define ALTER_FOREIGN_KEY (1L << 26)
-typedef struct st_alter_info
+/**
+ @brief Parsing data for CREATE or ALTER TABLE.
+
+ This structure contains a list of columns or indexes to be created,
+ altered or dropped.
+*/
+
+class Alter_info
{
+public:
List<Alter_drop> drop_list;
List<Alter_column> alter_list;
+ List<Key> key_list;
+ List<create_field> create_list;
uint flags;
enum enum_enable_or_disable keys_onoff;
enum tablespace_op_type tablespace_op;
List<char> partition_names;
uint no_parts;
- st_alter_info(){clear();}
- void clear()
+ Alter_info() :
+ flags(0),
+ keys_onoff(LEAVE_AS_IS),
+ tablespace_op(NO_TABLESPACE_OP),
+ no_parts(0)
+ {}
+
+ void reset()
{
+ drop_list.empty();
+ alter_list.empty();
+ key_list.empty();
+ create_list.empty();
+ flags= 0;
keys_onoff= LEAVE_AS_IS;
tablespace_op= NO_TABLESPACE_OP;
no_parts= 0;
partition_names.empty();
}
- void reset(){drop_list.empty();alter_list.empty();clear();}
-} ALTER_INFO;
+ /**
+ Construct a copy of this object to be used for mysql_alter_table
+ and mysql_create_table. Historically, these two functions modify
+ their Alter_info arguments. This behaviour breaks re-execution of
+ prepared statements and stored procedures and is compensated by
+ always supplying a copy of Alter_info to these functions.
+ The constructed copy still shares key Key, Alter_drop, create_field
+ and Alter_column elements of the lists - these structures are not
+ modified and thus are not copied.
+
+ @note You need to use check thd->is_fatal_error for out
+ of memory condition after calling this function.
+ */
+ Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root);
+private:
+ Alter_info &operator=(const Alter_info &rhs); // not implemented
+ Alter_info(const Alter_info &rhs); // not implemented
+};
struct st_sp_chistics
{
@@ -1104,8 +1141,6 @@ typedef struct st_lex : public Query_tab
List<String> interval_list;
List<LEX_USER> users_list;
List<LEX_COLUMN> columns;
- List<Key> key_list;
- List<create_field> create_list;
List<Item> *insert_list,field_list,value_list,update_list;
List<List_item> many_values;
List<set_var_base> var_list;
@@ -1203,7 +1238,7 @@ typedef struct st_lex : public Query_tab
bool safe_to_cache_query;
bool subqueries, ignore;
st_parsing_options parsing_options;
- ALTER_INFO alter_info;
+ Alter_info alter_info;
/* Prepared statements SQL syntax:*/
LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
/*
--- 1.46/sql/sql_list.h 2007-03-29 12:21:59 +04:00
+++ 1.47/sql/sql_list.h 2007-05-21 19:07:46 +04:00
@@ -63,21 +63,24 @@ public:
pointer.
*/
-class list_node :public Sql_alloc
+
+/**
+ list_node - a node of a single-linked list.
+ @note We never call a destructor for instances of this class.
+*/
+
+struct list_node :public Sql_alloc
{
-public:
list_node *next;
void *info;
list_node(void *info_par,list_node *next_par)
:next(next_par),info(info_par)
- {}
+ {}
list_node() /* For end_of_list */
- {
- info=0;
- next= this;
- }
- friend class base_list;
- friend class base_list_iterator;
+ {
+ info= 0;
+ next= this;
+ }
};
@@ -93,12 +96,57 @@ public:
inline void empty() { elements=0; first= &end_of_list; last=&first;}
inline base_list() { empty(); }
+ /**
+ This is a shallow copy constructor that implicitly passes the ownership
+ from the source list to the new instance. The old instance is not
+ updated, so both objects end up sharing the same nodes. If one of
+ the instances then adds or removes a node, the other becomes out of
+ sync ('last' pointer), while still operational. Some old code uses and
+ relies on this behaviour. This logic is quite tricky: please do not use
+ it in any new code.
+ */
inline base_list(const base_list &tmp) :Sql_alloc()
{
elements= tmp.elements;
first= tmp.first;
last= elements ? tmp.last : &first;
}
+ /**
+ Construct a deep copy of the argument in memory root mem_root.
+ The elements themselves are copied by pointer.
+ */
+ inline base_list(const base_list &rhs, MEM_ROOT *mem_root)
+ {
+ if (rhs.elements)
+ {
+ /*
+ It's okay to allocate an array of nodes at once: we never
+ call a destructor for list_node objects anyway.
+ */
+ first= (list_node*) alloc_root(mem_root,
+ sizeof(list_node) * rhs.elements);
+ if (first)
+ {
+ elements= rhs.elements;
+ list_node *dst= first;
+ list_node *src= rhs.first;
+ for (; dst < first + elements - 1; dst++, src= src->next)
+ {
+ dst->info= src->info;
+ dst->next= dst + 1;
+ }
+ /* Copy the last node */
+ dst->info= src->info;
+ dst->next= &end_of_list;
+ /* Setup 'last' member */
+ last= &dst->next;
+ return;
+ }
+ }
+ elements= 0;
+ first= &end_of_list;
+ last= &first;
+ }
inline base_list(bool error) { }
inline bool push_back(void *info)
{
@@ -349,6 +397,8 @@ template <class T> class List :public ba
public:
inline List() :base_list() {}
inline List(const List<T> &tmp) :base_list(tmp) {}
+ inline List(const List<T> &tmp, MEM_ROOT *mem_root) :
+ base_list(tmp, mem_root) {}
inline bool push_back(T *a) { return base_list::push_back(a); }
inline bool push_back(T *a, MEM_ROOT *mem_root)
{ return base_list::push_back(a, mem_root); }
--- 1.668/sql/sql_parse.cc 2007-05-15 18:03:51 +04:00
+++ 1.669/sql/sql_parse.cc 2007-05-21 19:07:46 +04:00
@@ -2094,23 +2094,41 @@ mysql_execute_command(THD *thd)
// Skip first table, which is the table we are creating
TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
TABLE_LIST *select_tables= lex->query_tables;
+ /*
+ Code below (especially in mysql_create_table() and select_create
+ methods) may modify HA_CREATE_INFO structure in LEX, so we have to
+ use a copy of this structure to make execution prepared statement-
+ safe. A shallow copy is enough as this code won't modify any memory
+ referenced from this structure.
+ */
+ HA_CREATE_INFO create_info(lex->create_info);
+ Alter_info alter_info(lex->alter_info, thd->mem_root);
+
+ if (thd->is_fatal_error)
+ {
+ /* out of memory when creating a copy of alter_info */
+ res= 1;
+ goto end_with_restore_list;
+ }
if ((res= create_table_precheck(thd, select_tables, create_table)))
goto end_with_restore_list;
+ create_info.alias= create_table->alias;
+
#ifndef HAVE_READLINK
- if (lex->create_info.data_file_name)
+ if (create_info.data_file_name)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
"DATA DIRECTORY option ignored");
- if (lex->create_info.index_file_name)
+ if (create_info.index_file_name)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
"INDEX DIRECTORY option ignored");
- lex->create_info.data_file_name=lex->create_info.index_file_name=0;
+ create_info.data_file_name= create_info.index_file_name= NULL;
#else
/* Fix names if symlinked tables */
- if (append_file_to_dir(thd, &lex->create_info.data_file_name,
+ if (append_file_to_dir(thd, &create_info.data_file_name,
create_table->table_name) ||
- append_file_to_dir(thd, &lex->create_info.index_file_name,
+ append_file_to_dir(thd, &create_info.index_file_name,
create_table->table_name))
goto end_with_restore_list;
#endif
@@ -2118,14 +2136,14 @@ mysql_execute_command(THD *thd)
If we are using SET CHARSET without DEFAULT, add an implicit
DEFAULT to not confuse old users. (This may change).
*/
- if ((lex->create_info.used_fields &
+ if ((create_info.used_fields &
(HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
HA_CREATE_USED_CHARSET)
{
- lex->create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
- lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
- lex->create_info.default_table_charset= lex->create_info.table_charset;
- lex->create_info.table_charset= 0;
+ create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
+ create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
+ create_info.default_table_charset= create_info.table_charset;
+ create_info.table_charset= 0;
}
/*
The create-select command will open and read-lock the select table
@@ -2164,7 +2182,7 @@ mysql_execute_command(THD *thd)
select_lex->options|= SELECT_NO_UNLOCK;
unit->set_limit(select_lex);
- if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
lex->link_first_table_back(create_table, link_to_local);
create_table->create= TRUE;
@@ -2176,7 +2194,7 @@ mysql_execute_command(THD *thd)
Is table which we are changing used somewhere in other parts
of query
*/
- if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
TABLE_LIST *duplicate;
create_table= lex->unlink_first_table(&link_to_local);
@@ -2188,10 +2206,10 @@ mysql_execute_command(THD *thd)
}
}
/* If we create merge table, we have to test tables in merge, too */
- if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
+ if (create_info.used_fields & HA_CREATE_USED_UNION)
{
TABLE_LIST *tab;
- for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
+ for (tab= (TABLE_LIST*) create_info.merge_list.first;
tab;
tab= tab->next_local)
{
@@ -2206,18 +2224,15 @@ mysql_execute_command(THD *thd)
}
/*
- FIXME Temporary hack which will go away once Kostja pushes
- his uber-fix for ALTER/CREATE TABLE.
+ select_create is currently not re-execution friendly and
+ needs to be created for every execution of a PS/SP.
*/
- lex->create_info.table_existed= 0;
-
if ((result= new select_create(create_table,
- &lex->create_info,
- lex->create_list,
- lex->key_list,
- select_lex->item_list,
- lex->duplicates,
- lex->ignore)))
+ &create_info,
+ &alter_info,
+ select_lex->item_list,
+ lex->duplicates,
+ lex->ignore)))
{
/*
CREATE from SELECT give its SELECT_LEX for SELECT,
@@ -2226,29 +2241,26 @@ mysql_execute_command(THD *thd)
res= handle_select(thd, lex, result, 0);
delete result;
}
- /* reset for PS */
- lex->create_list.empty();
- lex->key_list.empty();
}
- else if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ else if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
create_table= lex->unlink_first_table(&link_to_local);
}
else
{
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
- if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
thd->options|= OPTION_KEEP_LOG;
/* regular create */
if (lex->like_name)
- res= mysql_create_like_table(thd, create_table, &lex->create_info,
- lex->like_name);
+ res= mysql_create_like_table(thd, create_table, &create_info,
+ lex->like_name);
else
{
res= mysql_create_table(thd, create_table->db,
- create_table->table_name, &lex->create_info,
- lex->create_list,
- lex->key_list, 0, 0, 1);
+ create_table->table_name, &create_info,
+ alter_info.create_list,
+ alter_info.key_list, 0, 0);
}
if (!res)
send_ok(thd);
@@ -2260,15 +2272,51 @@ end_with_restore_list:
break;
}
case SQLCOM_CREATE_INDEX:
+ /* Fall through */
+ case SQLCOM_DROP_INDEX:
+ /*
+ CREATE INDEX and DROP INDEX are implemented by calling ALTER
+ TABLE with proper arguments. This isn't very fast but it
+ should work for most cases.
+
+ In the future ALTER TABLE will notice that only added
+ indexes and create these one by one for the existing table
+ without having to do a full rebuild.
+
+ One should normally create all indexes with CREATE TABLE or
+ ALTER TABLE.
+ */
+ {
+ Alter_info alter_info(lex->alter_info, thd->mem_root);
+ HA_CREATE_INFO create_info;
+
+ if (thd->is_fatal_error) /* out of memory creating a copy of alter_info*/
+ goto error;
+
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
- thd->enable_slow_log= opt_log_slow_admin_statements;
if (end_active_trans(thd))
goto error;
- res= mysql_create_index(thd, first_table, lex->key_list);
- break;
+ /*
+ Currently CREATE INDEX or DROP INDEX cause a full table rebuild
+ and thus classify as slow administrative statements just like
+ ALTER TABLE.
+ */
+ thd->enable_slow_log= opt_log_slow_admin_statements;
+ bzero((char*) &create_info, sizeof(create_info));
+ create_info.db_type= 0;
+ create_info.row_type= ROW_TYPE_NOT_USED;
+ create_info.default_table_charset= thd->variables.collation_database;
+
+ res= mysql_alter_table(thd, first_table->db, first_table->table_name,
+ &create_info, first_table,
+ alter_info.create_list,
+ alter_info.key_list,
+ 0, (ORDER*) 0, 0, &alter_info);
+ break;
+ }
#ifdef HAVE_REPLICATION
case SQLCOM_SLAVE_START:
{
@@ -2311,6 +2359,19 @@ end_with_restore_list:
ulong priv=0;
ulong priv_needed= ALTER_ACL;
/*
+ Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
+ so we have to use a copy of this structure to make execution
+ prepared statement- safe. A shallow copy is enough as no memory
+ referenced from this structure will be modified.
+ */
+ HA_CREATE_INFO create_info(lex->create_info);
+#if 0
+ Alter_info alter_info(lex->alter_info, thd->mem_root);
+#endif
+
+ if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
+ goto error;
+ /*
We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
*/
@@ -2326,7 +2387,7 @@ end_with_restore_list:
is_schema_db(select_lex->db))||
check_merge_table_access(thd, first_table->db,
(TABLE_LIST *)
- lex->create_info.merge_list.first))
+ create_info.merge_list.first))
goto error; /* purecov: inspected */
if (grant_option)
{
@@ -2345,13 +2406,13 @@ end_with_restore_list:
}
}
/* Don't yet allow changing of symlinks with ALTER TABLE */
- if (lex->create_info.data_file_name)
+ if (create_info.data_file_name)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
"DATA DIRECTORY option ignored");
- if (lex->create_info.index_file_name)
+ if (create_info.index_file_name)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
"INDEX DIRECTORY option ignored");
- lex->create_info.data_file_name=lex->create_info.index_file_name=0;
+ create_info.data_file_name= create_info.index_file_name= NULL;
/* ALTER TABLE ends previous transaction */
if (end_active_trans(thd))
goto error;
@@ -2365,12 +2426,12 @@ end_with_restore_list:
thd->enable_slow_log= opt_log_slow_admin_statements;
res= mysql_alter_table(thd, select_lex->db, lex->name.str,
- &lex->create_info,
- first_table, lex->create_list,
- lex->key_list,
+ &create_info,
+ first_table, lex->alter_info.create_list,
+ lex->alter_info.key_list,
select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
- lex->ignore, &lex->alter_info, 1);
+ lex->ignore, &lex->alter_info);
break;
}
case SQLCOM_RENAME_TABLE:
@@ -2518,7 +2579,7 @@ end_with_restore_list:
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
- mysql_recreate_table(thd, first_table, 1) :
+ mysql_recreate_table(thd, first_table) :
mysql_optimize_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
@@ -2871,14 +2932,6 @@ end_with_restore_list:
lex->drop_temporary);
}
break;
- case SQLCOM_DROP_INDEX:
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_one_table_access(thd, INDEX_ACL, all_tables))
- goto error; /* purecov: inspected */
- if (end_active_trans(thd))
- goto error;
- res= mysql_drop_index(thd, first_table, &lex->alter_info);
- break;
case SQLCOM_SHOW_PROCESSLIST:
if (!thd->security_ctx->priv_user[0] &&
check_global_access(thd,PROCESS_ACL))
@@ -3018,6 +3071,12 @@ end_with_restore_list:
break;
case SQLCOM_CREATE_DB:
{
+ /*
+ As mysql_create_db() may modify HA_CREATE_INFO structure passed to
+ it, we need to use a copy of LEX::create_info to make execution
+ prepared statement- safe.
+ */
+ HA_CREATE_INFO create_info(lex->create_info);
if (end_active_trans(thd))
{
res= -1;
@@ -3050,7 +3109,7 @@ end_with_restore_list:
is_schema_db(lex->name.str)))
break;
res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
- lex->name.str), &lex->create_info, 0);
+ lex->name.str), &create_info, 0);
break;
}
case SQLCOM_DROP_DB:
@@ -3143,6 +3202,7 @@ end_with_restore_list:
case SQLCOM_ALTER_DB:
{
LEX_STRING *db= &lex->name;
+ HA_CREATE_INFO create_info(lex->create_info);
if (check_db_name(db))
{
my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
@@ -3172,7 +3232,7 @@ end_with_restore_list:
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- res= mysql_alter_db(thd, db->str, &lex->create_info);
+ res= mysql_alter_db(thd, db->str, &create_info);
break;
}
case SQLCOM_SHOW_CREATE_DB:
@@ -3763,7 +3823,7 @@ create_sp_error:
goto error;
}
- my_bool nsok= thd->net.no_send_ok;
+ my_bool save_no_send_ok= thd->net.no_send_ok;
thd->net.no_send_ok= TRUE;
if (sp->m_flags & sp_head::MULTI_RESULTS)
{
@@ -3774,7 +3834,7 @@ create_sp_error:
back
*/
my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
- thd->net.no_send_ok= nsok;
+ thd->net.no_send_ok= save_no_send_ok;
goto error;
}
/*
@@ -3790,7 +3850,7 @@ create_sp_error:
if (check_routine_access(thd, EXECUTE_ACL,
sp->m_db.str, sp->m_name.str, TRUE, FALSE))
{
- thd->net.no_send_ok= nsok;
+ thd->net.no_send_ok= save_no_send_ok;
goto error;
}
#endif
@@ -3815,7 +3875,7 @@ create_sp_error:
thd->variables.select_limit= select_limit;
- thd->net.no_send_ok= nsok;
+ thd->net.no_send_ok= save_no_send_ok;
thd->server_status&= ~bits_to_be_cleared;
if (!res)
@@ -5446,17 +5506,17 @@ bool add_field_to_list(THD *thd, LEX_STR
if (type_modifier & PRI_KEY_FLAG)
{
lex->col_list.push_back(new key_part_spec(field_name->str, 0));
- lex->key_list.push_back(new Key(Key::PRIMARY, NullS,
- &default_key_create_info,
- 0, lex->col_list));
+ lex->alter_info.key_list.push_back(new Key(Key::PRIMARY, NullS,
+ &default_key_create_info,
+ 0, lex->col_list));
lex->col_list.empty();
}
if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
{
lex->col_list.push_back(new key_part_spec(field_name->str, 0));
- lex->key_list.push_back(new Key(Key::UNIQUE, NullS,
- &default_key_create_info, 0,
- lex->col_list));
+ lex->alter_info.key_list.push_back(new Key(Key::UNIQUE, NullS,
+ &default_key_create_info, 0,
+ lex->col_list));
lex->col_list.empty();
}
@@ -5516,7 +5576,7 @@ bool add_field_to_list(THD *thd, LEX_STR
interval_list, cs, uint_geom_type))
DBUG_RETURN(1);
- lex->create_list.push_back(new_field);
+ lex->alter_info.create_list.push_back(new_field);
lex->last_field=new_field;
DBUG_RETURN(0);
}
@@ -6539,55 +6599,6 @@ Item * all_any_subquery_creator(Item *le
/*
- 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.
-
- In the future ALTER TABLE will notice that only added indexes
- and create these one by one for the existing table without having to do
- a full rebuild.
-
- One should normally create all indexes with CREATE TABLE or ALTER TABLE.
-*/
-
-bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
-{
- List<create_field> fields;
- ALTER_INFO alter_info;
- alter_info.flags= ALTER_ADD_INDEX;
- HA_CREATE_INFO create_info;
- DBUG_ENTER("mysql_create_index");
- bzero((char*) &create_info,sizeof(create_info));
- create_info.db_type= 0;
- create_info.default_table_charset= thd->variables.collation_database;
- create_info.row_type= ROW_TYPE_NOT_USED;
- DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
- &create_info, table_list,
- fields, keys, 0, (ORDER*)0,
- 0, &alter_info, 1));
-}
-
-
-bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
-{
- List<create_field> fields;
- List<Key> keys;
- HA_CREATE_INFO create_info;
- DBUG_ENTER("mysql_drop_index");
- bzero((char*) &create_info,sizeof(create_info));
- create_info.db_type= 0;
- create_info.default_table_charset= thd->variables.collation_database;
- create_info.row_type= ROW_TYPE_NOT_USED;
- alter_info->clear();
- alter_info->flags= ALTER_DROP_INDEX;
- DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
- &create_info, table_list,
- fields, keys, 0, (ORDER*)0,
- 0, alter_info, 1));
-}
-
-
-/*
Multi update query pre-check
SYNOPSIS
@@ -6879,7 +6890,6 @@ bool create_table_precheck(THD *thd, TAB
want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
CREATE_TMP_ACL : CREATE_ACL);
- lex->create_info.alias= create_table->alias;
if (check_access(thd, want_priv, create_table->db,
&create_table->grant.privilege, 0, 0,
test(create_table->schema_table)) ||
--- 1.416/sql/sql_table.cc 2007-05-15 17:44:40 +04:00
+++ 1.417/sql/sql_table.cc 2007-05-21 19:07:47 +04:00
@@ -3165,31 +3165,6 @@ void sp_prepare_create_field(THD *thd, c
/*
- Copy HA_CREATE_INFO struct
- SYNOPSIS
- copy_create_info()
- lex_create_info The create_info struct setup by parser
- RETURN VALUES
- > 0 A pointer to a copy of the lex_create_info
- 0 Memory allocation error
- DESCRIPTION
- Allocate memory for copy of HA_CREATE_INFO structure from parser
- to ensure we can reuse the parser struct in stored procedures
- and prepared statements.
-*/
-
-static HA_CREATE_INFO *copy_create_info(HA_CREATE_INFO *lex_create_info)
-{
- HA_CREATE_INFO *create_info;
- if (!(create_info= (HA_CREATE_INFO*)sql_alloc(sizeof(HA_CREATE_INFO))))
- mem_alloc_error(sizeof(HA_CREATE_INFO));
- else
- memcpy((void*)create_info, (void*)lex_create_info, sizeof(HA_CREATE_INFO));
- return create_info;
-}
-
-
-/*
Create a table
SYNOPSIS
@@ -3197,15 +3172,12 @@ static HA_CREATE_INFO *copy_create_info(
thd Thread object
db Database
table_name Table name
- lex_create_info Create information (like MAX_ROWS)
+ create_info Create information (like MAX_ROWS)
fields List of fields to create
keys List of keys to create
internal_tmp_table Set to 1 if this is an internal temporary table
(From ALTER TABLE)
- select_field_count
- use_copy_create_info Should we make a copy of create info (we do this
- when this is called from sql_parse.cc where we
- want to ensure lex object isn't manipulated.
+ select_field_count
DESCRIPTION
If one creates a temporary table, this is automatically opened
@@ -3227,33 +3199,22 @@ static HA_CREATE_INFO *copy_create_info(
bool mysql_create_table_no_lock(THD *thd,
const char *db, const char *table_name,
- HA_CREATE_INFO *lex_create_info,
+ HA_CREATE_INFO *create_info,
List<create_field> &fields,
List<Key> &keys,bool internal_tmp_table,
- uint select_field_count,
- bool use_copy_create_info)
+ uint select_field_count)
{
char path[FN_REFLEN];
uint path_length;
const char *alias;
uint db_options, key_count;
KEY *key_info_buffer;
- HA_CREATE_INFO *create_info;
handler *file;
bool error= TRUE;
DBUG_ENTER("mysql_create_table_no_lock");
DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d",
db, table_name, internal_tmp_table));
- if (use_copy_create_info)
- {
- if (!(create_info= copy_create_info(lex_create_info)))
- {
- DBUG_RETURN(TRUE);
- }
- }
- else
- create_info= lex_create_info;
/* Check for duplicate fields and check type of table to create */
if (!fields.elements)
@@ -3600,8 +3561,7 @@ bool mysql_create_table(THD *thd, const
HA_CREATE_INFO *create_info,
List<create_field> &fields,
List<Key> &keys,bool internal_tmp_table,
- uint select_field_count,
- bool use_copy_create_info)
+ uint select_field_count)
{
TABLE *name_lock= 0;
bool result;
@@ -3652,8 +3612,7 @@ bool mysql_create_table(THD *thd, const
result= mysql_create_table_no_lock(thd, db, table_name, create_info,
fields, keys, internal_tmp_table,
- select_field_count,
- use_copy_create_info);
+ select_field_count);
unlock:
if (name_lock)
@@ -4307,10 +4266,13 @@ static bool mysql_admin_table(THD* thd,
(table->table->file->ha_check_for_upgrade(check_opt) ==
HA_ADMIN_NEEDS_ALTER))
{
+ my_bool save_no_send_ok= thd->net.no_send_ok;
ha_autocommit_or_rollback(thd, 1);
close_thread_tables(thd);
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
- result_code= mysql_recreate_table(thd, table, 0);
+ thd->net.no_send_ok= TRUE;
+ result_code= mysql_recreate_table(thd, table);
+ thd->net.no_send_ok= save_no_send_ok;
reenable_binlog(thd);
goto send_result;
}
@@ -4389,6 +4351,7 @@ send_result_message:
case HA_ADMIN_TRY_ALTER:
{
+ my_bool save_no_send_ok= thd->net.no_send_ok;
/*
This is currently used only by InnoDB. ha_innobase::optimize() answers
"try with alter", so here we close the table, do an ALTER TABLE,
@@ -4400,7 +4363,9 @@ send_result_message:
*save_next_global= table->next_global;
table->next_local= table->next_global= 0;
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
- result_code= mysql_recreate_table(thd, table, 0);
+ thd->net.no_send_ok= TRUE;
+ result_code= mysql_recreate_table(thd, table);
+ thd->net.no_send_ok= save_no_send_ok;
reenable_binlog(thd);
ha_autocommit_or_rollback(thd, 0);
close_thread_tables(thd);
@@ -4675,7 +4640,7 @@ bool mysql_preload_keys(THD* thd, TABLE_
*/
bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
- HA_CREATE_INFO *lex_create_info,
+ HA_CREATE_INFO *create_info,
Table_ident *table_ident)
{
TABLE *tmp_table, *name_lock= 0;
@@ -4689,7 +4654,6 @@ bool mysql_create_like_table(THD* thd, T
int err;
bool res= TRUE;
enum legacy_db_type not_used;
- HA_CREATE_INFO *create_info;
#ifdef WITH_PARTITION_STORAGE_ENGINE
char tmp_path[FN_REFLEN];
#endif
@@ -4697,10 +4661,6 @@ bool mysql_create_like_table(THD* thd, T
TABLE_LIST src_tables_list;
DBUG_ENTER("mysql_create_like_table");
- if (!(create_info= copy_create_info(lex_create_info)))
- {
- DBUG_RETURN(TRUE);
- }
DBUG_ASSERT(table_ident->db.str); /* Must be set in the parser */
src_db= table_ident->db.str;
@@ -5049,11 +5009,11 @@ err:
compare_tables()
table The original table.
create_list The fields for the new table.
- key_info_buffer An array of KEY structs for the new indexes.
- key_count The number of elements in the array.
+ key_list The keys for the new table
create_info Create options for the new table.
alter_info Alter options.
order_num Number of order list elements.
+ key_info_buffer OUT An array of KEY structs for new indexes
index_drop_buffer OUT An array of offsets into table->key_info.
index_drop_count OUT The number of elements in the array.
index_add_buffer OUT An array of offsets into key_info_buffer.
@@ -5080,22 +5040,79 @@ err:
ALTER_TABLE_INDEX_CHANGED Index changes, copy might be needed
*/
-static uint compare_tables(TABLE *table, List<create_field> *create_list,
- KEY *key_info_buffer, uint key_count,
+static uint compare_tables(TABLE *table,
+ List<create_field> *create_list,
+ List<Key> *key_list,
HA_CREATE_INFO *create_info,
- ALTER_INFO *alter_info, uint order_num,
- uint *index_drop_buffer, uint *index_drop_count,
- uint *index_add_buffer, uint *index_add_count,
+ Alter_info *alter_info, uint order_num,
+ KEY **key_info_buffer,
+ uint **index_drop_buffer, uint *index_drop_count,
+ uint **index_add_buffer, uint *index_add_count,
bool varchar)
{
Field **f_ptr, *field;
uint changes= 0, tmp;
+ uint key_count;
List_iterator_fast<create_field> new_field_it(*create_list);
create_field *new_field;
KEY_PART_INFO *key_part;
KEY_PART_INFO *end;
DBUG_ENTER("compare_tables");
+ {
+ THD *thd= table->in_use;
+ List<create_field> prepared_create_list;
+ List<Key> prepared_key_list;
+ uint db_options= 0;
+ /*
+ For some purposes we need prepared table structures and translated
+ key descriptions with proper default key name assignment.
+
+ Unfortunately, mysql_prepare_table() modifies the field and key
+ lists. mysql_create_table() needs the unmodified lists. Hence, we
+ need to copy the lists and all their elements. The lists contain
+ pointers to the elements only.
+
+ We cannot copy conditionally because the partition code always
+ needs prepared lists and compare_tables() needs them and is almost
+ always called.
+ */
+
+ /* Copy fields. */
+ List_iterator<create_field> prep_field_it(*create_list);
+ create_field *prep_field;
+ while ((prep_field= prep_field_it++))
+ prepared_create_list.push_back(new create_field(*prep_field));
+
+ /* Copy keys and key parts. */
+ List_iterator<Key> prep_key_it(*key_list);
+ Key *prep_key;
+ while ((prep_key= prep_key_it++))
+ {
+ List<key_part_spec> prep_columns;
+ List_iterator<key_part_spec> prep_col_it(prep_key->columns);
+ key_part_spec *prep_col;
+
+ while ((prep_col= prep_col_it++))
+ prep_columns.push_back(new key_part_spec(*prep_col));
+ prepared_key_list.push_back(new Key(prep_key->type, prep_key->name,
+ &prep_key->key_create_info,
+ prep_key->generated, prep_columns));
+ }
+
+ /* Create the prepared information. */
+ if (mysql_prepare_table(thd, create_info, &prepared_create_list,
+ &prepared_key_list,
+ (table->s->tmp_table != NO_TMP_TABLE), &db_options,
+ table->file, key_info_buffer, &key_count, 0))
+ DBUG_RETURN(1);
+ /* Try to optimize ALTER TABLE. Allocate result buffers. */
+ if (! (*index_drop_buffer=
+ (uint*) thd->alloc(sizeof(uint) * table->s->keys)) ||
+ ! (*index_add_buffer=
+ (uint*) thd->alloc(sizeof(uint) * prepared_key_list.elements)))
+ DBUG_RETURN(1);
+ }
/*
Some very basic checks. If number of fields changes, or the
handler, we need to run full ALTER TABLE. In the future
@@ -5179,7 +5196,7 @@ static uint compare_tables(TABLE *table,
KEY *table_key;
KEY *table_key_end= table->key_info + table->s->keys;
KEY *new_key;
- KEY *new_key_end= key_info_buffer + key_count;
+ KEY *new_key_end= *key_info_buffer + key_count;
DBUG_PRINT("info", ("index count old: %d new: %d",
table->s->keys, key_count));
@@ -5195,7 +5212,7 @@ static uint compare_tables(TABLE *table,
KEY_PART_INFO *new_part;
/* Search a new key with the same name. */
- for (new_key= key_info_buffer; new_key < new_key_end; new_key++)
+ for (new_key= *key_info_buffer; new_key < new_key_end; new_key++)
{
if (! strcmp(table_key->name, new_key->name))
break;
@@ -5203,7 +5220,7 @@ static uint compare_tables(TABLE *table,
if (new_key >= new_key_end)
{
/* Key not found. Add the offset of the key to the drop buffer. */
- index_drop_buffer[(*index_drop_count)++]= table_key - table->key_info;
+ (*index_drop_buffer)[(*index_drop_count)++]= table_key - table->key_info;
DBUG_PRINT("info", ("index dropped: '%s'", table_key->name));
continue;
}
@@ -5236,8 +5253,8 @@ static uint compare_tables(TABLE *table,
index_changed:
/* Key modified. Add the offset of the key to both buffers. */
- index_drop_buffer[(*index_drop_count)++]= table_key - table->key_info;
- index_add_buffer[(*index_add_count)++]= new_key - key_info_buffer;
+ (*index_drop_buffer)[(*index_drop_count)++]= table_key - table->key_info;
+ (*index_add_buffer)[(*index_add_count)++]= new_key - *key_info_buffer;
key_part= new_key->key_part;
end= key_part + new_key->key_parts;
for(; key_part != end; key_part++)
@@ -5253,7 +5270,7 @@ static uint compare_tables(TABLE *table,
/*
Step through all keys of the new table and find matching old keys.
*/
- for (new_key= key_info_buffer; new_key < new_key_end; new_key++)
+ for (new_key= *key_info_buffer; new_key < new_key_end; new_key++)
{
/* Search an old key with the same name. */
for (table_key= table->key_info; table_key < table_key_end; table_key++)
@@ -5264,7 +5281,7 @@ static uint compare_tables(TABLE *table,
if (table_key >= table_key_end)
{
/* Key not found. Add the offset of the key to the add buffer. */
- index_add_buffer[(*index_add_count)++]= new_key - key_info_buffer;
+ (*index_add_buffer)[(*index_add_count)++]= new_key - *key_info_buffer;
key_part= new_key->key_part;
end= key_part + new_key->key_parts;
for(; key_part != end; key_part++)
@@ -5344,10 +5361,8 @@ bool alter_table_manage_keys(TABLE *tabl
thd Thread handle
new_db If there is a RENAME clause
new_name If there is a RENAME clause
- lex_create_info Information from the parsing phase. Since some
- clauses are common to CREATE and ALTER TABLE, the
- data is stored in lex->create_info. The non-common
- is stored in lex->alter_info.
+ create_info Information from the parsing phase. Since some
+ clauses are common to CREATE and ALTER TABLE,
table_list The table to change.
fields lex->create_list - List of fields to be changed,
added or dropped.
@@ -5358,7 +5373,6 @@ bool alter_table_manage_keys(TABLE *tabl
ignore Whether we have ALTER IGNORE TABLE
alter_info Information from the parsing phase specific to ALTER
TABLE and not shared with CREATE TABLE.
- do_send_ok Whether to call send_ok() on success.
DESCRIPTION
This is a veery long function and is everything but the kitchen sink :)
@@ -5386,11 +5400,11 @@ bool alter_table_manage_keys(TABLE *tabl
*/
bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
- HA_CREATE_INFO *lex_create_info,
+ HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
List<create_field> &fields, List<Key> &keys,
uint order_num, ORDER *order, bool ignore,
- ALTER_INFO *alter_info, bool do_send_ok)
+ Alter_info *alter_info)
{
TABLE *table, *new_table= 0, *name_lock= 0;
int error= 0;
@@ -5403,7 +5417,6 @@ bool mysql_alter_table(THD *thd,char *ne
uint db_create_options, used_fields;
handlerton *old_db_type, *new_db_type, *save_old_db_type;
legacy_db_type table_type;
- HA_CREATE_INFO *create_info;
frm_type_enum frm_type;
uint need_copy_table= 0;
bool no_table_reopen= FALSE, varchar= FALSE;
@@ -5411,11 +5424,7 @@ bool mysql_alter_table(THD *thd,char *ne
uint fast_alter_partition= 0;
bool partition_changed= FALSE;
#endif
- List<create_field> prepared_create_list;
- List<Key> prepared_key_list;
bool need_lock_for_indexes= TRUE;
- uint db_options= 0;
- uint key_count;
KEY *key_info_buffer;
uint index_drop_count;
uint *index_drop_buffer;
@@ -5429,6 +5438,12 @@ bool mysql_alter_table(THD *thd,char *ne
LINT_INIT(index_add_buffer);
LINT_INIT(index_drop_buffer);
+ /*
+ Check if we attempt to alter mysql.slow_log or
+ mysql.general_log table and apply restrictions
+ on these tables if it's the case
+ TODO: this design is obsolete and will be removed.
+ */
if (table_list && table_list->db && table_list->table_name)
{
int table_kind= 0;
@@ -5446,20 +5461,21 @@ bool mysql_alter_table(THD *thd,char *ne
/* Disable alter of log tables to unsupported engine */
if (table_kind &&
- (lex_create_info->used_fields & HA_CREATE_USED_ENGINE) &&
- (!lex_create_info->db_type || /* unknown engine */
- !(lex_create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
+ (create_info->used_fields & HA_CREATE_USED_ENGINE) &&
+ (!create_info->db_type || /* unknown engine */
+ !(create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
{
my_error(ER_UNSUPORTED_LOG_ENGINE, MYF(0));
DBUG_RETURN(TRUE);
}
}
+ /*
+ Assign variables table_name, new_name, db, new_db, path, reg_path
+ to simplify further comparisions: we want to see if it's a rename
+ later just by comparing the pointers, without strcmp.
+ */
thd->proc_info="init";
- if (!(create_info= copy_create_info(lex_create_info)))
- {
- DBUG_RETURN(TRUE);
- }
table_name=table_list->table_name;
alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
db=table_list->db;
@@ -5482,8 +5498,17 @@ bool mysql_alter_table(THD *thd,char *ne
(void) unpack_filename(new_name_buff, new_name_buff);
if (lower_case_table_names != 2)
my_casedn_str(files_charset_info, new_name_buff);
+
+ /*
+ If this is just a rename of a view, short cut to the
+ following scenario: 1) lock LOCK_open 2) move do a rename
+ 2) unlock LOCK_open
+ This is a copy-paste from mysql_rename_table to make sure
+ ALTER TABLE .. RENAME works for views.
+ !!! This code is WRONG and must be REMOVED: !!!
+ */
frm_type= mysql_frm_type(thd, new_name_buff, &table_type);
- /* Rename a view */
+ /* Sic: a race here, frm type might have changed. */
if (frm_type == FRMTYPE_VIEW && !(alter_info->flags & ~ALTER_RENAME))
{
/*
@@ -5745,8 +5770,7 @@ view_err:
if (!error)
{
write_bin_log(thd, TRUE, thd->query, thd->query_length);
- if (do_send_ok)
- send_ok(thd);
+ send_ok(thd);
}
else if (error > 0)
{
@@ -6075,50 +6099,6 @@ view_err:
set_table_default_charset(thd, create_info, db);
- {
- /*
- For some purposes we need prepared table structures and translated
- key descriptions with proper default key name assignment.
-
- Unfortunately, mysql_prepare_table() modifies the field and key
- lists. mysql_create_table() needs the unmodified lists. Hence, we
- need to copy the lists and all their elements. The lists contain
- pointers to the elements only.
-
- We cannot copy conditionally because the partition code always
- needs prepared lists and compare_tables() needs them and is almost
- always called.
- */
-
- /* Copy fields. */
- List_iterator<create_field> prep_field_it(create_list);
- create_field *prep_field;
- while ((prep_field= prep_field_it++))
- prepared_create_list.push_back(new create_field(*prep_field));
-
- /* Copy keys and key parts. */
- List_iterator<Key> prep_key_it(key_list);
- Key *prep_key;
- while ((prep_key= prep_key_it++))
- {
- List<key_part_spec> prep_columns;
- List_iterator<key_part_spec> prep_col_it(prep_key->columns);
- key_part_spec *prep_col;
-
- while ((prep_col= prep_col_it++))
- prep_columns.push_back(new key_part_spec(*prep_col));
- prepared_key_list.push_back(new Key(prep_key->type, prep_key->name,
- &prep_key->key_create_info,
- prep_key->generated, prep_columns));
- }
-
- /* Create the prepared information. */
- if (mysql_prepare_table(thd, create_info, &prepared_create_list,
- &prepared_key_list,
- (table->s->tmp_table != NO_TMP_TABLE), &db_options,
- table->file, &key_info_buffer, &key_count, 0))
- goto err;
- }
if (thd->variables.old_alter_table
|| (table->s->db_type() != create_info->db_type)
@@ -6129,18 +6109,12 @@ view_err:
need_copy_table= 1;
else
{
- /* Try to optimize ALTER TABLE. Allocate result buffers. */
- if (! (index_drop_buffer=
- (uint*) thd->alloc(sizeof(uint) * table->s->keys)) ||
- ! (index_add_buffer=
- (uint*) thd->alloc(sizeof(uint) * prepared_key_list.elements)))
- goto err;
/* Check how much the tables differ. */
- need_copy_table= compare_tables(table, &prepared_create_list,
- key_info_buffer, key_count,
+ need_copy_table= compare_tables(table, &create_list, &key_list,
create_info, alter_info, order_num,
- index_drop_buffer, &index_drop_count,
- index_add_buffer, &index_add_count,
+ &key_info_buffer,
+ &index_drop_buffer, &index_drop_count,
+ &index_add_buffer, &index_add_count,
varchar);
}
@@ -6326,7 +6300,7 @@ view_err:
tmp_disable_binlog(thd);
error= mysql_create_table_no_lock(thd, new_db, tmp_name,
create_info, create_list,
- key_list, 1, 0, 0);
+ key_list, 1, 0);
reenable_binlog(thd);
if (error)
goto err;
@@ -6399,26 +6373,6 @@ view_err:
table->file->prepare_for_alter();
if (index_add_count)
{
-#ifdef XXX_TO_BE_DONE_LATER_BY_WL3020_AND_WL1892
- if (! need_lock_for_indexes)
- {
- /* Downgrade the write lock. */
- mysql_lock_downgrade_write(thd, table, TL_WRITE_ALLOW_WRITE);
- }
-
- /* Create a new .frm file for crash recovery. */
- /* TODO: Must set INDEX_TO_BE_ADDED flags in the frm file. */
- VOID(pthread_mutex_lock(&LOCK_open));
- error= (mysql_create_frm(thd, reg_path, db, table_name,
- create_info, prepared_create_list, key_count,
- key_info_buffer, table->file) ||
- table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG,
- create_info));
- VOID(pthread_mutex_unlock(&LOCK_open));
- if (error)
- goto err1;
-#endif
-
/* The add_index() method takes an array of KEY structs. */
key_info= (KEY*) thd->alloc(sizeof(KEY) * index_add_count);
key= key_info;
@@ -6451,36 +6405,6 @@ view_err:
if (index_drop_count)
{
-#ifdef XXX_TO_BE_DONE_LATER_BY_WL3020_AND_WL1892
- /* Create a new .frm file for crash recovery. */
- /* TODO: Must set INDEX_IS_ADDED in the frm file. */
- /* TODO: Must set INDEX_TO_BE_DROPPED in the frm file. */
- VOID(pthread_mutex_lock(&LOCK_open));
- error= (mysql_create_frm(thd, reg_path, db, table_name,
- create_info, prepared_create_list, key_count,
- key_info_buffer, table->file) ||
- table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG,
- create_info));
- VOID(pthread_mutex_unlock(&LOCK_open));
- if (error)
- goto err1;
-
- if (! need_lock_for_indexes)
- {
- LOCK_PARAM_TYPE lpt;
-
- lpt.thd= thd;
- lpt.table= table;
- lpt.db= db;
- lpt.table_name= table_name;
- lpt.create_info= create_info;
- lpt.create_list= &create_list;
- lpt.key_count= key_count;
- lpt.key_info_buffer= key_info_buffer;
- abort_and_upgrade_lock(lpt);
- }
-#endif
-
/* The prepare_drop_index() method takes an array of key numbers. */
key_numbers= (uint*) thd->alloc(sizeof(uint) * index_drop_count);
keyno_p= key_numbers;
@@ -6500,27 +6424,6 @@ view_err:
goto err1;
}
-#ifdef XXX_TO_BE_DONE_LATER_BY_WL3020
- if (! need_lock_for_indexes)
- {
- /* Downgrade the lock again. */
- if (table->reginfo.lock_type == TL_WRITE_ALLOW_READ)
- {
- LOCK_PARAM_TYPE lpt;
-
- lpt.thd= thd;
- lpt.table= table;
- lpt.db= db;
- lpt.table_name= table_name;
- lpt.create_info= create_info;
- lpt.create_list= &create_list;
- lpt.key_count= key_count;
- lpt.key_info_buffer= key_info_buffer;
- close_open_tables_and_downgrade(lpt);
- }
- }
-#endif
-
/* Tell the handler to finally drop the indexes. */
if ((error= table->file->final_drop_index(table)))
{
@@ -6841,8 +6744,7 @@ end_temporary:
my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
(ulong) (copied + deleted), (ulong) deleted,
(ulong) thd->cuted_fields);
- if (do_send_ok)
- send_ok(thd,copied+deleted,0L,tmp_name);
+ send_ok(thd, copied + deleted, 0L, tmp_name);
thd->some_tables_deleted=0;
DBUG_RETURN(FALSE);
@@ -7071,31 +6973,27 @@ copy_data_between_tables(TABLE *from,TAB
mysql_recreate_table()
thd Thread handler
tables Tables to recreate
- do_send_ok If we should send_ok() or leave it to caller
RETURN
Like mysql_alter_table().
*/
-bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
- bool do_send_ok)
+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
{
DBUG_ENTER("mysql_recreate_table");
LEX *lex= thd->lex;
HA_CREATE_INFO create_info;
- lex->create_list.empty();
- lex->key_list.empty();
lex->col_list.empty();
lex->alter_info.reset();
- bzero((char*) &create_info,sizeof(create_info));
+ bzero((char*) &create_info, sizeof(create_info));
create_info.db_type= 0;
create_info.row_type=ROW_TYPE_NOT_USED;
create_info.default_table_charset=default_charset_info;
/* Force alter table to recreate table */
lex->alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
- table_list, lex->create_list,
- lex->key_list, 0, (ORDER *) 0,
- 0, &lex->alter_info, do_send_ok));
+ table_list, lex->alter_info.create_list,
+ lex->alter_info.key_list, 0, (ORDER *) 0,
+ 0, &lex->alter_info));
}
--- 1.569/sql/sql_yacc.yy 2007-05-15 18:03:52 +04:00
+++ 1.570/sql/sql_yacc.yy 2007-05-21 19:07:47 +04:00
@@ -491,7 +491,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
%pure_parser /* We have threads */
/*
- Currently there is 287 shift/reduce conflict. We should not introduce
+ Currently there is 286 shift/reduce conflict. We should not introduce
new conflicts any more.
*/
%expect 286
@@ -1569,8 +1569,7 @@ create:
TL_OPTION_UPDATING,
TL_WRITE))
MYSQL_YYABORT;
- lex->create_list.empty();
- lex->key_list.empty();
+ lex->alter_info.reset();
lex->col_list.empty();
lex->change=NullS;
bzero((char*) &lex->create_info,sizeof(lex->create_info));
@@ -1604,21 +1603,23 @@ create:
NULL,
TL_OPTION_UPDATING))
MYSQL_YYABORT;
- lex->create_list.empty();
- lex->key_list.empty();
+ lex->alter_info.reset();
+ lex->alter_info.flags= ALTER_ADD_INDEX;
lex->col_list.empty();
lex->change=NullS;
}
'(' key_list ')' key_options
{
LEX *lex=Lex;
+ Key *key;
if ($2 != Key::FULLTEXT && lex->key_create_info.parser_name.str)
{
my_parse_error(ER(ER_SYNTAX_ERROR));
MYSQL_YYABORT;
}
- lex->key_list.push_back(new Key($2, $4.str, &lex->key_create_info, 0,
- lex->col_list));
+ key= new Key($2, $4.str, &lex->key_create_info, 0,
+ lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty();
}
| CREATE DATABASE opt_if_not_exists ident
@@ -4491,8 +4492,9 @@ key_def:
my_parse_error(ER(ER_SYNTAX_ERROR));
MYSQL_YYABORT;
}
- lex->key_list.push_back(new Key($1,$2, &lex->key_create_info, 0,
- lex->col_list));
+ Key *key= new Key($1, $2, &lex->key_create_info, 0,
+ lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint constraint_key_type opt_ident key_alg
@@ -4500,24 +4502,27 @@ key_def:
{
LEX *lex=Lex;
const char *key_name= $3 ? $3 : $1;
- lex->key_list.push_back(new Key($2, key_name, &lex->key_create_info, 0,
- lex->col_list));
+ Key *key= new Key($2, key_name, &lex->key_create_info, 0,
+ lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
{
LEX *lex=Lex;
- lex->key_list.push_back(new foreign_key($4 ? $4:$1, lex->col_list,
- $8,
- lex->ref_list,
- lex->fk_delete_opt,
- lex->fk_update_opt,
- lex->fk_match_option));
- lex->key_list.push_back(new Key(Key::MULTIPLE, $4 ? $4 : $1,
- &default_key_create_info, 1,
- lex->col_list));
+ const char *key_name= $4 ? $4 : $1;
+ Key *key= new foreign_key(key_name, lex->col_list,
+ $8,
+ lex->ref_list,
+ lex->fk_delete_opt,
+ lex->fk_update_opt,
+ lex->fk_match_option);
+ lex->alter_info.key_list.push_back(key);
+ key= new Key(Key::MULTIPLE, key_name,
+ &default_key_create_info, 1,
+ lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty(); /* Alloced by sql_alloc */
-
/* Only used for ALTER TABLE. Ignored otherwise. */
lex->alter_info.flags|= ALTER_FOREIGN_KEY;
}
@@ -5108,8 +5113,7 @@ alter:
if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
TL_OPTION_UPDATING))
MYSQL_YYABORT;
- lex->create_list.empty();
- lex->key_list.empty();
+ lex->alter_info.reset();
lex->col_list.empty();
lex->select_lex.init_order();
lex->like_name= 0;
@@ -5119,8 +5123,7 @@ alter:
lex->create_info.db_type= 0;
lex->create_info.default_table_charset= NULL;
lex->create_info.row_type= ROW_TYPE_NOT_USED;
- lex->alter_info.reset();
- lex->alter_info.flags= 0;
+ lex->alter_info.reset();
lex->no_write_to_binlog= 0;
lex->create_info.storage_media= HA_SM_DEFAULT;
}
@@ -8155,7 +8158,8 @@ drop:
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_DROP_INDEX;
- lex->alter_info.drop_list.empty();
+ lex->alter_info.reset();
+ lex->alter_info.flags= ALTER_DROP_INDEX;
lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str));
if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL,
--- 1.103/sql/sql_partition.cc 2007-05-15 17:44:39 +04:00
+++ 1.104/sql/sql_partition.cc 2007-05-21 19:07:47 +04:00
@@ -4130,7 +4130,7 @@ error:
change patterns.
*/
-uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
+uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
HA_CREATE_INFO *create_info,
handlerton *old_db_type,
bool *partition_changed,
@@ -6011,7 +6011,7 @@ void handle_alter_part_error(ALTER_PARTI
*/
uint fast_alter_partition_table(THD *thd, TABLE *table,
- ALTER_INFO *alter_info,
+ Alter_info *alter_info,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
List<create_field> *create_list,
@@ -6111,7 +6111,7 @@ uint fast_alter_partition_table(THD *thd
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
+ 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.
| Thread |
|---|
| • bk commit into 5.1 tree (kostja:1.2528) | konstantin | 21 May |