summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <kostja@bodhi.local>2006-12-12 01:23:30 +0300
committerunknown <kostja@bodhi.local>2006-12-12 01:23:30 +0300
commit3e3990433a0c8ec7cea01274909fdb17024519e8 (patch)
tree3a662cb0552120a80c60d29abb3b2f97c9d177b2 /sql
parentfe84b016e1fd62d92c9f13a1e21784ea8cb200cd (diff)
parente47ded8114f0b692a2ecf010998edcad46e6c2b3 (diff)
downloadmariadb-git-3e3990433a0c8ec7cea01274909fdb17024519e8.tar.gz
Merge bodhi.local:/opt/local/work/mysql-4.1-4968
into bodhi.local:/opt/local/work/mysql-5.0-4968-pull-from-4.1 sql/sql_insert.cc: Auto merged mysql-test/r/ps.result: Manual merge. mysql-test/t/ps.test: Manual merge. sql/mysql_priv.h: Manual merge. sql/sql_class.h: Manual merge. sql/sql_lex.cc: Manual merge. sql/sql_lex.h: Manual merge. sql/sql_list.h: Manual merge. sql/sql_parse.cc: Manual merge. sql/sql_show.cc: Manual merge. sql/sql_table.cc: Manual merge. sql/sql_yacc.yy: Manual merge.
Diffstat (limited to 'sql')
-rw-r--r--sql/mysql_priv.h16
-rw-r--r--sql/sql_class.h21
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_lex.cc12
-rw-r--r--sql/sql_lex.h54
-rw-r--r--sql/sql_list.h68
-rw-r--r--sql/sql_parse.cc209
-rw-r--r--sql/sql_show.cc2
-rw-r--r--sql/sql_table.cc159
-rw-r--r--sql/sql_yacc.yy47
10 files changed, 362 insertions, 228 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a63b714e0b0..3f208a0b3bf 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -774,17 +774,15 @@ int prepare_create_field(create_field *sql_field,
uint table_flags);
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,
+ Alter_info *alter_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,
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);
-bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
+ Alter_info *alter_info,
+ uint order_num, ORDER *order, bool ignore);
+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);
@@ -793,9 +791,6 @@ bool mysql_rename_table(enum db_type base,
const char * old_name,
const char *new_db,
const char * new_name);
-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);
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,
@@ -897,7 +892,8 @@ int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
-bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
+bool mysqld_show_create_db(THD *thd, char *dbname,
+ const HA_CREATE_INFO *create);
void mysqld_list_processes(THD *thd,const char *user,bool verbose);
int mysqld_show_status(THD *thd);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index ec03b9cb4a6..f8da7facdca 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1840,21 +1840,22 @@ class select_insert :public select_result_interceptor {
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;
MYSQL_LOCK *lock;
Field **field;
public:
- select_create (TABLE_LIST *table,
- 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),
- extra_fields(&fields_par),keys(&keys_par), create_info(create_info_par),
+ select_create(TABLE_LIST *table,
+ 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),
+ create_info(create_info_arg),
+ alter_info(alter_info_arg),
lock(0)
- {}
+ {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
void store_values(List<Item> &values);
void send_error(uint errcode,const char *err);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 2ce83caa369..79e91dc4cb1 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2764,7 +2764,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
unit= u;
table= create_table_from_items(thd, create_info, create_table,
- extra_fields, keys, &values, &lock);
+ alter_info, &values, &lock);
if (!table)
DBUG_RETURN(-1); // abort() deletes table
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 3de842c8551..e063db58488 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1055,6 +1055,18 @@ 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),
+ is_simple(rhs.is_simple)
+{}
+
+
/*
Skip comment in the end of statement.
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 5f968252cc3..bca1d5e1ba9 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -688,18 +688,58 @@ typedef class st_select_lex SELECT_LEX;
#define ALTER_CONVERT 1024
#define ALTER_FORCE 2048
-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;
- st_alter_info(){clear();}
- void clear(){keys_onoff= LEAVE_AS_IS;tablespace_op= NO_TABLESPACE_OP;}
- void reset(){drop_list.empty();alter_list.empty();clear();}
-} ALTER_INFO;
+ Alter_info() :
+ flags(0),
+ keys_onoff(LEAVE_AS_IS),
+ tablespace_op(NO_TABLESPACE_OP)
+ {}
+
+ 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;
+ }
+ /**
+ 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
{
@@ -885,8 +925,6 @@ typedef struct st_lex : public Query_tables_list
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;
@@ -979,7 +1017,7 @@ typedef struct st_lex : public Query_tables_list
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) */
/*
diff --git a/sql/sql_list.h b/sql/sql_list.h
index afad6d0f6ac..c1989590d2d 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -62,21 +62,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;
+ }
};
@@ -92,12 +95,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)
{
@@ -348,6 +396,8 @@ template <class T> class List :public base_list
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); }
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index fec7e5ab20d..aa69e3133fc 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2894,17 +2894,33 @@ 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 unsent_create_error;
+ }
if ((res= create_table_precheck(thd, select_tables, create_table)))
goto end_with_restore_list;
#ifndef HAVE_READLINK
- 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
@@ -2912,14 +2928,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
@@ -2980,14 +2996,16 @@ mysql_execute_command(THD *thd)
}
}
}
-
+ /*
+ select_create is currently not re-execution friendly and
+ needs to be created for every execution of a PS/SP.
+ */
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,
@@ -2996,23 +3014,19 @@ 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
{
/* regular create */
if (lex->name)
- res= mysql_create_like_table(thd, create_table, &lex->create_info,
+ res= mysql_create_like_table(thd, create_table, &create_info,
(Table_ident *)lex->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);
+ create_table->table_name, &create_info,
+ &alter_info, 0, 0);
}
if (!res)
send_ok(thd);
@@ -3024,16 +3038,48 @@ 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))
+ if (check_one_table_access(thd, INDEX_ACL, first_table))
goto error; /* purecov: inspected */
- thd->enable_slow_log= opt_log_slow_admin_statements;
if (end_active_trans(thd))
goto error;
- else
- 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= DB_TYPE_DEFAULT;
+ create_info.default_table_charset= thd->variables.collation_database;
+
+ res= mysql_alter_table(thd, first_table->db, first_table->real_name,
+ &create_info, first_table, &alter_info,
+ 0, (ORDER*)0, DUP_ERROR, 0);
+ break;
+ }
#ifdef HAVE_REPLICATION
case SQLCOM_SLAVE_START:
{
@@ -3074,6 +3120,17 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
{
ulong priv=0;
+ /*
+ 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);
+ Alter_info alter_info(lex->alter_info, thd->mem_root);
+
+ if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
+ goto error;
if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name);
@@ -3088,7 +3145,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)
{
@@ -3107,13 +3164,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;
@@ -3127,13 +3184,13 @@ end_with_restore_list:
}
thd->enable_slow_log= opt_log_slow_admin_statements;
- res= mysql_alter_table(thd, select_lex->db, lex->name,
- &lex->create_info,
- first_table, lex->create_list,
- lex->key_list,
- select_lex->order_list.elements,
+ res= mysql_alter_table(thd, select_lex->db, lex->name,
+ &create_info,
+ first_table,
+ &alter_info,
+ select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
- lex->ignore, &lex->alter_info, 1);
+ lex->ignore);
}
break;
}
@@ -3286,7 +3343,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)
@@ -3602,15 +3659,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;
- else
- 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))
@@ -3739,6 +3787,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;
@@ -3769,7 +3823,7 @@ end_with_restore_list:
if (check_access(thd,CREATE_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
break;
res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name),
- &lex->create_info, 0);
+ &create_info, 0);
break;
}
case SQLCOM_DROP_DB:
@@ -5916,15 +5970,17 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
if (type_modifier & PRI_KEY_FLAG)
{
lex->col_list.push_back(new key_part_spec(field_name,0));
- lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
- 0, lex->col_list));
+ lex->alter_info.key_list.push_back(new Key(Key::PRIMARY, NullS,
+ HA_KEY_ALG_UNDEF, 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,0));
- lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF, 0,
- lex->col_list));
+ lex->alter_info.key_list.push_back(new Key(Key::UNIQUE, NullS,
+ HA_KEY_ALG_UNDEF, 0,
+ lex->col_list));
lex->col_list.empty();
}
@@ -5987,7 +6043,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
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);
}
@@ -7013,53 +7069,6 @@ Item * all_any_subquery_creator(Item *left_expr,
/*
- 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=DB_TYPE_DEFAULT;
- create_info.default_table_charset= thd->variables.collation_database;
- 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=DB_TYPE_DEFAULT;
- create_info.default_table_charset= thd->variables.collation_database;
- 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
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 1d524418480..bf58c1fa2ce 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -461,7 +461,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
}
bool mysqld_show_create_db(THD *thd, char *dbname,
- HA_CREATE_INFO *create_info)
+ const HA_CREATE_INFO *create_info)
{
Security_context *sctx= thd->security_ctx;
int length;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index c14529f6eb1..56691821ce1 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -644,8 +644,7 @@ int prepare_create_field(create_field *sql_field,
mysql_prepare_table()
thd Thread object
create_info Create information (like MAX_ROWS)
- fields List of fields to create
- keys List of keys to create
+ alter_info List of columns and indexes to create
DESCRIPTION
Prepares the table and key structures for table creation.
@@ -659,8 +658,8 @@ int prepare_create_field(create_field *sql_field,
*/
static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
- List<create_field> *fields,
- List<Key> *keys, bool tmp_table,
+ Alter_info *alter_info,
+ bool tmp_table,
uint *db_options,
handler *file, KEY **key_info_buffer,
uint *key_count, int select_field_count)
@@ -674,11 +673,12 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
int timestamps= 0, timestamps_with_niladic= 0;
int field_no,dup_no;
int select_field_pos,auto_increment=0;
- List_iterator<create_field> it(*fields),it2(*fields);
+ List_iterator<create_field> it(alter_info->create_list);
+ List_iterator<create_field> it2(alter_info->create_list);
uint total_uneven_bit_length= 0;
DBUG_ENTER("mysql_prepare_table");
- select_field_pos= fields->elements - select_field_count;
+ select_field_pos= alter_info->create_list.elements - select_field_count;
null_fields=blob_columns=0;
create_info->varchar= 0;
max_key_length= file->max_key_length();
@@ -1003,7 +1003,8 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
/* Create keys */
- List_iterator<Key> key_iterator(*keys), key_iterator2(*keys);
+ List_iterator<Key> key_iterator(alter_info->key_list);
+ List_iterator<Key> key_iterator2(alter_info->key_list);
uint key_parts=0, fk_key_count=0;
bool primary_key=0,unique_key=0;
Key *key, *key2;
@@ -1562,14 +1563,13 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field)
SYNOPSIS
mysql_create_table()
- thd Thread object
- db Database
- table_name Table name
- 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)
+ thd Thread object
+ db Database
+ table_name Table name
+ create_info [in/out] Create information (like MAX_ROWS)
+ alter_info [in/out] List of columns and indexes to create
+ internal_tmp_table Set to 1 if this is an internal temporary table
+ (From ALTER TABLE)
DESCRIPTION
If one creates a temporary table, this is automatically opened
@@ -1579,6 +1579,11 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field)
select_field_count is also used for CREATE ... SELECT,
and must be zero for standard create of table.
+ Note that structures passed as 'create_info' and 'alter_info' parameters
+ may be modified by this function. It is responsibility of the caller to
+ make a copy of create_info in order to provide correct execution in
+ prepared statements/stored routines.
+
RETURN VALUES
FALSE OK
TRUE error
@@ -1586,7 +1591,7 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field)
bool mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
- List<create_field> &fields,
+ Alter_info *alter_info,
List<Key> &keys,bool internal_tmp_table,
uint select_field_count)
{
@@ -1599,7 +1604,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_ENTER("mysql_create_table");
/* Check for duplicate fields and check type of table to create */
- if (!fields.elements)
+ if (!alter_info->create_list.elements)
{
my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
MYF(0));
@@ -1643,10 +1648,10 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
create_info->default_table_charset= db_info.default_table_charset;
}
- if (mysql_prepare_table(thd, create_info, &fields,
- &keys, internal_tmp_table, &db_options, file,
- &key_info_buffer, &key_count,
- select_field_count))
+ if (mysql_prepare_table(thd, create_info, alter_info, internal_tmp_table,
+ &db_options, file,
+ &key_info_buffer, &key_count,
+ select_field_count))
DBUG_RETURN(TRUE);
/* Check if table exists */
@@ -1736,8 +1741,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
create_info->table_options=db_options;
if (rea_create_table(thd, path, db, table_name,
- create_info, fields, key_count,
- key_info_buffer))
+ create_info, alter_info->create_list,
+ key_count, key_info_buffer))
goto end;
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
@@ -2403,6 +2408,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,
@@ -2413,7 +2419,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);
close_thread_tables(thd);
if (!result_code) // recreation went ok
@@ -2935,14 +2943,21 @@ err:
/*
Alter table
+
+
+ NOTE
+ The structures passed as 'create_info' and 'alter_info' parameters may
+ be modified by this function. It is responsibility of the caller to make
+ a copy of create_info in order to provide correct execution in prepared
+ statements/stored routines.
*/
bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
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,
+ uint order_num, ORDER *order,
+ bool ignore)
{
TABLE *table,*new_table=0;
int error;
@@ -3158,8 +3173,7 @@ view_err:
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
- if (do_send_ok)
- send_ok(thd);
+ send_ok(thd);
}
else if (error > 0)
{
@@ -3186,10 +3200,9 @@ view_err:
restore_record(table, s->default_values); // Empty record for DEFAULT
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
- List_iterator<create_field> def_it(fields);
+ List_iterator<create_field> def_it(alter_info->create_list);
List_iterator<Alter_column> alter_it(alter_info->alter_list);
- List<create_field> create_list; // Add new fields here
- List<Key> key_list; // Add new keys here
+ Alter_info new_info; // Add new columns and indexes here
create_field *def;
/*
@@ -3237,13 +3250,13 @@ view_err:
def->field=field;
if (!def->after)
{
- create_list.push_back(def);
+ new_info.create_list.push_back(def);
def_it.remove();
}
}
else
{ // Use old field value
- create_list.push_back(def=new create_field(field,field));
+ new_info.create_list.push_back(def= new create_field(field, field));
alter_it.rewind(); // Change default if ALTER
Alter_column *alter;
while ((alter=alter_it++))
@@ -3267,7 +3280,7 @@ view_err:
}
}
def_it.rewind();
- List_iterator<create_field> find_it(create_list);
+ List_iterator<create_field> find_it(new_info.create_list);
while ((def=def_it++)) // Add new columns
{
if (def->change && ! def->field)
@@ -3276,9 +3289,9 @@ view_err:
DBUG_RETURN(TRUE);
}
if (!def->after)
- create_list.push_back(def);
+ new_info.create_list.push_back(def);
else if (def->after == first_keyword)
- create_list.push_front(def);
+ new_info.create_list.push_front(def);
else
{
create_field *find;
@@ -3302,7 +3315,7 @@ view_err:
alter_info->alter_list.head()->name, table_name);
DBUG_RETURN(TRUE);
}
- if (!create_list.elements)
+ if (!new_info.create_list.elements)
{
my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
MYF(0));
@@ -3314,8 +3327,8 @@ view_err:
for which some fields exists.
*/
- List_iterator<Key> key_it(keys);
- List_iterator<create_field> field_it(create_list);
+ List_iterator<Key> key_it(alter_info->key_list);
+ List_iterator<create_field> field_it(new_info.create_list);
List<key_part_spec> key_parts;
KEY *key_info=table->key_info;
@@ -3387,24 +3400,37 @@ view_err:
key_part_length));
}
if (key_parts.elements)
- key_list.push_back(new Key(key_info->flags & HA_SPATIAL ? Key::SPATIAL :
- (key_info->flags & HA_NOSAME ?
- (!my_strcasecmp(system_charset_info,
- key_name, primary_key_name) ?
- Key::PRIMARY : Key::UNIQUE) :
- (key_info->flags & HA_FULLTEXT ?
- Key::FULLTEXT : Key::MULTIPLE)),
- key_name,
- key_info->algorithm,
- test(key_info->flags & HA_GENERATED_KEY),
- key_parts));
+ {
+ Key *key;
+ enum Key::Keytype key_type;
+
+ if (key_info->flags & HA_SPATIAL)
+ key_type= Key::SPATIAL;
+ else if (key_info->flags & HA_NOSAME)
+ {
+ if (! my_strcasecmp(system_charset_info, key_name, primary_key_name))
+ key_type= Key::PRIMARY;
+ else
+ key_type= Key::UNIQUE;
+ }
+ else if (key_info->flags & HA_FULLTEXT)
+ key_type= Key::FULLTEXT;
+ else
+ key_type= Key::MULTIPLE;
+
+ key= new Key(key_type, key_name,
+ key_info->algorithm,
+ test(key_info->flags & HA_GENERATED_KEY),
+ key_parts);
+ new_info.key_list.push_back(key);
+ }
}
{
Key *key;
while ((key=key_it++)) // Add new keys
{
if (key->type != Key::FOREIGN_KEY)
- key_list.push_back(key);
+ new_info.key_list.push_back(key);
if (key->name &&
!my_strcasecmp(system_charset_info,key->name,primary_key_name))
{
@@ -3539,7 +3565,7 @@ view_err:
{
tmp_disable_binlog(thd);
error= mysql_create_table(thd, new_db, tmp_name,
- create_info,create_list,key_list,1,0);
+ create_info,alter_info, 1, 0);
reenable_binlog(thd);
if (error)
DBUG_RETURN(error);
@@ -3580,8 +3606,9 @@ view_err:
{
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
new_table->next_number_field=new_table->found_next_number_field;
- error=copy_data_between_tables(table, new_table, create_list, ignore,
- order_num, order, &copied, &deleted);
+ error= copy_data_between_tables(table, new_table, new_info.create_list,
+ ignore, order_num, order, &copied,
+ &deleted);
}
thd->last_insert_id=next_insert_id; // Needed for correct log
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -3794,8 +3821,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);
@@ -3990,21 +4016,19 @@ copy_data_between_tables(TABLE *from,TABLE *to,
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)
+int 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();
+ Alter_info alter_info;
+
+ DBUG_ENTER("mysql_recreate_table");
+
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
create_info.row_type=ROW_TYPE_NOT_USED;
@@ -4012,9 +4036,8 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
/* Force alter table to recreate table */
lex->alter_info.flags= ALTER_CHANGE_COLUMN;
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, &alter_info,
+ 0, (ORDER *) 0, 0));
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 2d315e91f52..719d48af33f 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1171,8 +1171,7 @@ create:
TL_READ_NO_INSERT:
TL_READ)))
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));
@@ -1190,16 +1189,18 @@ create:
if (!lex->current_select->add_table_to_list(lex->thd, $7, NULL,
TL_OPTION_UPDATING))
YYABORT;
- lex->create_list.empty();
- lex->key_list.empty();
+ lex->alter_info.reset();
+ lex->alter_info.is_simple= 0;
+ lex->alter_info.flags= ALTER_ADD_INDEX;
lex->col_list.empty();
lex->change=NullS;
}
'(' key_list ')'
{
LEX *lex=Lex;
+ Key *key= new Key($2, $4.str, $5, 0, lex->col_list);
- lex->key_list.push_back(new Key($2,$4.str, $5, 0, lex->col_list));
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty();
}
| CREATE DATABASE opt_if_not_exists ident
@@ -2734,29 +2735,34 @@ key_def:
key_type opt_ident key_alg '(' key_list ')'
{
LEX *lex=Lex;
- lex->key_list.push_back(new Key($1,$2, $3, 0, lex->col_list));
+ Key *key= new Key($1, $2, $3, 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 '(' key_list ')'
{
LEX *lex=Lex;
const char *key_name= $3 ? $3:$1;
- lex->key_list.push_back(new Key($2, key_name, $4, 0,
- lex->col_list));
+ Key *key= new Key($2, key_name, $4, 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,
- HA_KEY_ALG_UNDEF, 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,
+ HA_KEY_ALG_UNDEF, 1,
+ lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| constraint opt_check_constraint
@@ -3298,8 +3304,6 @@ alter:
if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
TL_OPTION_UPDATING))
YYABORT;
- lex->create_list.empty();
- lex->key_list.empty();
lex->col_list.empty();
lex->select_lex.init_order();
lex->select_lex.db=
@@ -3310,7 +3314,6 @@ alter:
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;
}
alter_list
{}
@@ -6072,7 +6075,9 @@ drop:
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_DROP_INDEX;
- lex->alter_info.drop_list.empty();
+ lex->alter_info.reset();
+ lex->alter_info.is_simple= 0;
+ 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,