Merge 5.1->5.2
This commit is contained in:
commit
8127e631de
8
mysql-test/r/information_schema2.result
Normal file
8
mysql-test/r/information_schema2.result
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
select variable_name from information_schema.session_status where variable_name =
|
||||||
|
(select variable_name from information_schema.session_status where variable_name = 'uptime');
|
||||||
|
variable_name
|
||||||
|
UPTIME
|
||||||
|
select variable_name from information_schema.session_variables where variable_name =
|
||||||
|
(select variable_name from information_schema.session_variables where variable_name = 'basedir');
|
||||||
|
variable_name
|
||||||
|
BASEDIR
|
@ -103,5 +103,20 @@ sm
|
|||||||
10323810
|
10323810
|
||||||
10325070
|
10325070
|
||||||
10326330
|
10326330
|
||||||
|
#
|
||||||
|
# Bug mdev-4063: SUM(DISTINCT...) with small'max_heap_table_size
|
||||||
|
# (bug #56927)
|
||||||
|
#
|
||||||
|
SET max_heap_table_size=default;
|
||||||
|
INSERT INTO t1 SELECT id+16384 FROM t1;
|
||||||
|
DELETE FROM t2;
|
||||||
|
INSERT INTO t2 SELECT id FROM t1 ORDER BY id*rand();
|
||||||
|
SELECT SUM(DISTINCT id) sm FROM t2;
|
||||||
|
sm
|
||||||
|
536887296
|
||||||
|
SET max_heap_table_size=16384;
|
||||||
|
SELECT SUM(DISTINCT id) sm FROM t2;
|
||||||
|
sm
|
||||||
|
536887296
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
DROP TABLE t2;
|
DROP TABLE t2;
|
||||||
|
9
mysql-test/t/information_schema2.test
Normal file
9
mysql-test/t/information_schema2.test
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
#
|
||||||
|
# MDEV-4029 SELECT on information_schema using a subquery locks up the information_schema table due to incorrect mutexes handling
|
||||||
|
#
|
||||||
|
select variable_name from information_schema.session_status where variable_name =
|
||||||
|
(select variable_name from information_schema.session_status where variable_name = 'uptime');
|
||||||
|
select variable_name from information_schema.session_variables where variable_name =
|
||||||
|
(select variable_name from information_schema.session_variables where variable_name = 'basedir');
|
||||||
|
|
@ -63,5 +63,22 @@ SELECT SUM(DISTINCT id) sm FROM t1;
|
|||||||
SELECT SUM(DISTINCT id) sm FROM t2;
|
SELECT SUM(DISTINCT id) sm FROM t2;
|
||||||
SELECT SUM(DISTINCT id) sm FROM t1 GROUP BY id % 13;
|
SELECT SUM(DISTINCT id) sm FROM t1 GROUP BY id % 13;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug mdev-4063: SUM(DISTINCT...) with small'max_heap_table_size
|
||||||
|
--echo # (bug #56927)
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET max_heap_table_size=default;
|
||||||
|
|
||||||
|
INSERT INTO t1 SELECT id+16384 FROM t1;
|
||||||
|
DELETE FROM t2;
|
||||||
|
INSERT INTO t2 SELECT id FROM t1 ORDER BY id*rand();
|
||||||
|
|
||||||
|
SELECT SUM(DISTINCT id) sm FROM t2;
|
||||||
|
|
||||||
|
SET max_heap_table_size=16384;
|
||||||
|
|
||||||
|
SELECT SUM(DISTINCT id) sm FROM t2;
|
||||||
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
DROP TABLE t2;
|
DROP TABLE t2;
|
||||||
|
@ -1085,7 +1085,7 @@ void Item_sum_distinct::calculate_val_and_count()
|
|||||||
if (tree)
|
if (tree)
|
||||||
{
|
{
|
||||||
table->field[0]->set_notnull();
|
table->field[0]->set_notnull();
|
||||||
tree->walk(item_sum_distinct_walk, (void*) this);
|
tree->walk(table, item_sum_distinct_walk, (void*) this);
|
||||||
}
|
}
|
||||||
is_evaluated= TRUE;
|
is_evaluated= TRUE;
|
||||||
}
|
}
|
||||||
@ -2584,7 +2584,7 @@ longlong Item_sum_count_distinct::val_int()
|
|||||||
if (tree->elements == 0)
|
if (tree->elements == 0)
|
||||||
return (longlong) tree->elements_in_tree(); // everything fits in memory
|
return (longlong) tree->elements_in_tree(); // everything fits in memory
|
||||||
count= 0;
|
count= 0;
|
||||||
tree->walk(count_distinct_walk, (void*) &count);
|
tree->walk(table, count_distinct_walk, (void*) &count);
|
||||||
is_evaluated= TRUE;
|
is_evaluated= TRUE;
|
||||||
return (longlong) count;
|
return (longlong) count;
|
||||||
}
|
}
|
||||||
|
@ -3068,6 +3068,8 @@ class Unique :public Sql_alloc
|
|||||||
bool flush();
|
bool flush();
|
||||||
uint size;
|
uint size;
|
||||||
|
|
||||||
|
bool merge(TABLE *table, uchar *buff, bool without_last_merge);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ulong elements;
|
ulong elements;
|
||||||
Unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg,
|
Unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg,
|
||||||
@ -3095,7 +3097,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
bool walk(tree_walk_action action, void *walk_action_arg);
|
bool walk(TABLE *table, tree_walk_action action, void *walk_action_arg);
|
||||||
|
|
||||||
uint get_size() const { return size; }
|
uint get_size() const { return size; }
|
||||||
ulonglong get_max_in_memory_size() const { return max_in_memory_size; }
|
ulonglong get_max_in_memory_size() const { return max_in_memory_size; }
|
||||||
|
@ -2334,7 +2334,6 @@ static bool show_status_array(THD *thd, const char *wild,
|
|||||||
int len;
|
int len;
|
||||||
LEX_STRING null_lex_str;
|
LEX_STRING null_lex_str;
|
||||||
SHOW_VAR tmp, *var;
|
SHOW_VAR tmp, *var;
|
||||||
COND *partial_cond= 0;
|
|
||||||
enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
|
enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
|
||||||
bool res= FALSE;
|
bool res= FALSE;
|
||||||
CHARSET_INFO *charset= system_charset_info;
|
CHARSET_INFO *charset= system_charset_info;
|
||||||
@ -2348,7 +2347,6 @@ static bool show_status_array(THD *thd, const char *wild,
|
|||||||
if (*prefix)
|
if (*prefix)
|
||||||
*prefix_end++= '_';
|
*prefix_end++= '_';
|
||||||
len=name_buffer + sizeof(name_buffer) - prefix_end;
|
len=name_buffer + sizeof(name_buffer) - prefix_end;
|
||||||
partial_cond= make_cond_for_info_schema(cond, table->pos_in_table_list);
|
|
||||||
|
|
||||||
for (; variables->name; variables++)
|
for (; variables->name; variables++)
|
||||||
{
|
{
|
||||||
@ -2371,13 +2369,13 @@ static bool show_status_array(THD *thd, const char *wild,
|
|||||||
if (show_type == SHOW_ARRAY)
|
if (show_type == SHOW_ARRAY)
|
||||||
{
|
{
|
||||||
show_status_array(thd, wild, (SHOW_VAR *) var->value, value_type,
|
show_status_array(thd, wild, (SHOW_VAR *) var->value, value_type,
|
||||||
status_var, name_buffer, table, ucase_names, partial_cond);
|
status_var, name_buffer, table, ucase_names, cond);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!(wild && wild[0] && wild_case_compare(system_charset_info,
|
if (!(wild && wild[0] && wild_case_compare(system_charset_info,
|
||||||
name_buffer, wild)) &&
|
name_buffer, wild)) &&
|
||||||
(!partial_cond || partial_cond->val_int()))
|
(!cond || cond->val_int()))
|
||||||
{
|
{
|
||||||
char *value=var->value;
|
char *value=var->value;
|
||||||
const char *pos, *end; // We assign a lot of const's
|
const char *pos, *end; // We assign a lot of const's
|
||||||
@ -5953,9 +5951,12 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||||||
schema_table_idx == SCH_GLOBAL_VARIABLES)
|
schema_table_idx == SCH_GLOBAL_VARIABLES)
|
||||||
option_type= OPT_GLOBAL;
|
option_type= OPT_GLOBAL;
|
||||||
|
|
||||||
|
COND *partial_cond= make_cond_for_info_schema(cond, tables);
|
||||||
|
|
||||||
rw_rdlock(&LOCK_system_variables_hash);
|
rw_rdlock(&LOCK_system_variables_hash);
|
||||||
res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars),
|
res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars),
|
||||||
option_type, NULL, "", tables->table, upper_case_names, cond);
|
option_type, NULL, "", tables->table, upper_case_names,
|
||||||
|
partial_cond);
|
||||||
rw_unlock(&LOCK_system_variables_hash);
|
rw_unlock(&LOCK_system_variables_hash);
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
@ -5992,13 +5993,18 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||||||
tmp1= &thd->status_var;
|
tmp1= &thd->status_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COND *partial_cond= make_cond_for_info_schema(cond, tables);
|
||||||
|
// Evaluate and cache const subqueries now, before the mutex.
|
||||||
|
if (partial_cond)
|
||||||
|
partial_cond->val_int();
|
||||||
|
|
||||||
pthread_mutex_lock(&LOCK_status);
|
pthread_mutex_lock(&LOCK_status);
|
||||||
if (option_type == OPT_GLOBAL)
|
if (option_type == OPT_GLOBAL)
|
||||||
calc_sum_of_all_status(&tmp);
|
calc_sum_of_all_status(&tmp);
|
||||||
res= show_status_array(thd, wild,
|
res= show_status_array(thd, wild,
|
||||||
(SHOW_VAR *)all_status_vars.buffer,
|
(SHOW_VAR *)all_status_vars.buffer,
|
||||||
option_type, tmp1, "", tables->table,
|
option_type, tmp1, "", tables->table,
|
||||||
upper_case_names, cond);
|
upper_case_names, partial_cond);
|
||||||
pthread_mutex_unlock(&LOCK_status);
|
pthread_mutex_unlock(&LOCK_status);
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
174
sql/uniques.cc
174
sql/uniques.cc
@ -538,6 +538,7 @@ end:
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
Unique:walk()
|
Unique:walk()
|
||||||
All params are 'IN':
|
All params are 'IN':
|
||||||
|
table parameter for the call of the merge method
|
||||||
action function-visitor, typed in include/my_tree.h
|
action function-visitor, typed in include/my_tree.h
|
||||||
function is called for each unique element
|
function is called for each unique element
|
||||||
arg argument for visitor, which is passed to it on each call
|
arg argument for visitor, which is passed to it on each call
|
||||||
@ -546,30 +547,117 @@ end:
|
|||||||
<> 0 error
|
<> 0 error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool Unique::walk(tree_walk_action action, void *walk_action_arg)
|
bool Unique::walk(TABLE *table, tree_walk_action action, void *walk_action_arg)
|
||||||
{
|
{
|
||||||
int res;
|
int res= 0;
|
||||||
uchar *merge_buffer;
|
uchar *merge_buffer;
|
||||||
|
|
||||||
if (elements == 0) /* the whole tree is in memory */
|
if (elements == 0) /* the whole tree is in memory */
|
||||||
return tree_walk(&tree, action, walk_action_arg, left_root_right);
|
return tree_walk(&tree, action, walk_action_arg, left_root_right);
|
||||||
|
|
||||||
|
table->sort.found_records=elements+tree.elements_in_tree;
|
||||||
/* flush current tree to the file to have some memory for merge buffer */
|
/* flush current tree to the file to have some memory for merge buffer */
|
||||||
if (flush())
|
if (flush())
|
||||||
return 1;
|
return 1;
|
||||||
if (flush_io_cache(&file) || reinit_io_cache(&file, READ_CACHE, 0L, 0, 0))
|
if (flush_io_cache(&file) || reinit_io_cache(&file, READ_CACHE, 0L, 0, 0))
|
||||||
return 1;
|
return 1;
|
||||||
if (!(merge_buffer= (uchar *) my_malloc((ulong) max_in_memory_size, MYF(0))))
|
ulong buff_sz= (max_in_memory_size / size + 1) * size;
|
||||||
|
if (!(merge_buffer= (uchar *) my_malloc((ulong) buff_sz, MYF(0))))
|
||||||
return 1;
|
return 1;
|
||||||
res= merge_walk(merge_buffer, (ulong) max_in_memory_size, size,
|
if (buff_sz < (ulong) (size * (file_ptrs.elements + 1)))
|
||||||
(BUFFPEK *) file_ptrs.buffer,
|
res= merge(table, merge_buffer, buff_sz >= size * MERGEBUFF2) ;
|
||||||
(BUFFPEK *) file_ptrs.buffer + file_ptrs.elements,
|
|
||||||
action, walk_action_arg,
|
if (!res)
|
||||||
tree.compare, tree.custom_arg, &file);
|
{
|
||||||
|
res= merge_walk(merge_buffer, (ulong) max_in_memory_size, size,
|
||||||
|
(BUFFPEK *) file_ptrs.buffer,
|
||||||
|
(BUFFPEK *) file_ptrs.buffer + file_ptrs.elements,
|
||||||
|
action, walk_action_arg,
|
||||||
|
tree.compare, tree.custom_arg, &file);
|
||||||
|
}
|
||||||
my_free((char*) merge_buffer, MYF(0));
|
my_free((char*) merge_buffer, MYF(0));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
DESCRIPTION
|
||||||
|
Perform multi-pass sort merge of the elements accessed through table->sort,
|
||||||
|
using the buffer buff as the merge buffer. The last pass is not performed
|
||||||
|
if without_last_merge is TRUE.
|
||||||
|
SYNOPSIS
|
||||||
|
Unique:merge()
|
||||||
|
All params are 'IN':
|
||||||
|
table the parameter to access sort context
|
||||||
|
buff merge buffer
|
||||||
|
without_last_merge TRUE <=> do not perform the last merge
|
||||||
|
RETURN VALUE
|
||||||
|
0 OK
|
||||||
|
<> 0 error
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool Unique::merge(TABLE *table, uchar *buff, bool without_last_merge)
|
||||||
|
{
|
||||||
|
SORTPARAM sort_param;
|
||||||
|
IO_CACHE *outfile= table->sort.io_cache;
|
||||||
|
BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer;
|
||||||
|
uint maxbuffer= file_ptrs.elements - 1;
|
||||||
|
my_off_t save_pos;
|
||||||
|
bool error= 1;
|
||||||
|
|
||||||
|
/* Open cached file if it isn't open */
|
||||||
|
if (!outfile)
|
||||||
|
outfile= table->sort.io_cache= (IO_CACHE*) my_malloc(sizeof(IO_CACHE),
|
||||||
|
MYF(MY_ZEROFILL));
|
||||||
|
if (!outfile ||
|
||||||
|
(! my_b_inited(outfile) &&
|
||||||
|
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
|
||||||
|
MYF(MY_WME))))
|
||||||
|
return 1;
|
||||||
|
reinit_io_cache(outfile,WRITE_CACHE,0L,0,0);
|
||||||
|
|
||||||
|
bzero((char*) &sort_param,sizeof(sort_param));
|
||||||
|
sort_param.max_rows= elements;
|
||||||
|
sort_param.sort_form= table;
|
||||||
|
sort_param.rec_length= sort_param.sort_length= sort_param.ref_length=
|
||||||
|
size;
|
||||||
|
sort_param.keys= (uint) (max_in_memory_size / sort_param.sort_length);
|
||||||
|
sort_param.not_killable= 1;
|
||||||
|
|
||||||
|
sort_param.unique_buff= buff + (sort_param.keys * sort_param.sort_length);
|
||||||
|
|
||||||
|
sort_param.compare= (qsort2_cmp) buffpek_compare;
|
||||||
|
sort_param.cmp_context.key_compare= tree.compare;
|
||||||
|
sort_param.cmp_context.key_compare_arg= tree.custom_arg;
|
||||||
|
|
||||||
|
/* Merge the buffers to one file, removing duplicates */
|
||||||
|
if (merge_many_buff(&sort_param,buff,file_ptr,&maxbuffer,&file))
|
||||||
|
goto err;
|
||||||
|
if (flush_io_cache(&file) ||
|
||||||
|
reinit_io_cache(&file,READ_CACHE,0L,0,0))
|
||||||
|
goto err;
|
||||||
|
if (without_last_merge)
|
||||||
|
{
|
||||||
|
file_ptrs.elements= maxbuffer+1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (merge_buffers(&sort_param, &file, outfile, buff, file_ptr,
|
||||||
|
file_ptr, file_ptr+maxbuffer,0))
|
||||||
|
goto err;
|
||||||
|
error= 0;
|
||||||
|
err:
|
||||||
|
if (flush_io_cache(outfile))
|
||||||
|
error= 1;
|
||||||
|
|
||||||
|
/* Setup io_cache for reading */
|
||||||
|
save_pos= outfile->pos_in_file;
|
||||||
|
if (reinit_io_cache(outfile,READ_CACHE,0L,0,0))
|
||||||
|
error= 1;
|
||||||
|
outfile->end_of_file=save_pos;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Modify the TABLE element so that when one calls init_records()
|
Modify the TABLE element so that when one calls init_records()
|
||||||
the rows will be read in priority order.
|
the rows will be read in priority order.
|
||||||
@ -577,8 +665,9 @@ bool Unique::walk(tree_walk_action action, void *walk_action_arg)
|
|||||||
|
|
||||||
bool Unique::get(TABLE *table)
|
bool Unique::get(TABLE *table)
|
||||||
{
|
{
|
||||||
SORTPARAM sort_param;
|
bool rc= 1;
|
||||||
table->sort.found_records=elements+tree.elements_in_tree;
|
uchar *sort_buffer= NULL;
|
||||||
|
table->sort.found_records= elements+tree.elements_in_tree;
|
||||||
|
|
||||||
if (my_b_tell(&file) == 0)
|
if (my_b_tell(&file) == 0)
|
||||||
{
|
{
|
||||||
@ -594,63 +683,16 @@ bool Unique::get(TABLE *table)
|
|||||||
/* Not enough memory; Save the result to file && free memory used by tree */
|
/* Not enough memory; Save the result to file && free memory used by tree */
|
||||||
if (flush())
|
if (flush())
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
IO_CACHE *outfile=table->sort.io_cache;
|
ulong buff_sz= (max_in_memory_size / size + 1) * size;
|
||||||
BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer;
|
if (!(sort_buffer= (uchar*) my_malloc(buff_sz, MYF(0))))
|
||||||
uint maxbuffer= file_ptrs.elements - 1;
|
|
||||||
uchar *sort_buffer;
|
|
||||||
my_off_t save_pos;
|
|
||||||
bool error=1;
|
|
||||||
|
|
||||||
/* Open cached file if it isn't open */
|
|
||||||
outfile=table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
|
|
||||||
MYF(MY_ZEROFILL));
|
|
||||||
|
|
||||||
if (!outfile ||
|
|
||||||
(! my_b_inited(outfile) &&
|
|
||||||
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
|
|
||||||
MYF(MY_WME))))
|
|
||||||
return 1;
|
return 1;
|
||||||
reinit_io_cache(outfile,WRITE_CACHE,0L,0,0);
|
|
||||||
|
|
||||||
bzero((char*) &sort_param,sizeof(sort_param));
|
if (merge(table, sort_buffer, FALSE))
|
||||||
sort_param.max_rows= elements;
|
goto err;
|
||||||
sort_param.sort_form=table;
|
rc= 0;
|
||||||
sort_param.rec_length= sort_param.sort_length= sort_param.ref_length=
|
|
||||||
size;
|
|
||||||
sort_param.keys= (uint) (max_in_memory_size / sort_param.sort_length);
|
|
||||||
sort_param.not_killable=1;
|
|
||||||
|
|
||||||
if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) *
|
err:
|
||||||
sort_param.sort_length,
|
x_free(sort_buffer);
|
||||||
MYF(0))))
|
return rc;
|
||||||
return 1;
|
|
||||||
sort_param.unique_buff= sort_buffer+(sort_param.keys*
|
|
||||||
sort_param.sort_length);
|
|
||||||
|
|
||||||
sort_param.compare= (qsort2_cmp) buffpek_compare;
|
|
||||||
sort_param.cmp_context.key_compare= tree.compare;
|
|
||||||
sort_param.cmp_context.key_compare_arg= tree.custom_arg;
|
|
||||||
|
|
||||||
/* Merge the buffers to one file, removing duplicates */
|
|
||||||
if (merge_many_buff(&sort_param,sort_buffer,file_ptr,&maxbuffer,&file))
|
|
||||||
goto err;
|
|
||||||
if (flush_io_cache(&file) ||
|
|
||||||
reinit_io_cache(&file,READ_CACHE,0L,0,0))
|
|
||||||
goto err;
|
|
||||||
if (merge_buffers(&sort_param, &file, outfile, sort_buffer, file_ptr,
|
|
||||||
file_ptr, file_ptr+maxbuffer,0))
|
|
||||||
goto err;
|
|
||||||
error=0;
|
|
||||||
err:
|
|
||||||
x_free(sort_buffer);
|
|
||||||
if (flush_io_cache(outfile))
|
|
||||||
error=1;
|
|
||||||
|
|
||||||
/* Setup io_cache for reading */
|
|
||||||
save_pos=outfile->pos_in_file;
|
|
||||||
if (reinit_io_cache(outfile,READ_CACHE,0L,0,0))
|
|
||||||
error=1;
|
|
||||||
outfile->end_of_file=save_pos;
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user