Commit 0e8ccc1b authored by tomas@poseidon.ndb.mysql.com's avatar tomas@poseidon.ndb.mysql.com

Merge tulin@bk-internal.mysql.com:/home/bk/mysql-5.1-new

into  poseidon.ndb.mysql.com:/home/tomas/mysql-5.1-new
parents fc387e73 e0c68bff
...@@ -3580,7 +3580,7 @@ sub valgrind_arguments { ...@@ -3580,7 +3580,7 @@ sub valgrind_arguments {
if ( $opt_valgrind_options ) if ( $opt_valgrind_options )
{ {
mtr_add_arg($args, split(' ', $opt_valgrind_options)); mtr_add_arg($args, '%s', $_) for (split(' ', $opt_valgrind_options));
} }
......
...@@ -175,6 +175,14 @@ SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END; ...@@ -175,6 +175,14 @@ SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END;
case+union+test case+union+test
case+union+test case+union+test
nobug nobug
create table t1(a float, b int default 3);
insert into t1 (a) values (2), (11), (8);
select min(a), min(case when 1=1 then a else NULL end),
min(case when 1!=1 then NULL else a end)
from t1 where b=3 group by b;
min(a) min(case when 1=1 then a else NULL end) min(case when 1!=1 then NULL else a end)
2 2 2
drop table t1;
CREATE TABLE t1 (EMPNUM INT); CREATE TABLE t1 (EMPNUM INT);
INSERT INTO t1 VALUES (0), (2); INSERT INTO t1 VALUES (0), (2);
CREATE TABLE t2 (EMPNUM DECIMAL (4, 2)); CREATE TABLE t2 (EMPNUM DECIMAL (4, 2));
......
...@@ -43,7 +43,7 @@ SLEEP(3) ...@@ -43,7 +43,7 @@ SLEEP(3)
0 0
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log; SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text user_host query_time db sql_text
root[root] @ localhost [] 00:00:03 events_test SELECT SLEEP(3) root[root] @ localhost [] SLEEPVAL events_test SELECT SLEEP(3)
TRUNCATE mysql.slow_log; TRUNCATE mysql.slow_log;
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint); CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
"This won't go to the slow log" "This won't go to the slow log"
...@@ -75,7 +75,7 @@ slo_val val ...@@ -75,7 +75,7 @@ slo_val val
"Check slow log. Should see 1 row because 5 is over the threshold of 4 for GLOBAL, though under SESSION which is 10" "Check slow log. Should see 1 row because 5 is over the threshold of 4 for GLOBAL, though under SESSION which is 10"
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log; SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text user_host query_time db sql_text
root[root] @ localhost [localhost] 00:00:05 events_test INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(5) root[root] @ localhost [localhost] SLEEPVAL events_test INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(5)
DROP EVENT long_event2; DROP EVENT long_event2;
SET GLOBAL long_query_time =@old_global_long_query_time; SET GLOBAL long_query_time =@old_global_long_query_time;
SET SESSION long_query_time =@old_session_long_query_time; SET SESSION long_query_time =@old_session_long_query_time;
......
...@@ -4,7 +4,9 @@ CREATE TABLE table_1(a int); ...@@ -4,7 +4,9 @@ CREATE TABLE table_1(a int);
CREATE TABLE table_2(a int); CREATE TABLE table_2(a int);
CREATE TABLE table_3(a int); CREATE TABLE table_3(a int);
CREATE TABLE table_4(a int); CREATE TABLE table_4(a int);
CREATE TABLE T19170(s1 TIMESTAMP);
SET GLOBAL event_scheduler=1; SET GLOBAL event_scheduler=1;
CREATE EVENT E19170 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO T19170 VALUES(CURRENT_TIMESTAMP);
CREATE EVENT two_sec ON SCHEDULE EVERY 2 SECOND DO INSERT INTO table_1 VALUES(1); CREATE EVENT two_sec ON SCHEDULE EVERY 2 SECOND DO INSERT INTO table_1 VALUES(1);
CREATE EVENT start_n_end CREATE EVENT start_n_end
ON SCHEDULE EVERY 1 SECOND ON SCHEDULE EVERY 1 SECOND
...@@ -29,8 +31,8 @@ DROP EVENT two_sec; ...@@ -29,8 +31,8 @@ DROP EVENT two_sec;
SELECT IF(TIME_TO_SEC(TIMEDIFF(ENDS,STARTS))=6, 'OK', 'ERROR') FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='start_n_end' AND ENDS IS NOT NULL; SELECT IF(TIME_TO_SEC(TIMEDIFF(ENDS,STARTS))=6, 'OK', 'ERROR') FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='start_n_end' AND ENDS IS NOT NULL;
IF(TIME_TO_SEC(TIMEDIFF(ENDS,STARTS))=6, 'OK', 'ERROR') IF(TIME_TO_SEC(TIMEDIFF(ENDS,STARTS))=6, 'OK', 'ERROR')
OK OK
SELECT IF(LAST_EXECUTED-ENDS < 2, 'OK', 'ERROR') FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='start_n_end' AND ENDS IS NOT NULL; SELECT IF(LAST_EXECUTED-ENDS < 3, 'OK', 'ERROR') FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='start_n_end' AND ENDS IS NOT NULL;
IF(LAST_EXECUTED-ENDS < 2, 'OK', 'ERROR') IF(LAST_EXECUTED-ENDS < 3, 'OK', 'ERROR')
OK OK
DROP EVENT start_n_end; DROP EVENT start_n_end;
"Already dropped because ended. Therefore an error." "Already dropped because ended. Therefore an error."
...@@ -43,4 +45,8 @@ DROP TABLE table_1; ...@@ -43,4 +45,8 @@ DROP TABLE table_1;
DROP TABLE table_2; DROP TABLE table_2;
DROP TABLE table_3; DROP TABLE table_3;
DROP TABLE table_4; DROP TABLE table_4;
"Checking for multiple executions in one second, should not happen -> 0 as result"
SELECT COUNT(*) FROM (SELECT s1, COUNT(*) AS cnt FROM T19170 GROUP BY s1) AS tmp WHERE tmp.cnt > 1;
COUNT(*)
0
DROP DATABASE events_test; DROP DATABASE events_test;
...@@ -72,3 +72,10 @@ set @@max_allowed_packet=1048576*100; ...@@ -72,3 +72,10 @@ set @@max_allowed_packet=1048576*100;
select compress(repeat('aaaaaaaaaa', IF(XXX, 10, 10000000))) is null; select compress(repeat('aaaaaaaaaa', IF(XXX, 10, 10000000))) is null;
compress(repeat('aaaaaaaaaa', IF(XXX, 10, 10000000))) is null compress(repeat('aaaaaaaaaa', IF(XXX, 10, 10000000))) is null
0 0
create table t1(a blob);
insert into t1 values(NULL), (compress('a'));
select uncompress(a), uncompressed_length(a) from t1;
uncompress(a) uncompressed_length(a)
NULL NULL
a 1
drop table t1;
...@@ -88,3 +88,17 @@ f ...@@ -88,3 +88,17 @@ f
1 1
drop temporary table t4; drop temporary table t4;
drop table t5; drop table t5;
set @session.pseudo_thread_id=100;
create temporary table t101 (id int);
create temporary table t102 (id int);
set @session.pseudo_thread_id=200;
create temporary table t201 (id int);
create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int);
set @con1_id=connection_id();
kill @con1_id;
create table t1(f int);
insert into t1 values (1);
select * from t1 /* must be 1 */;
f
1
drop table t1;
...@@ -122,6 +122,17 @@ SELECT 'case+union+test' ...@@ -122,6 +122,17 @@ SELECT 'case+union+test'
UNION UNION
SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END; SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END;
#
# Bug #17896: problem with MIN(CASE...)
#
create table t1(a float, b int default 3);
insert into t1 (a) values (2), (11), (8);
select min(a), min(case when 1=1 then a else NULL end),
min(case when 1!=1 then NULL else a end)
from t1 where b=3 group by b;
drop table t1;
# End of 4.1 tests # End of 4.1 tests
......
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
events_bugs : BUG#17619 2006-02-21 andrey Race conditions events_bugs : BUG#17619 2006-02-21 andrey Race conditions
events_stress : BUG#17619 2006-02-21 andrey Race conditions events_stress : BUG#17619 2006-02-21 andrey Race conditions
events : BUG#17619 2006-02-21 andrey Race conditions events : BUG#17619 2006-02-21 andrey Race conditions
events_scheduling : BUG#18958 2006-04-13 andrey Test case unstable
events_logs_tests : BUG#18953 2006-04-12 kent Test is randomly failing
ndb_autodiscover : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog ndb_autodiscover : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog
ndb_autodiscover2 : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog ndb_autodiscover2 : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog
#ndb_cache2 : BUG#18597 2006-03-28 brian simultaneous drop table and ndb statistics update triggers node failure #ndb_cache2 : BUG#18597 2006-03-28 brian simultaneous drop table and ndb statistics update triggers node failure
......
...@@ -56,6 +56,7 @@ SET GLOBAL long_query_time=4; ...@@ -56,6 +56,7 @@ SET GLOBAL long_query_time=4;
SET SESSION long_query_time=2; SET SESSION long_query_time=2;
--echo "Check that logging is working" --echo "Check that logging is working"
SELECT SLEEP(3); SELECT SLEEP(3);
--replace_regex /00:00:0[3-5]/SLEEPVAL/
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log; SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
TRUNCATE mysql.slow_log; TRUNCATE mysql.slow_log;
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint); CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
...@@ -79,6 +80,7 @@ CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_te ...@@ -79,6 +80,7 @@ CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_te
--echo "Check our table. Should see 2 rows" --echo "Check our table. Should see 2 rows"
SELECT * FROM slow_event_test; SELECT * FROM slow_event_test;
--echo "Check slow log. Should see 1 row because 5 is over the threshold of 4 for GLOBAL, though under SESSION which is 10" --echo "Check slow log. Should see 1 row because 5 is over the threshold of 4 for GLOBAL, though under SESSION which is 10"
--replace_regex /00:00:0[5-7]/SLEEPVAL/
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log; SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
DROP EVENT long_event2; DROP EVENT long_event2;
SET GLOBAL long_query_time =@old_global_long_query_time; SET GLOBAL long_query_time =@old_global_long_query_time;
......
...@@ -4,7 +4,9 @@ CREATE TABLE table_1(a int); ...@@ -4,7 +4,9 @@ CREATE TABLE table_1(a int);
CREATE TABLE table_2(a int); CREATE TABLE table_2(a int);
CREATE TABLE table_3(a int); CREATE TABLE table_3(a int);
CREATE TABLE table_4(a int); CREATE TABLE table_4(a int);
CREATE TABLE T19170(s1 TIMESTAMP);
SET GLOBAL event_scheduler=1; SET GLOBAL event_scheduler=1;
CREATE EVENT E19170 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO T19170 VALUES(CURRENT_TIMESTAMP);
CREATE EVENT two_sec ON SCHEDULE EVERY 2 SECOND DO INSERT INTO table_1 VALUES(1); CREATE EVENT two_sec ON SCHEDULE EVERY 2 SECOND DO INSERT INTO table_1 VALUES(1);
CREATE EVENT start_n_end CREATE EVENT start_n_end
ON SCHEDULE EVERY 1 SECOND ON SCHEDULE EVERY 1 SECOND
...@@ -21,7 +23,7 @@ SELECT IF(SUM(a) > 0, 'OK', 'ERROR') FROM table_3; ...@@ -21,7 +23,7 @@ SELECT IF(SUM(a) > 0, 'OK', 'ERROR') FROM table_3;
SELECT IF(SUM(a) > 0, 'OK', 'ERROR') FROM table_4; SELECT IF(SUM(a) > 0, 'OK', 'ERROR') FROM table_4;
DROP EVENT two_sec; DROP EVENT two_sec;
SELECT IF(TIME_TO_SEC(TIMEDIFF(ENDS,STARTS))=6, 'OK', 'ERROR') FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='start_n_end' AND ENDS IS NOT NULL; SELECT IF(TIME_TO_SEC(TIMEDIFF(ENDS,STARTS))=6, 'OK', 'ERROR') FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='start_n_end' AND ENDS IS NOT NULL;
SELECT IF(LAST_EXECUTED-ENDS < 2, 'OK', 'ERROR') FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='start_n_end' AND ENDS IS NOT NULL; SELECT IF(LAST_EXECUTED-ENDS < 3, 'OK', 'ERROR') FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA=DATABASE() AND EVENT_NAME='start_n_end' AND ENDS IS NOT NULL;
DROP EVENT start_n_end; DROP EVENT start_n_end;
--echo "Already dropped because ended. Therefore an error." --echo "Already dropped because ended. Therefore an error."
--error ER_EVENT_DOES_NOT_EXIST --error ER_EVENT_DOES_NOT_EXIST
...@@ -33,4 +35,6 @@ DROP TABLE table_1; ...@@ -33,4 +35,6 @@ DROP TABLE table_1;
DROP TABLE table_2; DROP TABLE table_2;
DROP TABLE table_3; DROP TABLE table_3;
DROP TABLE table_4; DROP TABLE table_4;
--echo "Checking for multiple executions in one second, should not happen -> 0 as result"
SELECT COUNT(*) FROM (SELECT s1, COUNT(*) AS cnt FROM T19170 GROUP BY s1) AS tmp WHERE tmp.cnt > 1;
DROP DATABASE events_test; DROP DATABASE events_test;
...@@ -47,4 +47,13 @@ set @@max_allowed_packet=1048576*100; ...@@ -47,4 +47,13 @@ set @@max_allowed_packet=1048576*100;
--replace_result "''" XXX "'1'" XXX --replace_result "''" XXX "'1'" XXX
eval select compress(repeat('aaaaaaaaaa', IF('$LOW_MEMORY', 10, 10000000))) is null; eval select compress(repeat('aaaaaaaaaa', IF('$LOW_MEMORY', 10, 10000000))) is null;
#
# Bug #18643: problem with null values
#
create table t1(a blob);
insert into t1 values(NULL), (compress('a'));
select uncompress(a), uncompressed_length(a) from t1;
drop table t1;
# End of 4.1 tests # End of 4.1 tests
...@@ -131,6 +131,8 @@ drop table t1,t2; ...@@ -131,6 +131,8 @@ drop table t1,t2;
create temporary table t3 (f int); create temporary table t3 (f int);
sync_with_master; sync_with_master;
# The server will now close done
# #
# Bug#17284 erroneous temp table cleanup on slave # Bug#17284 erroneous temp table cleanup on slave
# #
...@@ -156,5 +158,31 @@ connection master; ...@@ -156,5 +158,31 @@ connection master;
drop temporary table t4; drop temporary table t4;
drop table t5; drop table t5;
# The server will now close done #
# BUG#17263 incorrect generation DROP temp tables
# Temporary tables of connection are dropped in batches
# where a batch correspond to pseudo_thread_id
# value was set up at the moment of temp table creation
#
connection con1;
set @session.pseudo_thread_id=100;
create temporary table t101 (id int);
create temporary table t102 (id int);
set @session.pseudo_thread_id=200;
create temporary table t201 (id int);
create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int);
set @con1_id=connection_id();
kill @con1_id;
#now do something to show that slave is ok after DROP temp tables
connection master;
create table t1(f int);
insert into t1 values (1);
sync_slave_with_master;
#connection slave;
select * from t1 /* must be 1 */;
connection master;
drop table t1;
# End of 5.1 tests # End of 5.1 tests
...@@ -731,7 +731,9 @@ bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec, ...@@ -731,7 +731,9 @@ bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec,
get the next exec if the modulus is not get the next exec if the modulus is not
*/ */
DBUG_PRINT("info", ("multiplier=%d", multiplier)); DBUG_PRINT("info", ("multiplier=%d", multiplier));
if (seconds_diff % seconds || (!seconds_diff && last_exec->year)) if (seconds_diff % seconds || (!seconds_diff && last_exec->year) ||
TIME_to_ulonglong_datetime(time_now) ==
TIME_to_ulonglong_datetime(last_exec))
++multiplier; ++multiplier;
interval.second= seconds * multiplier; interval.second= seconds * multiplier;
DBUG_PRINT("info", ("multiplier=%u interval.second=%u", multiplier, DBUG_PRINT("info", ("multiplier=%u interval.second=%u", multiplier,
...@@ -893,16 +895,15 @@ Event_timed::compute_next_execution_time() ...@@ -893,16 +895,15 @@ Event_timed::compute_next_execution_time()
DBUG_PRINT("info", ("Both STARTS & ENDS are set")); DBUG_PRINT("info", ("Both STARTS & ENDS are set"));
if (!last_executed.year) if (!last_executed.year)
{ {
DBUG_PRINT("info", ("Not executed so far. Execute NOW.")); DBUG_PRINT("info", ("Not executed so far."));
execute_at= time_now;
execute_at_null= FALSE;
} }
else
{ {
TIME next_exec; TIME next_exec;
DBUG_PRINT("info", ("Executed at least once")); DBUG_PRINT("info", ("Executed at least once"));
if (get_next_time(&next_exec, &starts, &time_now, &last_executed, if (get_next_time(&next_exec, &starts, &time_now,
last_executed.year? &last_executed:&starts,
expression, interval)) expression, interval))
goto err; goto err;
...@@ -925,8 +926,9 @@ Event_timed::compute_next_execution_time() ...@@ -925,8 +926,9 @@ Event_timed::compute_next_execution_time()
} }
goto ret; goto ret;
} }
else if (starts_null && ends_null) else if (starts_null && ends_null)
{ {
/* starts is always set, so this is a dead branch !! */
DBUG_PRINT("info", ("Neither STARTS nor ENDS are set")); DBUG_PRINT("info", ("Neither STARTS nor ENDS are set"));
/* /*
Both starts and m_ends are not set, so we schedule for the next Both starts and m_ends are not set, so we schedule for the next
...@@ -961,25 +963,26 @@ Event_timed::compute_next_execution_time() ...@@ -961,25 +963,26 @@ Event_timed::compute_next_execution_time()
Hence schedule for starts + m_expression in case last_executed Hence schedule for starts + m_expression in case last_executed
is not set, otherwise to last_executed + m_expression is not set, otherwise to last_executed + m_expression
*/ */
if (last_executed.year) if (!last_executed.year)
{
DBUG_PRINT("info", ("Not executed so far."));
}
{ {
TIME next_exec; TIME next_exec;
DBUG_PRINT("info", ("Executed at least once.")); DBUG_PRINT("info", ("Executed at least once."));
if (get_next_time(&next_exec, &starts, &time_now, &last_executed, if (get_next_time(&next_exec, &starts, &time_now,
last_executed.year? &last_executed:&starts,
expression, interval)) expression, interval))
goto err; goto err;
execute_at= next_exec; execute_at= next_exec;
DBUG_PRINT("info",("Next[%llu]",TIME_to_ulonglong_datetime(&next_exec))); DBUG_PRINT("info",("Next[%llu]",TIME_to_ulonglong_datetime(&next_exec)));
} }
else
{
DBUG_PRINT("info", ("Not executed so far. Execute at STARTS"));
execute_at= starts;
}
execute_at_null= FALSE; execute_at_null= FALSE;
} }
else else
{ {
/* this is a dead branch, because starts is always set !!! */
DBUG_PRINT("info", ("STARTS is not set. ENDS is set")); DBUG_PRINT("info", ("STARTS is not set. ENDS is set"));
/* /*
- m_ends is set - m_ends is set
......
...@@ -41,10 +41,25 @@ static Item_result item_store_type(Item_result a,Item_result b) ...@@ -41,10 +41,25 @@ static Item_result item_store_type(Item_result a,Item_result b)
static void agg_result_type(Item_result *type, Item **items, uint nitems) static void agg_result_type(Item_result *type, Item **items, uint nitems)
{ {
uint i; Item **item, **item_end;
type[0]= items[0]->result_type();
for (i=1 ; i < nitems ; i++) *type= STRING_RESULT;
type[0]= item_store_type(type[0], items[i]->result_type()); /* Skip beginning NULL items */
for (item= items, item_end= item + nitems; item < item_end; item++)
{
if ((*item)->type() != Item::NULL_ITEM)
{
*type= (*item)->result_type();
item++;
break;
}
}
/* Combine result types. Note: NULL items don't affect the result */
for (; item < item_end; item++)
{
if ((*item)->type() != Item::NULL_ITEM)
*type= item_store_type(type[0], (*item)->result_type());
}
} }
......
...@@ -2941,6 +2941,7 @@ String *Item_func_uncompress::val_str(String *str) ...@@ -2941,6 +2941,7 @@ String *Item_func_uncompress::val_str(String *str)
if (!res) if (!res)
goto err; goto err;
null_value= 0;
if (res->is_empty()) if (res->is_empty())
return res; return res;
......
...@@ -1167,16 +1167,26 @@ bool close_thread_table(THD *thd, TABLE **table_ptr) ...@@ -1167,16 +1167,26 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
} }
/* close_temporary_tables' internal, 4 is due to uint4korr definition */
static inline uint tmpkeyval(THD *thd, TABLE *table)
{
return uint4korr(table->s->table_cache_key.str + table->s->table_cache_key.length - 4);
}
/* /*
Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
creates one DROP TEMPORARY TABLE binlog event for each pseudo-thread
*/ */
void close_temporary_tables(THD *thd) void close_temporary_tables(THD *thd)
{ {
TABLE *table,*next; TABLE *next,
char *query, *end; *prev_table /* prev link is not maintained in TABLE's double-linked list */,
uint query_buf_size; *table;
bool found_user_tables = 0; char *query= (gptr) 0, *end;
uint query_buf_size, max_names_len;
bool found_user_tables;
if (!thd->temporary_tables) if (!thd->temporary_tables)
return; return;
...@@ -1184,50 +1194,123 @@ void close_temporary_tables(THD *thd) ...@@ -1184,50 +1194,123 @@ void close_temporary_tables(THD *thd)
LINT_INIT(end); LINT_INIT(end);
query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS
for (table=thd->temporary_tables ; table ; table=table->next) /*
insertion sort of temp tables by pseudo_thread_id to build ordered list
of sublists of equal pseudo_thread_id
*/
for (prev_table= thd->temporary_tables,
table= prev_table->next,
found_user_tables= (prev_table->s->table_name.str[0] != '#');
table;
prev_table= table, table= table->next)
{ {
TABLE *prev_sorted /* same as for prev_table */,
*sorted;
/* /*
We are going to add 4 ` around the db/table names, so 1 does not look table not created directly by the user is moved to the tail.
enough; indeed it is enough, because table->table_cache_key.length is Fixme/todo: nothing (I checked the manual) prevents user to create temp
greater (by 8, because of server_id and thread_id) than db||table. with `#'
*/ */
query_buf_size+= table->s->table_cache_key.length+1; if (table->s->table_name.str[0] == '#')
continue;
else
{
found_user_tables = 1;
}
for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table;
prev_sorted= sorted, sorted= sorted->next)
{
if (sorted->s->table_name.str[0] == '#' || tmpkeyval(thd, sorted) > tmpkeyval(thd, table))
{
/* move into the sorted part of the list from the unsorted */
prev_table->next= table->next;
table->next= sorted;
if (prev_sorted)
{
prev_sorted->next= table;
}
else
{
thd->temporary_tables= table;
}
table= prev_table;
break;
}
}
}
/*
calc query_buf_size as max per sublists, one sublist per pseudo thread id.
Also stop at first occurence of `#'-named table that starts
all implicitly created temp tables
*/
for (max_names_len= 0, table=thd->temporary_tables;
table && table->s->table_name.str[0] != '#';
table=table->next)
{
uint tmp_names_len;
for (tmp_names_len= table->s->table_cache_key.length + 1;
table->next && table->s->table_name.str[0] != '#' &&
tmpkeyval(thd, table) == tmpkeyval(thd, table->next);
table=table->next)
{
/*
We are going to add 4 ` around the db/table names, so 1 might not look
enough; indeed it is enough, because table->s->table_cache_key.length is
greater (by 8, because of server_id and thread_id) than db||table.
*/
tmp_names_len += table->next->s->table_cache_key.length + 1;
}
if (tmp_names_len > max_names_len) max_names_len= tmp_names_len;
} }
if ((query = alloc_root(thd->mem_root, query_buf_size))) /* allocate */
if (found_user_tables && mysql_bin_log.is_open() &&
!thd->current_stmt_binlog_row_based &&
(query = alloc_root(thd->mem_root, query_buf_size+= max_names_len)))
// Better add "if exists", in case a RESET MASTER has been done // Better add "if exists", in case a RESET MASTER has been done
end=strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "); end= strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ");
for (table=thd->temporary_tables ; table ; table=next) /* scan sorted tmps to generate sequence of DROP */
for (table=thd->temporary_tables; table; table= next)
{ {
if (query) // we might be out of memory, but this is not fatal if (query // we might be out of memory, but this is not fatal
&& table->s->table_name.str[0] != '#')
{ {
// skip temporary tables not created directly by the user char *end_cur;
if (table->s->table_name.str[0] != '#') /* Set pseudo_thread_id to be that of the processed table */
found_user_tables = 1; thd->variables.pseudo_thread_id= tmpkeyval(thd, table);
end= strxmov(end, "`",table->s->db.str, "`.`", /* Loop forward through all tables within the sublist of
table->s->table_name.str, "`,", NullS); common pseudo_thread_id to create single DROP query */
for (end_cur= end;
table && table->s->table_name.str[0] != '#' &&
tmpkeyval(thd, table) == thd->variables.pseudo_thread_id;
table= next)
{
end_cur= strxmov(end_cur, "`", table->s->db.str, "`.`",
table->s->table_name.str, "`,", NullS);
next= table->next;
close_temporary(table, 1, 1);
}
thd->clear_error();
/* The -1 is to remove last ',' */
Query_log_event qinfo(thd, query, (ulong)(end_cur - query) - 1, 0, FALSE);
/*
Imagine the thread had created a temp table, then was doing a SELECT,
and the SELECT was killed. Then it's not clever to mark the statement
above as "killed", because it's not really a statement updating data,
and there are 99.99% chances it will succeed on slave. If a real update
(one updating a persistent table) was killed on the master, then this
real update will be logged with error_code=killed, rightfully causing
the slave to stop.
*/
qinfo.error_code= 0;
mysql_bin_log.write(&qinfo);
}
else
{
next= table->next;
close_temporary(table, 1, 1);
} }
next=table->next;
close_temporary(table, 1, 1);
}
if (query && found_user_tables && mysql_bin_log.is_open() &&
!thd->current_stmt_binlog_row_based) // CREATE TEMP TABLE not binlogged if row-based
{
/* The -1 is to remove last ',' */
thd->clear_error();
Query_log_event qinfo(thd, query, (ulong)(end-query)-1, 0, FALSE);
/*
Imagine the thread had created a temp table, then was doing a SELECT, and
the SELECT was killed. Then it's not clever to mark the statement above
as "killed", because it's not really a statement updating data, and there
are 99.99% chances it will succeed on slave.
If a real update (one updating a persistent table) was killed on the
master, then this real update will be logged with error_code=killed,
rightfully causing the slave to stop.
*/
qinfo.error_code= 0;
mysql_bin_log.write(&qinfo);
} }
thd->temporary_tables=0; thd->temporary_tables=0;
} }
......
...@@ -34,20 +34,20 @@ static uint lengths[256]; ...@@ -34,20 +34,20 @@ static uint lengths[256];
static struct my_option my_long_options[] = static struct my_option my_long_options[] =
{ {
{"dump", 'd', "Dump index (incl. data offsets and word weights).", {"help", 'h', "Display help and exit.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"stats", 's', "Report global stats.", {"help", '?', "Synonym for -h.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"verbose", 'v', "Be verbose.",
(gptr*) &verbose, (gptr*) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"count", 'c', "Calculate per-word stats (counts and global weights).", {"count", 'c', "Calculate per-word stats (counts and global weights).",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"length", 'l', "Report length distribution.", {"dump", 'd', "Dump index (incl. data offsets and word weights).",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"help", 'h', "Display help and exit.", {"length", 'l', "Report length distribution.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"help", '?', "Synonym for -h.", {"stats", 's', "Report global stats.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"verbose", 'v', "Be verbose.",
(gptr*) &verbose, (gptr*) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 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