diff options
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r-- | sql/sql_table.cc | 195 |
1 files changed, 170 insertions, 25 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 49e84db62c9..291976fe154 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -46,7 +46,8 @@ static int copy_data_between_tables(TABLE *from,TABLE *to, ** This will wait for all users to free the table before dropping it *****************************************************************************/ -int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) +int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, + my_bool drop_temporary) { int error; DBUG_ENTER("mysql_rm_table"); @@ -57,7 +58,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) thd->mysys_var->current_cond= &COND_refresh; VOID(pthread_mutex_lock(&LOCK_open)); - if (global_read_lock) + if (!drop_temporary && global_read_lock) { if (thd->global_read_lock) { @@ -72,7 +73,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) } } - error=mysql_rm_table_part2(thd,tables,if_exists,0); + error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary, 0); err: pthread_mutex_unlock(&LOCK_open); @@ -91,14 +92,15 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, bool if_exists, - bool dont_log_query) + bool drop_temporary, bool dont_log_query) { int error; thd->mysys_var->current_mutex= &LOCK_open; thd->mysys_var->current_cond= &COND_refresh; VOID(pthread_mutex_lock(&LOCK_open)); - error=mysql_rm_table_part2(thd,tables, if_exists, dont_log_query); + error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary, + dont_log_query); pthread_mutex_unlock(&LOCK_open); VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh @@ -111,6 +113,17 @@ int mysql_rm_table_part2_with_lock(THD *thd, } /* + Execute the drop of a normal or temporary table + + SYNOPSIS + mysql_rm_table_part2() + thd Thread handler + tables Tables to drop + if_exists If set, don't give an error if table doesn't exists. + In this case we give an warning of level 'NOTE' + drop_temporary Only drop temporary tables + dont_log_query Don't log the query + TODO: When logging to the binary log, we should log tmp_tables and transactional tables as separate statements if we @@ -120,10 +133,15 @@ int mysql_rm_table_part2_with_lock(THD *thd, The current code only writes DROP statements that only uses temporary tables to the cache binary log. This should be ok on most cases, but not all. + + RETURN + 0 ok + 1 Error + -1 Thread was killed */ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, - bool dont_log_query) + bool drop_temporary, bool dont_log_query) { TABLE_LIST *table; char path[FN_REFLEN]; @@ -142,29 +160,33 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, continue; // removed temporary table } - abort_locked_tables(thd,db,table->real_name); - while (remove_table_from_cache(thd,db,table->real_name) && !thd->killed) - { - dropping_tables++; - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - dropping_tables--; - } - drop_locked_tables(thd,db,table->real_name); - if (thd->killed) - DBUG_RETURN(-1); - - /* remove form file and isam files */ - strxmov(path, mysql_data_home, "/", db, "/", table->real_name, reg_ext, - NullS); - (void) unpack_filename(path,path); error=0; + if (!drop_temporary) + { + abort_locked_tables(thd,db,table->real_name); + while (remove_table_from_cache(thd,db,table->real_name) && !thd->killed) + { + dropping_tables++; + (void) pthread_cond_wait(&COND_refresh,&LOCK_open); + dropping_tables--; + } + drop_locked_tables(thd,db,table->real_name); + if (thd->killed) + DBUG_RETURN(-1); - table_type=get_table_type(path); + /* remove form file and isam files */ + strxmov(path, mysql_data_home, "/", db, "/", table->real_name, reg_ext, + NullS); + (void) unpack_filename(path,path); - if (access(path,F_OK)) + table_type=get_table_type(path); + } + if (drop_temporary || access(path,F_OK)) { if (if_exists) - store_warning(thd, ER_BAD_TABLE_ERROR, table->real_name); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), + table->real_name); else error= 1; } @@ -190,6 +212,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, wrong_tables.append(String(table->real_name,default_charset_info)); } } + thd->lex.tmp_table_used= tmp_table_deleted; if (some_tables_deleted || tmp_table_deleted) { query_cache_invalidate3(thd, tables, 0); @@ -398,7 +421,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, it.rewind(); while ((sql_field=it++)) { - if(!sql_field->charset) + if (!sql_field->charset) sql_field->charset = create_info->table_charset ? create_info->table_charset : thd->db_charset? thd->db_charset : @@ -824,6 +847,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, (void) rm_temporary_table(create_info->db_type, path); goto end; } + thd->lex.tmp_table_used= 1; } if (!tmp_table && !no_log) { @@ -1392,6 +1416,127 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) } +/* + Create a table identical to the specified table + + SYNOPSIS + mysql_create_like_table() + thd Thread object + table Table list (one table only) + create_info Create info + table_ident Src table_ident + + RETURN VALUES + 0 ok + -1 error +*/ + +int mysql_create_like_table(THD* thd, TABLE_LIST* table, + HA_CREATE_INFO *create_info, + Table_ident *table_ident) +{ + TABLE **tmp_table; + char src_path[FN_REFLEN], dst_path[FN_REFLEN]; + char *db= table->db; + char *table_name= table->real_name; + char *src_db= thd->db; + char *src_table= table_ident->table.str; + int err; + + DBUG_ENTER("mysql_create_like_table"); + + /* + Validate the source table + */ + if (table_ident->table.length > NAME_LEN || + (table_ident->table.length && + check_table_name(src_table,table_ident->table.length)) || + table_ident->db.str && check_db_name((src_db= table_ident->db.str))) + { + my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table); + DBUG_RETURN(-1); + } + + if ((tmp_table= find_temporary_table(thd, src_db, src_table))) + strxmov(src_path, (*tmp_table)->path, reg_ext, NullS); + else + { + strxmov(src_path, mysql_data_home, "/", src_db, "/", src_table, + reg_ext, NullS); + if (access(src_path, F_OK)) + { + my_error(ER_BAD_TABLE_ERROR, MYF(0), src_table); + DBUG_RETURN(-1); + } + } + + /* + Validate the destination table + + skip the destination table name checking as this is already + validated. + */ + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + { + if (find_temporary_table(thd, db, table_name)) + goto table_exists; + sprintf(dst_path,"%s%s%lx_%lx_%x%s",mysql_tmpdir,tmp_file_prefix, + current_pid, thd->thread_id, thd->tmp_table++,reg_ext); + create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE; + } + else + { + strxmov(dst_path, mysql_data_home, "/", db, "/", table_name, + reg_ext, NullS); + if (!access(dst_path, F_OK)) + goto table_exists; + } + + /* + Create a new table by copying from source table + */ + if (my_copy(src_path, dst_path, MYF(MY_WME))) + DBUG_RETURN(-1); + + /* + As mysql_truncate don't work on a new table at this stage of + creation, instead create the table directly (for both normal + and temporary tables). + */ + *fn_ext(dst_path)= 0; + err= ha_create_table(dst_path, create_info, 1); + + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + { + if (err || !open_temporary_table(thd, dst_path, db, table_name, 1)) + { + (void) rm_temporary_table(create_info->db_type, + dst_path); /* purecov: inspected */ + DBUG_RETURN(-1); /* purecov: inspected */ + } + } + else if (err) + { + (void) quick_rm_table(create_info->db_type, db, + table_name); /* purecov: inspected */ + DBUG_RETURN(-1); /* purecov: inspected */ + } + DBUG_RETURN(0); + +table_exists: + if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + char warn_buff[MYSQL_ERRMSG_SIZE]; + sprintf(warn_buff,ER(ER_TABLE_EXISTS_ERROR),table_name); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TABLE_EXISTS_ERROR,warn_buff); + DBUG_RETURN(0); + } + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); + DBUG_RETURN(-1); +} + + int mysql_analyze_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) { #ifdef OS2 |