Commit 955e2819 authored by Otto Kekäläinen's avatar Otto Kekäläinen
Browse files

Merge tag 'upstream/5.5.52' into ubuntu-14.04

Upstream version 5.5.52
parents d6317e1a 4d305fb9
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. /* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
Copyright (c) 2010, 2016, MariaDB Copyright (c) 2010, 2016, MariaDB
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
...@@ -5371,6 +5371,15 @@ handle_view(THD *thd, Query_tables_list *prelocking_ctx, ...@@ -5371,6 +5371,15 @@ handle_view(THD *thd, Query_tables_list *prelocking_ctx,
&table_list->view->sroutines_list, &table_list->view->sroutines_list,
table_list->top_table()); table_list->top_table());
} }
/*
If a trigger was defined on one of the associated tables then assign the
'trg_event_map' value of the view to the next table in table_list. When a
Stored function is invoked, all the associated tables including the tables
associated with the trigger are prelocked.
*/
if (table_list->trg_event_map && table_list->next_global)
table_list->next_global->trg_event_map= table_list->trg_event_map;
return FALSE; return FALSE;
} }
......
...@@ -4736,9 +4736,11 @@ int THD::decide_logging_format(TABLE_LIST *tables) ...@@ -4736,9 +4736,11 @@ int THD::decide_logging_format(TABLE_LIST *tables)
{ {
static const char *prelocked_mode_name[] = { static const char *prelocked_mode_name[] = {
"NON_PRELOCKED", "NON_PRELOCKED",
"LOCK_TABLES",
"PRELOCKED", "PRELOCKED",
"PRELOCKED_UNDER_LOCK_TABLES", "PRELOCKED_UNDER_LOCK_TABLES",
}; };
compile_time_assert(array_elements(prelocked_mode_name) == LTM_always_last);
DBUG_PRINT("debug", ("prelocked_mode: %s", DBUG_PRINT("debug", ("prelocked_mode: %s",
prelocked_mode_name[locked_tables_mode])); prelocked_mode_name[locked_tables_mode]));
} }
......
...@@ -1075,7 +1075,8 @@ enum enum_locked_tables_mode ...@@ -1075,7 +1075,8 @@ enum enum_locked_tables_mode
LTM_NONE= 0, LTM_NONE= 0,
LTM_LOCK_TABLES, LTM_LOCK_TABLES,
LTM_PRELOCKED, LTM_PRELOCKED,
LTM_PRELOCKED_UNDER_LOCK_TABLES LTM_PRELOCKED_UNDER_LOCK_TABLES,
LTM_always_last
}; };
...@@ -3607,6 +3608,11 @@ class TMP_TABLE_PARAM :public Sql_alloc ...@@ -3607,6 +3608,11 @@ class TMP_TABLE_PARAM :public Sql_alloc
save_copy_field_end= copy_field_end= NULL; save_copy_field_end= copy_field_end= NULL;
} }
} }
void free_copy_field_data()
{
for (Copy_field *ptr= copy_field ; ptr != copy_field_end ; ptr++)
ptr->tmp.free();
}
}; };
class select_union :public select_result_interceptor class select_union :public select_result_interceptor
......
...@@ -3238,6 +3238,7 @@ bool Delayed_insert::handle_inserts(void) ...@@ -3238,6 +3238,7 @@ bool Delayed_insert::handle_inserts(void)
max_rows= 0; // For DBUG output max_rows= 0; // For DBUG output
#endif #endif
/* Remove all not used rows */ /* Remove all not used rows */
mysql_mutex_lock(&mutex);
while ((row=rows.get())) while ((row=rows.get()))
{ {
if (table->s->blob_fields) if (table->s->blob_fields)
...@@ -3254,7 +3255,6 @@ bool Delayed_insert::handle_inserts(void) ...@@ -3254,7 +3255,6 @@ bool Delayed_insert::handle_inserts(void)
} }
DBUG_PRINT("error", ("dropped %lu rows after an error", max_rows)); DBUG_PRINT("error", ("dropped %lu rows after an error", max_rows));
thread_safe_increment(delayed_insert_errors, &LOCK_delayed_status); thread_safe_increment(delayed_insert_errors, &LOCK_delayed_status);
mysql_mutex_lock(&mutex);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
#endif /* EMBEDDED_LIBRARY */ #endif /* EMBEDDED_LIBRARY */
......
...@@ -1389,8 +1389,8 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs, ...@@ -1389,8 +1389,8 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
set_if_bigger(length,line_start.length()); set_if_bigger(length,line_start.length());
stack=stack_pos=(int*) sql_alloc(sizeof(int)*length); stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0)))) if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(MY_WME))))
error=1; /* purecov: inspected */ error= true; /* purecov: inspected */
else else
{ {
end_of_buff=buffer+buff_length; end_of_buff=buffer+buff_length;
...@@ -1581,37 +1581,50 @@ int READ_INFO::read_field() ...@@ -1581,37 +1581,50 @@ int READ_INFO::read_field()
} }
} }
#ifdef USE_MB #ifdef USE_MB
if (my_mbcharlen(read_charset, chr) > 1 && uint ml= my_mbcharlen(read_charset, chr);
to + my_mbcharlen(read_charset, chr) <= end_of_buff) if (ml == 0)
{ {
uchar* p= to; *to= '\0';
int ml, i; my_error(ER_INVALID_CHARACTER_STRING, MYF(0),
*to++ = chr; read_charset->csname, buffer);
error= true;
ml= my_mbcharlen(read_charset, chr); return 1;
}
for (i= 1; i < ml; i++) if (ml > 1 &&
to + ml <= end_of_buff)
{ {
chr= GET; uchar* p= to;
if (chr == my_b_EOF) *to++ = chr;
for (uint i= 1; i < ml; i++)
{ {
/* chr= GET;
Need to back up the bytes already ready from illformed if (chr == my_b_EOF)
multi-byte char {
*/ /*
to-= i; Need to back up the bytes already ready from illformed
goto found_eof; multi-byte char
*/
to-= i;
goto found_eof;
}
*to++ = chr;
} }
*to++ = chr; if (my_ismbchar(read_charset,
}
if (my_ismbchar(read_charset,
(const char *)p, (const char *)p,
(const char *)to)) (const char *)to))
continue; continue;
for (i= 0; i < ml; i++) for (uint i= 0; i < ml; i++)
PUSH(*--to); PUSH(*--to);
chr= GET; chr= GET;
} }
else if (ml > 1)
{
// Buffer is too small, exit while loop, and reallocate.
PUSH(chr);
break;
}
#endif #endif
*to++ = (uchar) chr; *to++ = (uchar) chr;
} }
...@@ -1855,7 +1868,15 @@ int READ_INFO::read_value(int delim, String *val) ...@@ -1855,7 +1868,15 @@ int READ_INFO::read_value(int delim, String *val)
for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF;) for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF;)
{ {
#ifdef USE_MB #ifdef USE_MB
if (my_mbcharlen(read_charset, chr) > 1) uint ml= my_mbcharlen(read_charset, chr);
if (ml == 0)
{
chr= my_b_EOF;
val->length(0);
return chr;
}
if (ml > 1)
{ {
DBUG_PRINT("read_xml",("multi byte")); DBUG_PRINT("read_xml",("multi byte"));
int i, ml= my_mbcharlen(read_charset, chr); int i, ml= my_mbcharlen(read_charset, chr);
......
...@@ -2896,68 +2896,8 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) ...@@ -2896,68 +2896,8 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
if (!thd->variables.dynamic_variables_ptr || if (!thd->variables.dynamic_variables_ptr ||
(uint)offset > thd->variables.dynamic_variables_head) (uint)offset > thd->variables.dynamic_variables_head)
{ {
uint idx;
mysql_rwlock_rdlock(&LOCK_system_variables_hash); mysql_rwlock_rdlock(&LOCK_system_variables_hash);
sync_dynamic_session_variables(thd, global_lock);
thd->variables.dynamic_variables_ptr= (char*)
my_realloc(thd->variables.dynamic_variables_ptr,
global_variables_dynamic_size,
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
if (global_lock)
mysql_mutex_lock(&LOCK_global_system_variables);
mysql_mutex_assert_owner(&LOCK_global_system_variables);
memcpy(thd->variables.dynamic_variables_ptr +
thd->variables.dynamic_variables_size,
global_system_variables.dynamic_variables_ptr +
thd->variables.dynamic_variables_size,
global_system_variables.dynamic_variables_size -
thd->variables.dynamic_variables_size);
/*
now we need to iterate through any newly copied 'defaults'
and if it is a string type with MEMALLOC flag, we need to strdup
*/
for (idx= 0; idx < bookmark_hash.records; idx++)
{
sys_var_pluginvar *pi;
sys_var *var;
st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx);
if (v->version <= thd->variables.dynamic_variables_version)
continue; /* already in thd->variables */
if (!(var= intern_find_sys_var(v->key + 1, v->name_len)) ||
!(pi= var->cast_pluginvar()) ||
v->key[0] != plugin_var_bookmark_key(pi->plugin_var->flags))
continue;
/* Here we do anything special that may be required of the data types */
if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
{
char **pp= (char**) (thd->variables.dynamic_variables_ptr +
*(int*)(pi->plugin_var + 1));
if ((*pp= *(char**) (global_system_variables.dynamic_variables_ptr +
*(int*)(pi->plugin_var + 1))))
*pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
}
}
if (global_lock)
mysql_mutex_unlock(&LOCK_global_system_variables);
thd->variables.dynamic_variables_version=
global_system_variables.dynamic_variables_version;
thd->variables.dynamic_variables_head=
global_system_variables.dynamic_variables_head;
thd->variables.dynamic_variables_size=
global_system_variables.dynamic_variables_size;
mysql_rwlock_unlock(&LOCK_system_variables_hash); mysql_rwlock_unlock(&LOCK_system_variables_hash);
} }
DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset); DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset);
...@@ -3037,6 +2977,70 @@ void plugin_thdvar_init(THD *thd) ...@@ -3037,6 +2977,70 @@ void plugin_thdvar_init(THD *thd)
} }
void sync_dynamic_session_variables(THD* thd, bool global_lock)
{
uint idx;
thd->variables.dynamic_variables_ptr= (char*)
my_realloc(thd->variables.dynamic_variables_ptr,
global_variables_dynamic_size,
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
if (global_lock)
mysql_mutex_lock(&LOCK_global_system_variables);
mysql_mutex_assert_owner(&LOCK_global_system_variables);
memcpy(thd->variables.dynamic_variables_ptr +
thd->variables.dynamic_variables_size,
global_system_variables.dynamic_variables_ptr +
thd->variables.dynamic_variables_size,
global_system_variables.dynamic_variables_size -
thd->variables.dynamic_variables_size);
/*
now we need to iterate through any newly copied 'defaults'
and if it is a string type with MEMALLOC flag, we need to strdup
*/
for (idx= 0; idx < bookmark_hash.records; idx++)
{
sys_var_pluginvar *pi;
sys_var *var;
st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx);
if (v->version <= thd->variables.dynamic_variables_version)
continue; /* already in thd->variables */
if (!(var= intern_find_sys_var(v->key + 1, v->name_len)) ||
!(pi= var->cast_pluginvar()) ||
v->key[0] != plugin_var_bookmark_key(pi->plugin_var->flags))
continue;
/* Here we do anything special that may be required of the data types */
if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
{
int offset= ((thdvar_str_t *)(pi->plugin_var))->offset;
char **pp= (char**) (thd->variables.dynamic_variables_ptr + offset);
if (*pp)
*pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
}
}
if (global_lock)
mysql_mutex_unlock(&LOCK_global_system_variables);
thd->variables.dynamic_variables_version=
global_system_variables.dynamic_variables_version;
thd->variables.dynamic_variables_head=
global_system_variables.dynamic_variables_head;
thd->variables.dynamic_variables_size=
global_system_variables.dynamic_variables_size;
}
/* /*
Unlocks all system variables which hold a reference Unlocks all system variables which hold a reference
*/ */
......
...@@ -174,4 +174,6 @@ typedef my_bool (plugin_foreach_func)(THD *thd, ...@@ -174,4 +174,6 @@ typedef my_bool (plugin_foreach_func)(THD *thd,
#define plugin_foreach(A,B,C,D) plugin_foreach_with_mask(A,B,C,PLUGIN_IS_READY,D) #define plugin_foreach(A,B,C,D) plugin_foreach_with_mask(A,B,C,PLUGIN_IS_READY,D)
extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func, extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
int type, uint state_mask, void *arg); int type, uint state_mask, void *arg);
extern void sync_dynamic_session_variables(THD* thd, bool global_lock);
#endif #endif
...@@ -8275,9 +8275,26 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table) ...@@ -8275,9 +8275,26 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table)
We need to destruct the copy_field (allocated in create_tmp_table()) We need to destruct the copy_field (allocated in create_tmp_table())
before setting it to 0 if the join is not "reusable". before setting it to 0 if the join is not "reusable".
*/ */
if (!tmp_join || tmp_join != this) if (!tmp_join || tmp_join != this)
tmp_table_param.cleanup(); tmp_table_param.cleanup();
tmp_table_param.copy_field= tmp_table_param.copy_field_end=0; else
{
/*
Free data buffered in copy_fields, but keep data pointed by copy_field
around for next iteration (possibly stored in save_copy_fields).
It would be logically simpler to not clear copy_field
below, but as we have loops that runs over copy_field to
copy_field_end that should not be done anymore, it's simpler to
just clear the pointers.
Another option would be to just clear copy_field_end and not run
the loops if this is not set or to have tmp_table_param.cleanup()
to run cleanup on save_copy_field if copy_field is not set.
*/
tmp_table_param.free_copy_field_data();
tmp_table_param.copy_field= tmp_table_param.copy_field_end=0;
}
first_record= sort_and_group=0; first_record= sort_and_group=0;
send_records= (ha_rows) 0; send_records= (ha_rows) 0;
   
...@@ -10866,7 +10883,7 @@ void JOIN::join_free() ...@@ -10866,7 +10883,7 @@ void JOIN::join_free()
/** /**
Free resources of given join. Free resources of given join.
   
@param fill true if we should free all resources, call with full==1 @param full true if we should free all resources, call with full==1
should be last, before it this function can be called with should be last, before it this function can be called with
full==0 full==0
   
...@@ -10982,7 +10999,7 @@ void JOIN::cleanup(bool full) ...@@ -10982,7 +10999,7 @@ void JOIN::cleanup(bool full)
/* /*
If we have tmp_join and 'this' JOIN is not tmp_join and If we have tmp_join and 'this' JOIN is not tmp_join and
tmp_table_param.copy_field's of them are equal then we have to remove tmp_table_param.copy_field's of them are equal then we have to remove
pointer to tmp_table_param.copy_field from tmp_join, because it qill pointer to tmp_table_param.copy_field from tmp_join, because it will
be removed in tmp_table_param.cleanup(). be removed in tmp_table_param.cleanup().
*/ */
if (tmp_join && if (tmp_join &&
...@@ -14816,6 +14833,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, ...@@ -14816,6 +14833,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::VARBIN_ITEM: case Item::VARBIN_ITEM:
case Item::CACHE_ITEM: case Item::CACHE_ITEM:
case Item::EXPR_CACHE_ITEM: case Item::EXPR_CACHE_ITEM:
case Item::PARAM_ITEM:
if (make_copy_field) if (make_copy_field)
{ {
DBUG_ASSERT(((Item_result_field*)item)->result_field); DBUG_ASSERT(((Item_result_field*)item)->result_field);
...@@ -21397,7 +21415,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, ...@@ -21397,7 +21415,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
err: err:
if (copy) if (copy)
delete [] param->copy_field; // This is never 0 delete [] param->copy_field; // This is never 0
param->copy_field=0; param->copy_field= 0;
err2: err2:
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
......
...@@ -6937,19 +6937,30 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond) ...@@ -6937,19 +6937,30 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
const char *wild= lex->wild ? lex->wild->ptr() : NullS; const char *wild= lex->wild ? lex->wild->ptr() : NullS;
enum enum_schema_tables schema_table_idx= enum enum_schema_tables schema_table_idx=
get_schema_table_idx(tables->schema_table); get_schema_table_idx(tables->schema_table);
enum enum_var_type option_type= OPT_SESSION; enum enum_var_type scope= OPT_SESSION;
bool upper_case_names= (schema_table_idx != SCH_VARIABLES); bool upper_case_names= (schema_table_idx != SCH_VARIABLES);
bool sorted_vars= (schema_table_idx == SCH_VARIABLES); bool sorted_vars= (schema_table_idx == SCH_VARIABLES);
if ((sorted_vars && lex->option_type == OPT_GLOBAL) || if ((sorted_vars && lex->option_type == OPT_GLOBAL) ||
schema_table_idx == SCH_GLOBAL_VARIABLES) schema_table_idx == SCH_GLOBAL_VARIABLES)
option_type= OPT_GLOBAL; scope= OPT_GLOBAL;
COND *partial_cond= make_cond_for_info_schema(cond, tables); COND *partial_cond= make_cond_for_info_schema(cond, tables);
mysql_rwlock_rdlock(&LOCK_system_variables_hash); mysql_rwlock_rdlock(&LOCK_system_variables_hash);
res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, option_type),
option_type, NULL, "", tables->table, /*
Avoid recursive LOCK_system_variables_hash acquisition in
intern_sys_var_ptr() by pre-syncing dynamic session variables.
*/
if (scope == OPT_SESSION &&
(!thd->variables.dynamic_variables_ptr ||
global_system_variables.dynamic_variables_head >
thd->variables.dynamic_variables_head))
sync_dynamic_session_variables(thd, true);
res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, scope),
scope, NULL, "", tables->table,
upper_case_names, partial_cond); upper_case_names, partial_cond);
mysql_rwlock_unlock(&LOCK_system_variables_hash); mysql_rwlock_unlock(&LOCK_system_variables_hash);
DBUG_RETURN(res); DBUG_RETURN(res);
......
...@@ -887,6 +887,12 @@ bool st_select_lex_unit::cleanup() ...@@ -887,6 +887,12 @@ bool st_select_lex_unit::cleanup()
join->tables_list= 0; join->tables_list= 0;
join->table_count= 0; join->table_count= 0;
join->top_join_tab_count= 0; join->top_join_tab_count= 0;
if (join->tmp_join && join->tmp_join != join)
{
join->tmp_join->tables_list= 0;
join->tmp_join->table_count= 0;
join->tmp_join->top_join_tab_count= 0;
}
} }
error|= fake_select_lex->cleanup(); error|= fake_select_lex->cleanup();
/* /*
......
...@@ -3025,18 +3025,31 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var) ...@@ -3025,18 +3025,31 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var)
if (!var->save_result.string_value.str) if (!var->save_result.string_value.str)
return true; return true;
if (var->save_result.string_value.length > FN_REFLEN) LEX_STRING *val= &var->save_result.string_value;
if (val->length > FN_REFLEN)
{ // path is too long { // path is too long
my_error(ER_PATH_LENGTH, MYF(0), self->name.str); my_error(ER_PATH_LENGTH, MYF(0), self->name.str);
return true; return true;
} }
char path[FN_REFLEN]; char path[FN_REFLEN];
size_t path_length= unpack_filename(path, var->save_result.string_value.str); size_t path_length= unpack_filename(path, val->str);
if (!path_length) if (!path_length)
return true; return true;
static const LEX_CSTRING my_cnf= { STRING_WITH_LEN("my.cnf") };
static const LEX_CSTRING my_ini= { STRING_WITH_LEN("my.ini") };
if (path_length >= my_cnf.length)
{
if (strcasecmp(path + path_length - my_cnf.length, my_cnf.str) == 0)
return true; // log file name ends with "my.cnf"
DBUG_ASSERT(my_cnf.length == my_ini.length);
if (strcasecmp(path + path_length - my_ini.length, my_ini.str) == 0)
return true; // log file name ends with "my.ini"
}
MY_STAT f_stat; MY_STAT f_stat;
if (my_stat(path, &f_stat, MYF(0))) if (my_stat(path, &f_stat, MYF(0)))
...@@ -3046,9 +3059,9 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var) ...@@ -3046,9 +3059,9 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var)
return false; return false;
} }
(void) dirname_part(path, var->save_result.string_value.str, &path_length); (void) dirname_part(path, val->str, &path_length);
if (var->save_result.string_value.length - path_length >= FN_LEN) if (val->length - path_length >= FN_LEN)
{ // filename is too long { // filename is too long
my_error(ER_PATH_LENGTH, MYF(0), self->name.str); my_error(ER_PATH_LENGTH, MYF(0), self->name.str);
return true; return true;
......
...@@ -1242,14 +1242,14 @@ dict_create_or_check_foreign_constraint_tables(void) ...@@ -1242,14 +1242,14 @@ dict_create_or_check_foreign_constraint_tables(void)
fprintf(stderr, fprintf(stderr,
"InnoDB: dropping incompletely created" "InnoDB: dropping incompletely created"
" SYS_FOREIGN table\n"); " SYS_FOREIGN table\n");
row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE); row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE);
} }
if (table2) { if (table2) {
fprintf(stderr, fprintf(stderr,
"InnoDB: dropping incompletely created" "InnoDB: dropping incompletely created"
" SYS_FOREIGN_COLS table\n"); " SYS_FOREIGN_COLS table\n");
row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE); row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE);
} }
fprintf(stderr, fprintf(stderr,
...@@ -1298,8 +1298,8 @@ dict_create_or_check_foreign_constraint_tables(void) ...@@ -1298,8 +1298,8 @@ dict_create_or_check_foreign_constraint_tables(void)
"InnoDB: dropping incompletely created" "InnoDB: dropping incompletely created"
" SYS_FOREIGN tables\n"); " SYS_FOREIGN tables\n");
row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE); row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE);
row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE); row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE);
error = DB_MUST_GET_MORE_FILE_SPACE; error = DB_MUST_GET_MORE_FILE_SPACE;
} }
......
...@@ -7644,7 +7644,8 @@ ha_innobase::delete_table( ...@@ -7644,7 +7644,8 @@ ha_innobase::delete_table(
error = row_drop_table_for_mysql(norm_name, trx, error = row_drop_table_for_mysql(norm_name, trx,
thd_sql_command(thd) thd_sql_command(thd)
== SQLCOM_DROP_DB); == SQLCOM_DROP_DB,
FALSE);
/* Flush the log to reduce probability that the .frm files and /* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs the InnoDB data dictionary get out-of-sync if the user runs
......
...@@ -348,20 +348,13 @@ os_atomic_test_and_set(volatile lock_word_t* ptr) ...@@ -348,20 +348,13 @@ os_atomic_test_and_set(volatile lock_word_t* ptr)
} }
/** Do an atomic release. /** Do an atomic release.
In theory __sync_lock_release should be used to release the lock.
Unfortunately, it does not work properly alone. The workaround is
that more conservative __sync_lock_test_and_set is used instead.
Performance regression was observed at some conditions for Intel
architecture. Disable release barrier on Intel architecture for now.
@param[in,out] ptr Memory location to write to @param[in,out] ptr Memory location to write to
@return the previous value */ @return the previous value */
static inline static inline
lock_word_t void
os_atomic_clear(volatile lock_word_t* ptr) os_atomic_clear(volatile lock_word_t* ptr)
{ {
return(__sync_lock_test_and_set(ptr, 0)); __sync_lock_release(ptr);
} }
# elif defined(HAVE_IB_GCC_ATOMIC_TEST_AND_SET) # elif defined(HAVE_IB_GCC_ATOMIC_TEST_AND_SET)
......
...@@ -454,7 +454,10 @@ row_drop_table_for_mysql( ...@@ -454,7 +454,10 @@ row_drop_table_for_mysql(
/*=====================*/ /*=====================*/
const char* name, /*!< in: table name */ const char* name, /*!< in: table name */
trx_t* trx, /*!< in: transaction handle */ trx_t* trx, /*!< in: transaction handle */
ibool drop_db);/*!< in: TRUE=dropping whole database */ ibool drop_db,/*!< in: TRUE=dropping whole database */
ibool create_failed);/*!<in: TRUE=create table failed
because e.g. foreign key column
type mismatch. */
/*********************************************************************//** /*********************************************************************//**
Drop all temporary tables during crash recovery. */ Drop all temporary tables during crash recovery. */
UNIV_INTERN UNIV_INTERN
......
...@@ -178,6 +178,11 @@ mutex_exit_func( ...@@ -178,6 +178,11 @@ mutex_exit_func(
to wake up possible hanging threads if to wake up possible hanging threads if
they are missed in mutex_signal_object. */ they are missed in mutex_signal_object. */
/* We add a memory barrier to prevent reading of the
number of waiters before releasing the lock. */
os_mb;
if (mutex_get_waiters(mutex) != 0) { if (mutex_get_waiters(mutex) != 0) {
mutex_signal_object(mutex); mutex_signal_object(mutex);
......
...@@ -1048,6 +1048,26 @@ page_cur_insert_rec_low( ...@@ -1048,6 +1048,26 @@ page_cur_insert_rec_low(
insert_rec = rec_copy(insert_buf, rec, offsets); insert_rec = rec_copy(insert_buf, rec, offsets);
rec_offs_make_valid(insert_rec, index, offsets); rec_offs_make_valid(insert_rec, index, offsets);
/* This is because assertion below is debug assertion */
#ifdef UNIV_DEBUG
if (UNIV_UNLIKELY(current_rec == insert_rec)) {
ulint extra_len, data_len;
extra_len = rec_offs_extra_size(offsets);
data_len = rec_offs_data_size(offsets);
fprintf(stderr, "InnoDB: Error: current_rec == insert_rec "
" extra_len %lu data_len %lu insert_buf %p rec %p\n",
extra_len, data_len, insert_buf, rec);
fprintf(stderr, "InnoDB; Physical record: \n");
rec_print(stderr, rec, index);
fprintf(stderr, "InnoDB: Inserted record: \n");
rec_print(stderr, insert_rec, index);
fprintf(stderr, "InnoDB: Current record: \n");
rec_print(stderr, current_rec, index);
ut_a(current_rec != insert_rec);
}
#endif /* UNIV_DEBUG */
/* 4. Insert the record in the linked list of records */ /* 4. Insert the record in the linked list of records */
ut_ad(current_rec != insert_rec); ut_ad(current_rec != insert_rec);
......
...@@ -2685,7 +2685,7 @@ row_merge_drop_table( ...@@ -2685,7 +2685,7 @@ row_merge_drop_table(
/* There must be no open transactions on the table. */ /* There must be no open transactions on the table. */
ut_a(table->n_mysql_handles_opened == 0); ut_a(table->n_mysql_handles_opened == 0);
return(row_drop_table_for_mysql(table->name, trx, FALSE)); return(row_drop_table_for_mysql(table->name, trx, FALSE, FALSE));
} }
/*********************************************************************//** /*********************************************************************//**
......
...@@ -1987,7 +1987,7 @@ row_create_table_for_mysql( ...@@ -1987,7 +1987,7 @@ row_create_table_for_mysql(
if (dict_table_get_low(table->name, DICT_ERR_IGNORE_NONE)) { if (dict_table_get_low(table->name, DICT_ERR_IGNORE_NONE)) {
row_drop_table_for_mysql(table->name, trx, FALSE); row_drop_table_for_mysql(table->name, trx, FALSE, TRUE);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
} else { } else {
dict_mem_table_free(table); dict_mem_table_free(table);
...@@ -2117,7 +2117,7 @@ row_create_index_for_mysql( ...@@ -2117,7 +2117,7 @@ row_create_index_for_mysql(
trx_general_rollback_for_mysql(trx, NULL); trx_general_rollback_for_mysql(trx, NULL);
row_drop_table_for_mysql(table_name, trx, FALSE); row_drop_table_for_mysql(table_name, trx, FALSE, TRUE);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
...@@ -2187,7 +2187,7 @@ row_table_add_foreign_constraints( ...@@ -2187,7 +2187,7 @@ row_table_add_foreign_constraints(
trx_general_rollback_for_mysql(trx, NULL); trx_general_rollback_for_mysql(trx, NULL);
row_drop_table_for_mysql(name, trx, FALSE); row_drop_table_for_mysql(name, trx, FALSE, TRUE);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
...@@ -2228,7 +2228,7 @@ row_drop_table_for_mysql_in_background( ...@@ -2228,7 +2228,7 @@ row_drop_table_for_mysql_in_background(
/* Try to drop the table in InnoDB */ /* Try to drop the table in InnoDB */
error = row_drop_table_for_mysql(name, trx, FALSE); error = row_drop_table_for_mysql(name, trx, FALSE, FALSE);
/* Flush the log to reduce probability that the .frm files and /* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs the InnoDB data dictionary get out-of-sync if the user runs
...@@ -3078,7 +3078,10 @@ row_drop_table_for_mysql( ...@@ -3078,7 +3078,10 @@ row_drop_table_for_mysql(
/*=====================*/ /*=====================*/
const char* name, /*!< in: table name */ const char* name, /*!< in: table name */
trx_t* trx, /*!< in: transaction handle */ trx_t* trx, /*!< in: transaction handle */
ibool drop_db)/*!< in: TRUE=dropping whole database */ ibool drop_db,/*!< in: TRUE=dropping whole database */
ibool create_failed) /*!<in: TRUE=create table failed
because e.g. foreign key column
type mismatch. */
{ {
dict_foreign_t* foreign; dict_foreign_t* foreign;
dict_table_t* table; dict_table_t* table;
...@@ -3193,7 +3196,11 @@ row_drop_table_for_mysql( ...@@ -3193,7 +3196,11 @@ row_drop_table_for_mysql(
foreign = UT_LIST_GET_NEXT(referenced_list, foreign); foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
} }
if (foreign && trx->check_foreigns /* We should allow dropping a referenced table if creating
that referenced table has failed for some reason. For example
if referenced table is created but it column types that are
referenced do not match. */
if (foreign && trx->check_foreigns && !create_failed
&& !(drop_db && dict_tables_have_same_db( && !(drop_db && dict_tables_have_same_db(
name, foreign->foreign_table_name_lookup))) { name, foreign->foreign_table_name_lookup))) {
FILE* ef = dict_foreign_err_file; FILE* ef = dict_foreign_err_file;
...@@ -3578,7 +3585,7 @@ row_mysql_drop_temp_tables(void) ...@@ -3578,7 +3585,7 @@ row_mysql_drop_temp_tables(void)
table = dict_load_table(table_name, TRUE, DICT_ERR_IGNORE_NONE); table = dict_load_table(table_name, TRUE, DICT_ERR_IGNORE_NONE);
if (table) { if (table) {
row_drop_table_for_mysql(table_name, trx, FALSE); row_drop_table_for_mysql(table_name, trx, FALSE, FALSE);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
} }
...@@ -3708,7 +3715,7 @@ row_drop_database_for_mysql( ...@@ -3708,7 +3715,7 @@ row_drop_database_for_mysql(
goto loop; goto loop;
} }
err = row_drop_table_for_mysql(table_name, trx, TRUE); err = row_drop_table_for_mysql(table_name, trx, TRUE, FALSE);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
......
...@@ -504,7 +504,7 @@ trx_rollback_active( ...@@ -504,7 +504,7 @@ trx_rollback_active(
ut_print_name(stderr, trx, TRUE, table->name); ut_print_name(stderr, trx, TRUE, table->name);
fputs(" in recovery\n", stderr); fputs(" in recovery\n", stderr);
err = row_drop_table_for_mysql(table->name, trx, TRUE); err = row_drop_table_for_mysql(table->name, trx, TRUE, FALSE);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
ut_a(err == (int) DB_SUCCESS); ut_a(err == (int) DB_SUCCESS);
......
Supports Markdown
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