diff options
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r-- | sql/sql_table.cc | 140 |
1 files changed, 120 insertions, 20 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a49b7a2cc42..d5d33373e6c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3002,6 +3002,31 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field) /* + 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 @@ -3009,11 +3034,15 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field) thd Thread object db Database table_name Table name - create_info Create information (like MAX_ROWS) + lex_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. DESCRIPTION If one creates a temporary table, this is automatically opened @@ -3030,20 +3059,32 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field) bool mysql_create_table_internal(THD *thd, const char *db, const char *table_name, - HA_CREATE_INFO *create_info, + HA_CREATE_INFO *lex_create_info, List<create_field> &fields, List<Key> &keys,bool internal_tmp_table, - uint select_field_count) + uint select_field_count, + bool use_copy_create_info) { 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_internal"); + 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) { @@ -3144,8 +3185,7 @@ bool mysql_create_table_internal(THD *thd, } DBUG_PRINT("info", ("db_type = %d", ha_legacy_type(part_info->default_engine_type))); - if (part_info->check_partition_info(&engine_type, file, - create_info->max_rows)) + if (part_info->check_partition_info(thd, &engine_type, file, create_info)) goto err; part_info->default_engine_type= engine_type; @@ -3183,7 +3223,8 @@ bool mysql_create_table_internal(THD *thd, */ if (part_info->use_default_no_partitions && part_info->no_parts && - (int)part_info->no_parts != file->get_default_no_partitions(0ULL)) + (int)part_info->no_parts != + file->get_default_no_partitions(create_info)) { uint i; List_iterator<partition_element> part_it(part_info->partitions); @@ -3196,10 +3237,10 @@ bool mysql_create_table_internal(THD *thd, part_info->use_default_no_subpartitions && part_info->no_subparts && (int)part_info->no_subparts != - file->get_default_no_partitions(0ULL)) + file->get_default_no_partitions(create_info)) { DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE); - part_info->no_subparts= file->get_default_no_partitions(0ULL); + part_info->no_subparts= file->get_default_no_partitions(create_info); } } else if (create_info->db_type != engine_type) @@ -3237,8 +3278,23 @@ bool mysql_create_table_internal(THD *thd, my_casedn_str(files_charset_info, path); create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE; } - else + else + { + #ifdef FN_DEVCHAR + /* check if the table name contains FN_DEVCHAR when defined */ + const char *start= alias; + while (*start != '\0') + { + if (*start == FN_DEVCHAR) + { + my_error(ER_WRONG_TABLE_NAME, MYF(0), alias); + DBUG_RETURN(TRUE); + } + start++; + } +#endif path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext); + } /* Check if table already exists */ if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) && @@ -3358,7 +3414,8 @@ 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 internal_tmp_table, - uint select_field_count) + uint select_field_count, + bool use_copy_create_info) { bool result; DBUG_ENTER("mysql_create_table"); @@ -3382,7 +3439,8 @@ bool mysql_create_table(THD *thd, const char *db, const char *table_name, result= mysql_create_table_internal(thd, db, table_name, create_info, fields, keys, internal_tmp_table, - select_field_count); + select_field_count, + use_copy_create_info); pthread_mutex_lock(&LOCK_lock_db); if (!--creating_table && creating_database) @@ -4328,7 +4386,7 @@ bool mysql_preload_keys(THD* thd, TABLE_LIST* tables) */ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, - HA_CREATE_INFO *create_info, + HA_CREATE_INFO *lex_create_info, Table_ident *table_ident) { TABLE *tmp_table; @@ -4341,9 +4399,15 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, int err; bool res= TRUE; enum legacy_db_type not_used; + HA_CREATE_INFO *create_info; TABLE_LIST src_tables_list; DBUG_ENTER("mysql_create_like_table"); + + if (!(create_info= copy_create_info(lex_create_info))) + { + DBUG_RETURN(TRUE); + } src_db= table_ident->db.str ? table_ident->db.str : thd->db; /* @@ -4709,6 +4773,14 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list, At the moment we can't handle altering temporary tables without a copy. We also test if OPTIMIZE TABLE was given and was mapped to alter table. In that case we always do full copy. + + There was a bug prior to mysql-4.0.25. Number of null fields was + calculated incorrectly. As a result frm and data files gets out of + sync after fast alter table. There is no way to determine by which + mysql version (in 4.0 and 4.1 branches) table was created, thus we + disable fast alter table for all tables created by mysql versions + prior to 5.0 branch. + See BUG#6236. */ if (table->s->fields != create_list->elements || table->s->db_type != create_info->db_type || @@ -4718,6 +4790,7 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list, create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET || (alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) || order_num || + !table->s->mysql_version || (table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar)) DBUG_RETURN(ALTER_TABLE_DATA_CHANGED); @@ -4744,6 +4817,13 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list, create_info->row_type != ROW_TYPE_FIXED) create_info->table_options|= HA_OPTION_PACK_RECORD; + /* Check if field was renamed */ + field->flags&= ~FIELD_IS_RENAMED; + if (my_strcasecmp(system_charset_info, + field->field_name, + new_field->field_name)) + field->flags|= FIELD_IS_RENAMED; + /* Evaluate changes bitmap and send to check_if_incompatible_data() */ if (!(tmp= field->is_equal(new_field))) DBUG_RETURN(ALTER_TABLE_DATA_CHANGED); @@ -4873,7 +4953,7 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list, */ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, - HA_CREATE_INFO *create_info, + HA_CREATE_INFO *lex_create_info, TABLE_LIST *table_list, List<create_field> &fields, List<Key> &keys, uint order_num, ORDER *order, @@ -4891,6 +4971,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ulonglong next_insert_id; uint db_create_options, used_fields; handlerton *old_db_type, *new_db_type; + HA_CREATE_INFO *create_info; uint need_copy_table= 0; bool no_table_reopen= FALSE, varchar= FALSE; #ifdef WITH_PARTITION_STORAGE_ENGINE @@ -4916,6 +4997,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, LINT_INIT(index_drop_buffer); 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; @@ -4992,7 +5077,24 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, old_db_type= table->s->db_type; if (!create_info->db_type) - create_info->db_type= old_db_type; + { +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (table->part_info && + create_info->used_fields & HA_CREATE_USED_ENGINE) + { + /* + This case happens when the user specified + ENGINE = x where x is a non-existing storage engine + We set create_info->db_type to default_engine_type + to ensure we don't change underlying engine type + due to a erroneously given engine name. + */ + create_info->db_type= table->part_info->default_engine_type; + } + else +#endif + create_info->db_type= old_db_type; + } #ifdef WITH_PARTITION_STORAGE_ENGINE if (prep_alter_part_table(thd, table, alter_info, create_info, old_db_type, @@ -5653,7 +5755,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, */ tmp_disable_binlog(thd); error= mysql_create_table(thd, new_db, tmp_name, - create_info,create_list,key_list,1,0); + create_info,create_list,key_list,1,0,0); reenable_binlog(thd); if (error) DBUG_RETURN(error); @@ -6235,12 +6337,10 @@ copy_data_between_tables(TABLE *from,TABLE *to, } if ((error=to->file->ha_write_row((byte*) to->record[0]))) { - if ((!ignore && - handle_duplicates != DUP_REPLACE) || - (error != HA_ERR_FOUND_DUPP_KEY && - error != HA_ERR_FOUND_DUPP_UNIQUE)) + if (!ignore || handle_duplicates != DUP_ERROR || + to->file->is_fatal_error(error, HA_CHECK_DUP)) { - if (error == HA_ERR_FOUND_DUPP_KEY) + if (!to->file->is_fatal_error(error, HA_CHECK_DUP)) { uint key_nr= to->file->get_dup_key(error); if ((int) key_nr >= 0) |