diff options
author | unknown <kostja@bodhi.local> | 2006-12-12 01:23:30 +0300 |
---|---|---|
committer | unknown <kostja@bodhi.local> | 2006-12-12 01:23:30 +0300 |
commit | 3e3990433a0c8ec7cea01274909fdb17024519e8 (patch) | |
tree | 3a662cb0552120a80c60d29abb3b2f97c9d177b2 /sql | |
parent | fe84b016e1fd62d92c9f13a1e21784ea8cb200cd (diff) | |
parent | e47ded8114f0b692a2ecf010998edcad46e6c2b3 (diff) | |
download | mariadb-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.h | 16 | ||||
-rw-r--r-- | sql/sql_class.h | 21 | ||||
-rw-r--r-- | sql/sql_insert.cc | 2 | ||||
-rw-r--r-- | sql/sql_lex.cc | 12 | ||||
-rw-r--r-- | sql/sql_lex.h | 54 | ||||
-rw-r--r-- | sql/sql_list.h | 68 | ||||
-rw-r--r-- | sql/sql_parse.cc | 209 | ||||
-rw-r--r-- | sql/sql_show.cc | 2 | ||||
-rw-r--r-- | sql/sql_table.cc | 159 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 47 |
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, |