Merge c-4908e253.1238-1-64736c10.cust.bredbandsbolaget.se:/home/pappa/clean-mysql-5.1-new

into  c-4908e253.1238-1-64736c10.cust.bredbandsbolaget.se:/home/pappa/wl2826
parents 62e8932d 635b0a9d
......@@ -71,6 +71,7 @@ pentium_cflags="$check_cpu_cflags"
pentium64_cflags="$check_cpu_cflags -m64"
ppc_cflags="$check_cpu_cflags"
sparc_cflags=""
error_inject="--with-error-inject "
# be as fast as we can be without losing our ability to backtrace
fast_cflags="-O3 -fno-omit-frame-pointer"
......
......@@ -6,6 +6,6 @@ path=`dirname $0`
extra_flags="$pentium_cflags $debug_cflags $max_cflags"
c_warnings="$c_warnings $debug_extra_warnings"
cxx_warnings="$cxx_warnings $debug_extra_warnings"
extra_configs="$pentium_configs $debug_configs $max_configs"
extra_configs="$pentium_configs $debug_configs $max_configs $error_inject"
. "$path/FINISH.sh"
......@@ -666,6 +666,7 @@ else
AC_MSG_RESULT([no])
fi
MYSQL_SYS_LARGEFILE
# Types that must be checked AFTER large file support is checked
......@@ -1587,6 +1588,18 @@ then
DEBUG_OPTIMIZE_CXX=""
fi
# If we should allow error injection tests
AC_ARG_WITH(error-inject,
[ --with-error-inject Enable error injection in MySQL Server],
[ with_error_inject=$withval ],
[ with_error_inject=no ])
if test "$with_error_inject" = "yes"
then
CFLAGS="-DERROR_INJECT_SUPPORT $CFLAGS"
CXXFLAGS="-DERROR_INJECT_SUPPORT $CXXFLAGS"
fi
AC_ARG_WITH(debug,
[ --with-debug Add debug code
--with-debug=full Add debug code (adds memory checker, very slow)],
......
......@@ -559,7 +559,7 @@ extern File my_register_filename(File fd, const char *FileName,
enum file_type type_of_file,
uint error_message_number, myf MyFlags);
extern File my_create(const char *FileName,int CreateFlags,
int AccsesFlags, myf MyFlags);
int AccessFlags, myf MyFlags);
extern int my_close(File Filedes,myf MyFlags);
extern File my_dup(File file, myf MyFlags);
extern int my_mkdir(const char *dir, int Flags, myf MyFlags);
......
......@@ -165,6 +165,19 @@ ENGINE=NDB
PARTITION BY KEY(c3) PARTITIONS 5;
ALTER TABLE t1 COALESCE PARTITION 4;
DROP TABLE t1;
CREATE TABLE t1 (a int primary key)
ENGINE=NDB
PARTITION BY KEY(a);
ALTER TABLE t1 OPTIMIZE PARTITION p0;
ERROR HY000: Table storage engine for 't1' doesn't have this option
ALTER TABLE t1 CHECK PARTITION p0;
ERROR HY000: Table storage engine for 't1' doesn't have this option
ALTER TABLE t1 REPAIR PARTITION p0;
ERROR HY000: Table storage engine for 't1' doesn't have this option
ALTER TABLE t1 ANALYZE PARTITION p0;
ERROR HY000: Table storage engine for 't1' doesn't have this option
ALTER TABLE t1 REBUILD PARTITION p0;
ERROR HY000: Table storage engine for 't1' doesn't have this option
CREATE TABLE t1 (
c1 MEDIUMINT NOT NULL AUTO_INCREMENT,
c2 TEXT NOT NULL,
......
......@@ -154,6 +154,24 @@ ALTER TABLE t1 COALESCE PARTITION 4;
DROP TABLE t1;
#
# Bug 16822: OPTIMIZE TABLE hangs test
#
CREATE TABLE t1 (a int primary key)
ENGINE=NDB
PARTITION BY KEY(a);
--error 1031
ALTER TABLE t1 OPTIMIZE PARTITION p0;
--error 1031
ALTER TABLE t1 CHECK PARTITION p0;
--error 1031
ALTER TABLE t1 REPAIR PARTITION p0;
--error 1031
ALTER TABLE t1 ANALYZE PARTITION p0;
--error 1031
ALTER TABLE t1 REBUILD PARTITION p0;
DROP TABLE t1;
#
# BUG 16806: ALTER TABLE fails
#
......
......@@ -4687,7 +4687,9 @@ int ha_ndbcluster::create(const char *name,
DBUG_RETURN(my_errno);
}
int ha_ndbcluster::create_handler_files(const char *file)
int ha_ndbcluster::create_handler_files(const char *file,
const char *old_name,
bool rename_flag)
{
const char *name;
Ndb* ndb;
......@@ -4698,6 +4700,10 @@ int ha_ndbcluster::create_handler_files(const char *file)
DBUG_ENTER("create_handler_files");
if (rename_flag)
{
DBUG_RETURN(FALSE);
}
if (!(ndb= get_ndb()))
DBUG_RETURN(HA_ERR_NO_CONNECTION);
......
......@@ -611,7 +611,8 @@ class ha_ndbcluster: public handler
int rename_table(const char *from, const char *to);
int delete_table(const char *name);
int create(const char *name, TABLE *form, HA_CREATE_INFO *info);
int create_handler_files(const char *file);
int create_handler_files(const char *file, const char *old_name,
bool rename_flag);
int get_default_no_partitions(ulonglong max_rows);
bool get_no_parts(const char *name, uint *no_parts);
void set_auto_partitions(partition_info *part_info);
......
This diff is collapsed.
......@@ -179,7 +179,8 @@ class ha_partition :public handler
virtual int rename_table(const char *from, const char *to);
virtual int create(const char *name, TABLE *form,
HA_CREATE_INFO *create_info);
virtual int create_handler_files(const char *name);
virtual int create_handler_files(const char *name,
const char *old_name, bool rename_flag);
virtual void update_create_info(HA_CREATE_INFO *create_info);
virtual char *update_table_comment(const char *comment);
virtual int change_partitions(HA_CREATE_INFO *create_info,
......
......@@ -632,6 +632,7 @@ typedef struct {
#define UNDEF_NODEGROUP 65535
class Item;
struct st_table_log_memory_entry;
class partition_info;
......@@ -639,7 +640,6 @@ struct st_partition_iter;
#define NOT_A_PARTITION_ID ((uint32)-1)
typedef struct st_ha_create_information
{
CHARSET_INFO *table_charset, *default_table_charset;
......@@ -1378,7 +1378,11 @@ class handler :public Sql_alloc
virtual void drop_table(const char *name);
virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0;
virtual int create_handler_files(const char *name) { return FALSE;}
virtual int create_handler_files(const char *name, const char *old_name,
bool rename_flag)
{
return FALSE;
}
virtual int change_partitions(HA_CREATE_INFO *create_info,
const char *path,
......@@ -1386,7 +1390,7 @@ class handler :public Sql_alloc
ulonglong *deleted,
const void *pack_frm_data,
uint pack_frm_len)
{ return HA_ERR_WRONG_COMMAND; }
{ print_error(HA_ERR_WRONG_COMMAND, MYF(0)); return TRUE; }
virtual int drop_partitions(const char *path)
{ return HA_ERR_WRONG_COMMAND; }
virtual int rename_partitions(const char *path)
......
......@@ -617,6 +617,101 @@ struct Query_cache_query_flags
#define query_cache_invalidate_by_MyISAM_filename_ref NULL
#endif /*HAVE_QUERY_CACHE*/
/*
Error injector Macros to enable easy testing of recovery after failures
in various error cases.
*/
#ifndef ERROR_INJECT_SUPPORT
#define ERROR_INJECT(x) 0
#define ERROR_INJECT_ACTION(x,action) 0
#define ERROR_INJECT_CRASH(x) 0
#define ERROR_INJECT_VALUE(x) 0
#define ERROR_INJECT_VALUE_ACTION(x,action) 0
#define ERROR_INJECT_VALUE_CRASH(x) 0
#define SET_ERROR_INJECT_VALUE(x)
#else
inline bool
my_error_inject_name(const char *dbug_str)
{
const char *extra_str= "-d,";
char total_str[200];
if (_db_strict_keyword_ (dbug_str))
{
strxmov(total_str, extra_str, dbug_str, NullS);
DBUG_SET(total_str);
return 1;
}
return 0;
}
inline bool
my_error_inject(int value)
{
THD *thd= current_thd;
if (thd->error_inject_value == (uint)value)
{
thd->error_inject_value= 0;
return 1;
}
return 0;
}
/*
ERROR INJECT MODULE:
--------------------
These macros are used to insert macros from the application code.
The event that activates those error injections can be activated
from SQL by using:
SET SESSION dbug=+d,code;
After the error has been injected, the macros will automatically
remove the debug code, thus similar to using:
SET SESSION dbug=-d,code
from SQL.
ERROR_INJECT_CRASH will inject a crash of the MySQL Server if code
is set when macro is called. ERROR_INJECT_CRASH can be used in
if-statements, it will always return FALSE unless of course it
crashes in which case it doesn't return at all.
ERROR_INJECT_ACTION will inject the action specified in the action
parameter of the macro, before performing the action the code will
be removed such that no more events occur. ERROR_INJECT_ACTION
can also be used in if-statements and always returns FALSE.
ERROR_INJECT can be used in a normal if-statement, where the action
part is performed in the if-block. The macro returns TRUE if the
error was activated and otherwise returns FALSE. If activated the
code is removed.
Sometimes it is necessary to perform error inject actions as a serie
of events. In this case one can use one variable on the THD object.
Thus one sets this value by using e.g. SET_ERROR_INJECT_VALUE(100).
Then one can later test for it by using ERROR_INJECT_CRASH_VALUE,
ERROR_INJECT_ACTION_VALUE and ERROR_INJECT_VALUE. This have the same
behaviour as the above described macros except that they use the
error inject value instead of a code used by DBUG macros.
*/
#define SET_ERROR_INJECT_VALUE(x) \
current_thd->error_inject_value= (x)
#define ERROR_INJECT_CRASH(code) \
DBUG_EVALUATE_IF(code, (abort(), 0), 0)
#define ERROR_INJECT_ACTION(code, action) \
(my_error_inject_name(code) ? ((action), 0) : 0)
#define ERROR_INJECT(code) \
my_error_inject_name(code)
#define ERROR_INJECT_VALUE(value) \
my_error_inject(value)
#define ERROR_INJECT_VALUE_ACTION(value,action) \
(my_error_inject(value) ? (action) : 0)
#define ERROR_INJECT_VALUE_CRASH(value) \
(my_error_inject(value) ? abort() : 0)
#endif
uint build_table_path(char *buff, size_t bufflen, const char *db,
const char *table, const char *ext);
void write_bin_log(THD *thd, bool clear_error,
......@@ -1093,6 +1188,16 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
bool remove_table_from_cache(THD *thd, const char *db, const char *table,
uint flags);
#define NORMAL_PART_NAME 0
#define TEMP_PART_NAME 1
#define RENAMED_PART_NAME 2
void create_partition_name(char *out, const char *in1,
const char *in2, uint name_variant,
bool translate);
void create_subpartition_name(char *out, const char *in1,
const char *in2, const char *in3,
uint name_variant);
typedef struct st_lock_param_type
{
ulonglong copied;
......@@ -1112,14 +1217,97 @@ typedef struct st_lock_param_type
uint key_count;
uint db_options;
uint pack_frm_len;
partition_info *part_info;
} ALTER_PARTITION_PARAM_TYPE;
void mem_alloc_error(size_t size);
#define WFRM_INITIAL_WRITE 1
#define WFRM_CREATE_HANDLER_FILES 2
enum ddl_log_entry_code
{
/*
DDL_LOG_EXECUTE_CODE:
This is a code that indicates that this is a log entry to
be executed, from this entry a linked list of log entries
can be found and executed.
DDL_LOG_ENTRY_CODE:
An entry to be executed in a linked list from an execute log
entry.
DDL_IGNORE_LOG_ENTRY_CODE:
An entry that is to be ignored
*/
DDL_LOG_EXECUTE_CODE = 'e',
DDL_LOG_ENTRY_CODE = 'l',
DDL_IGNORE_LOG_ENTRY_CODE = 'i'
};
enum ddl_log_action_code
{
/*
The type of action that a DDL_LOG_ENTRY_CODE entry is to
perform.
DDL_LOG_DELETE_ACTION:
Delete an entity
DDL_LOG_RENAME_ACTION:
Rename an entity
DDL_LOG_REPLACE_ACTION:
Rename an entity after removing the previous entry with the
new name, that is replace this entry.
*/
DDL_LOG_DELETE_ACTION = 'd',
DDL_LOG_RENAME_ACTION = 'r',
DDL_LOG_REPLACE_ACTION = 's'
};
typedef struct st_ddl_log_entry
{
const char *name;
const char *from_name;
const char *handler_name;
uint next_entry;
uint entry_pos;
enum ddl_log_entry_code entry_type;
enum ddl_log_action_code action_type;
/*
Most actions have only one phase. REPLACE does however have two
phases. The first phase removes the file with the new name if
there was one there before and the second phase renames the
old name to the new name.
*/
char phase;
} DDL_LOG_ENTRY;
typedef struct st_ddl_log_memory_entry
{
uint entry_pos;
struct st_ddl_log_memory_entry *next_log_entry;
struct st_ddl_log_memory_entry *prev_log_entry;
struct st_ddl_log_memory_entry *next_active_log_entry;
} DDL_LOG_MEMORY_ENTRY;
#define DDL_LOG_HANDLER_TYPE_LEN 32
bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry,
DDL_LOG_MEMORY_ENTRY **active_entry);
bool write_execute_ddl_log_entry(uint first_entry,
bool complete,
DDL_LOG_MEMORY_ENTRY **active_entry);
bool deactivate_ddl_log_entry(uint entry_no);
void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry);
bool sync_ddl_log();
void release_ddl_log();
void execute_ddl_log_recovery();
bool execute_ddl_log_entry(uint first_entry);
void lock_global_ddl_log();
void unlock_global_ddl_log();
#define WFRM_WRITE_SHADOW 1
#define WFRM_INSTALL_SHADOW 2
#define WFRM_PACK_FRM 4
bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags);
bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt);
void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt);
void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt);
void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table);
......@@ -1290,6 +1478,9 @@ extern ulong delayed_insert_timeout;
extern ulong delayed_insert_limit, delayed_queue_size;
extern ulong delayed_insert_threads, delayed_insert_writes;
extern ulong delayed_rows_in_use,delayed_insert_errors;
#ifdef ERROR_INJECT_SUPPORT
extern ulong error_inject_value;
#endif
extern ulong slave_open_temp_tables;
extern ulong query_cache_size, query_cache_min_res_unit;
extern ulong slow_launch_threads, slow_launch_time;
......
......@@ -3665,6 +3665,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
unireg_abort(1);
}
}
execute_ddl_log_recovery();
create_shutdown_thread();
create_maintenance_thread();
......@@ -3695,6 +3696,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
/* (void) pthread_attr_destroy(&connection_attrib); */
DBUG_PRINT("quit",("Exiting main thread"));
release_ddl_log();
#ifndef __WIN__
#ifdef EXTRA_DEBUG2
......
......@@ -36,6 +36,8 @@ enum partition_state {
PART_IS_ADDED= 8
};
struct st_ddl_log_memory_entry;
class partition_element :public Sql_alloc {
public:
List<partition_element> subpartitions;
......@@ -44,6 +46,7 @@ class partition_element :public Sql_alloc {
ulonglong part_min_rows;
char *partition_name;
char *tablespace_name;
struct st_ddl_log_memory_entry *log_entry;
longlong range_value;
char* part_comment;
char* data_file_name;
......@@ -55,7 +58,8 @@ class partition_element :public Sql_alloc {
partition_element()
: part_max_rows(0), part_min_rows(0), partition_name(NULL),
tablespace_name(NULL), range_value(0), part_comment(NULL),
tablespace_name(NULL), log_entry(NULL),
range_value(0), part_comment(NULL),
data_file_name(NULL), index_file_name(NULL),
engine_type(NULL),part_state(PART_NORMAL),
nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE)
......
......@@ -28,7 +28,7 @@ typedef int (*get_part_id_func)(partition_info *part_info,
longlong *func_value);
typedef uint32 (*get_subpart_id_func)(partition_info *part_info);
struct st_ddl_log_memory_entry;
class partition_info : public Sql_alloc
{
......@@ -77,6 +77,10 @@ class partition_info : public Sql_alloc
Item *item_free_list;
struct st_ddl_log_memory_entry *first_log_entry;
struct st_ddl_log_memory_entry *exec_log_entry;
struct st_ddl_log_memory_entry *frm_log_entry;
/*
A bitmap of partitions used by the current query.
Usage pattern:
......@@ -191,6 +195,7 @@ class partition_info : public Sql_alloc
part_field_array(NULL), subpart_field_array(NULL),
full_part_field_array(NULL),
part_expr(NULL), subpart_expr(NULL), item_free_list(NULL),
first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL),
list_array(NULL),
part_info_string(NULL),
part_func_string(NULL), subpart_func_string(NULL),
......
......@@ -5826,3 +5826,5 @@ ER_NDB_CANT_SWITCH_BINLOG_FORMAT
eng "The NDB cluster engine does not support changing the binlog format on the fly yet"
ER_PARTITION_NO_TEMPORARY
eng "Cannot create temporary table with partitions"
ER_DDL_LOG_ERROR
eng "Error in DDL log"
......@@ -6156,23 +6156,17 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b)
old_lock_level Old lock level
*/
bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt)
void abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt)
{
uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG;
int error= FALSE;
DBUG_ENTER("abort_and_upgrade_locks");
lpt->old_lock_type= lpt->table->reginfo.lock_type;
VOID(pthread_mutex_lock(&LOCK_open));
mysql_lock_abort(lpt->thd, lpt->table, TRUE);
VOID(remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name, flags));
if (lpt->thd->killed)
{
lpt->thd->no_warnings_for_error= 0;
error= TRUE;
}
VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(error);
DBUG_VOID_RETURN;
}
......
......@@ -223,6 +223,9 @@ THD::THD()
cuted_fields= sent_row_count= 0L;
limit_found_rows= 0;
statement_id_counter= 0UL;
#ifdef ERROR_INJECT_SUPPORT
error_inject_value= 0UL;
#endif
// Must be reset to handle error with THD's created for init of mysqld
lex->current_select= 0;
start_time=(time_t) 0;
......
......@@ -1119,6 +1119,9 @@ class THD :public Statement,
query_id_t query_id, warn_id;
ulong thread_id, col_access;
#ifdef ERROR_INJECT_SUPPORT
ulong error_inject_value;
#endif
/* Statement id is thread-wide. This counter is used to generate ids */
ulong statement_id_counter;
ulong rand_saved_seed1, rand_saved_seed2;
......
This diff is collapsed.
This diff is collapsed.
......@@ -3557,75 +3557,14 @@ part_definition:
LEX *lex= Lex;
partition_info *part_info= lex->part_info;
partition_element *p_elem= new partition_element();
uint part_id= part_info->partitions.elements +
part_info->temp_partitions.elements;
enum partition_state part_state;
uint part_id= part_info->partitions.elements;
if (part_info->part_state)
part_state= (enum partition_state)part_info->part_state[part_id];
else
part_state= PART_NORMAL;
switch (part_state)
{
case PART_TO_BE_DROPPED:
/*
This part is currently removed so we keep it in a
temporary list for REPAIR TABLE to be able to handle
failures during drop partition process.
*/
case PART_TO_BE_ADDED:
/*
This part is currently being added so we keep it in a
temporary list for REPAIR TABLE to be able to handle
failures during add partition process.
*/
if (!p_elem || part_info->temp_partitions.push_back(p_elem))
{
mem_alloc_error(sizeof(partition_element));
YYABORT;
}
break;
case PART_IS_ADDED:
/*
Part has been added and is now a normal partition
*/
case PART_TO_BE_REORGED:
/*
This part is currently reorganised, it is still however
used so we keep it in the list of partitions. We do
however need the state to be able to handle REPAIR TABLE
after failures in the reorganisation process.
*/
case PART_REORGED_DROPPED:
/*
This part is currently reorganised as part of a
COALESCE PARTITION and it will be dropped without a new
replacement partition after completing the reorganisation.
*/
case PART_CHANGED:
/*
This part is currently split or merged as part of ADD
PARTITION for a hash partition or as part of COALESCE
PARTITION for a hash partitioned table.
*/
case PART_IS_CHANGED:
/*
This part has been split or merged as part of ADD
PARTITION for a hash partition or as part of COALESCE
PARTITION for a hash partitioned table.
*/
case PART_NORMAL:
if (!p_elem || part_info->partitions.push_back(p_elem))
{
mem_alloc_error(sizeof(partition_element));
YYABORT;
}
break;
default:
mem_alloc_error((part_id * 1000) + part_state);
YYABORT;
}
p_elem->part_state= part_state;
p_elem->part_state= PART_NORMAL;
part_info->curr_part_elem= p_elem;
part_info->current_partition= p_elem;
part_info->use_default_partitions= FALSE;
......
......@@ -667,36 +667,16 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
#endif
next_chunk+= 5 + partition_info_len;
}
if (share->mysql_version > 50105 && next_chunk + 5 < buff_end)
#if 1
if (share->mysql_version == 50106 ||
share->mysql_version == 50107)
{
/*
Partition state was introduced to support partition management in version 5.1.5
Partition state array was here in version 5.1.6, this code makes
it possible to load a 5.1.6 table in later versions. Can most
likely be removed at some point in time.
*/
uint32 part_state_len= uint4korr(next_chunk);
#ifdef WITH_PARTITION_STORAGE_ENGINE
if ((share->part_state_len= part_state_len))
if (!(share->part_state=
(uchar*) memdup_root(&share->mem_root, next_chunk + 4,
part_state_len)))
{
my_free(buff, MYF(0));
goto err;
}
#else
if (part_state_len)
{
DBUG_PRINT("info", ("WITH_PARTITION_STORAGE_ENGINE is not defined"));
my_free(buff, MYF(0));
goto err;
}
#endif
next_chunk+= 4 + part_state_len;
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
else
{
share->part_state_len= 0;
share->part_state= NULL;
next_chunk+= 4;
}
#endif
keyinfo= share->key_info;
......
......@@ -136,7 +136,6 @@ bool mysql_create_frm(THD *thd, const char *file_name,
if (part_info)
{
create_info->extra_size+= part_info->part_info_len;
create_info->extra_size+= part_info->part_state_len;
}
#endif
......@@ -209,12 +208,6 @@ bool mysql_create_frm(THD *thd, const char *file_name,
my_write(file, (const byte*)part_info->part_info_string,
part_info->part_info_len + 1, MYF_RW))
goto err;
DBUG_PRINT("info", ("Part state len = %d", part_info->part_state_len));
int4store(buff, part_info->part_state_len);
if (my_write(file, (const byte*)buff, 4, MYF_RW) ||
my_write(file, (const byte*)part_info->part_state,
part_info->part_state_len, MYF_RW))
goto err;
}
else
#endif
......@@ -330,7 +323,7 @@ int rea_create_table(THD *thd, const char *path,
// Make sure mysql_create_frm din't remove extension
DBUG_ASSERT(*fn_rext(frm_name));
if (file->create_handler_files(path))
if (file->create_handler_files(path, NULL, FALSE))
goto err_handler;
if (!create_info->frm_only && ha_create_table(thd, path, db, table_name,
create_info,0))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment