Commit c90ae2d2 authored by aelkin@mysql.com's avatar aelkin@mysql.com

Merge mysql.com:/usr_rh9/home/elkin.rh9/4.1

into  mysql.com:/usr_rh9/home/elkin.rh9/MySQL/Merge/5.0
parents 98b81c4f 27696712
...@@ -189,4 +189,9 @@ HEX(f) ...@@ -189,4 +189,9 @@ HEX(f)
select HEX(f) from t4; select HEX(f) from t4;
HEX(f) HEX(f)
835C 835C
drop table t1, t2, t03, t04, t3, t4; flush logs;
select * from t5 /* must be (1),(1) */;
a
1
1
drop table t1, t2, t03, t04, t3, t4, t5;
...@@ -122,9 +122,17 @@ select HEX(f) from t3; ...@@ -122,9 +122,17 @@ select HEX(f) from t3;
select HEX(f) from t04; select HEX(f) from t04;
select HEX(f) from t4; select HEX(f) from t4;
#
#14157: utf8 encoding in binlog without set character_set_client
#
flush logs;
--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table ` ` (a int); insert into ` ` values (1); insert into t5 select * from ` `'
# resulted log is client charset insensitive (latin1 not koi8r) as it must be
--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1
select * from t5 /* must be (1),(1) */;
# clean up # clean up
drop table t1, t2, t03, t04, t3, t4; drop table t1, t2, t03, t04, t3, t4, t5;
# End of 4.1 tests # End of 4.1 tests
...@@ -163,24 +163,19 @@ drop table t5; ...@@ -163,24 +163,19 @@ drop table t5;
# value was set up at the moment of temp table creation # value was set up at the moment of temp table creation
# #
connection con1; connection con1;
set @session.pseudo_thread_id=100; set @@session.pseudo_thread_id=100;
create temporary table t101 (id int); create temporary table t101 (id int);
create temporary table t102 (id int); create temporary table t102 (id int);
set @session.pseudo_thread_id=200; set @@session.pseudo_thread_id=200;
create temporary table t201 (id int); create temporary table t201 (id int);
create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); create temporary table `t``201` (id int);
# emulate internal temp table not to come to binlog
# create temporary table `#sql_not_user_table202` (id int);
# Don't kill our own connection to the server as set @@session.pseudo_thread_id=300;
# the result code differs depending on platform. create temporary table t301 (id int);
# create temporary table t302 (id int);
# Select the id to kill into a variable of mysqltest create temporary table `#sql_not_user_table303` (id int);
let $con1_id= `select connection_id()`; disconnect con1;
# Switch connection to avoid killing our own connection
connection master;
--disable_query_log
eval kill $con1_id;
--enable_query_log
#now do something to show that slave is ok after DROP temp tables #now do something to show that slave is ok after DROP temp tables
connection master; connection master;
...@@ -194,4 +189,16 @@ select * from t1 /* must be 1 */; ...@@ -194,4 +189,16 @@ select * from t1 /* must be 1 */;
connection master; connection master;
drop table t1; drop table t1;
#
#14157: utf8 encoding in binlog without set character_set_client
#
--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `ÔÏÌØËÏ ÇÅÒÏÉ ÓÒÅÚÁÀÔ ÒÁÛÐÉÌÅÍ ÇÒÉÍ` (a int); insert into `ÔÏÌØËÏ ÇÅÒÏÉ ÓÒÅÚÁÀÔ ÒÁÛÐÉÌÅÍ ÇÒÉÍ` values (1); insert into t1 select * from `ÔÏÌØËÏ ÇÅÒÏÉ ÓÒÅÚÁÀÔ ÒÁÛÐÉÌÅÍ ÇÒÉÍ`'
sync_slave_with_master;
#connection slave;
select * from t1;
connection master;
drop table t1;
# End of 5.0 tests # End of 5.0 tests
...@@ -1582,6 +1582,29 @@ inline int hexchar_to_int(char c) ...@@ -1582,6 +1582,29 @@ inline int hexchar_to_int(char c)
return -1; return -1;
} }
/*
wrapper to use instead of mysql_bin_log.write when
query is generated by the server using system_charset encoding
*/
inline void write_binlog_with_system_charset(THD * thd, Query_log_event * qinfo)
{
CHARSET_INFO * cs_save= thd->variables.character_set_client;
thd->variables.character_set_client= system_charset_info;
mysql_bin_log.write(qinfo);
thd->variables.character_set_client= cs_save;
}
/*
is_user_table()
return true if the table was created explicitly
*/
inline bool is_user_table(TABLE * table)
{
const char *name= table->real_name;
return strncmp(name, tmp_file_prefix, tmp_file_prefix_length);
}
/* /*
Some functions that are different in the embedded library and the normal Some functions that are different in the embedded library and the normal
......
...@@ -617,118 +617,107 @@ static inline uint tmpkeyval(THD *thd, TABLE *table) ...@@ -617,118 +617,107 @@ static inline uint tmpkeyval(THD *thd, TABLE *table)
void close_temporary_tables(THD *thd) void close_temporary_tables(THD *thd)
{ {
TABLE *next, TABLE *table;
*prev_table /* prev link is not maintained in TABLE's double-linked list */,
*table;
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;
LINT_INIT(end); if (!mysql_bin_log.is_open())
query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS {
for (table= thd->temporary_tables; table; table= table->next)
{
close_temporary(table, 1);
}
thd->temporary_tables= 0;
return;
}
TABLE *next,
*prev_table /* prev link is not maintained in TABLE's double-linked list */;
bool was_quote_show= true; /* to assume thd->options has OPTION_QUOTE_SHOW_CREATE */
// Better add "if exists", in case a RESET MASTER has been done
const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ";
uint stub_len= sizeof(stub) - 1;
char buf[256];
memcpy(buf, stub, stub_len);
String s_query= String(buf, sizeof(buf), system_charset_info);
bool found_user_tables= false;
LINT_INIT(next);
/* /*
insertion sort of temp tables by pseudo_thread_id to build ordered list insertion sort of temp tables by pseudo_thread_id to build ordered list
of sublists of equal pseudo_thread_id of sublists of equal pseudo_thread_id
*/ */
for (prev_table= thd->temporary_tables,
table= prev_table->next, for (prev_table= thd->temporary_tables, table= prev_table->next;
found_user_tables= (prev_table->s->table_name[0] != '#');
table; table;
prev_table= table, table= table->next) prev_table= table, table= table->next)
{ {
TABLE *prev_sorted /* same as for prev_table */, TABLE *prev_sorted /* same as for prev_table */, *sorted;
*sorted; if (is_user_table(table))
/*
table not created directly by the user is moved to the tail.
Fixme/todo: nothing (I checked the manual) prevents user to create temp
with `#'
*/
if (table->s->table_name[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[0] == '#' || tmpkeyval(thd, sorted) > tmpkeyval(thd, table)) if (!found_user_tables)
found_user_tables= true;
for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table;
prev_sorted= sorted, sorted= sorted->next)
{ {
/* move into the sorted part of the list from the unsorted */ if (!is_user_table(sorted) ||
prev_table->next= table->next; tmpkeyval(thd, sorted) > tmpkeyval(thd, table))
table->next= sorted;
if (prev_sorted)
{ {
prev_sorted->next= table; /* move into the sorted part of the list from the unsorted */
} prev_table->next= table->next;
else table->next= sorted;
{ if (prev_sorted)
thd->temporary_tables= table; {
prev_sorted->next= table;
}
else
{
thd->temporary_tables= table;
}
table= prev_table;
break;
} }
table= prev_table;
break;
} }
} }
} }
/*
calc query_buf_size as max per sublists, one sublist per pseudo thread id. /* We always quote db,table names though it is slight overkill */
Also stop at first occurence of `#'-named table that starts if (found_user_tables &&
all implicitly created temp tables !(was_quote_show= (thd->options & OPTION_QUOTE_SHOW_CREATE)))
*/
for (max_names_len= 0, table=thd->temporary_tables;
table && table->s->table_name[0] != '#';
table=table->next)
{ {
uint tmp_names_len; thd->options |= OPTION_QUOTE_SHOW_CREATE;
for (tmp_names_len= table->s->key_length + 1;
table->next && table->s->table_name[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->key_length is greater (by 8,
because of server_id and thread_id) than db||table.
*/
tmp_names_len += table->next->s->key_length + 1;
}
if (tmp_names_len > max_names_len) max_names_len= tmp_names_len;
} }
/* allocate */
if (found_user_tables && mysql_bin_log.is_open() &&
(query = alloc_root(thd->mem_root, query_buf_size+= max_names_len)))
// Better add "if exists", in case a RESET MASTER has been done
end= strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ");
/* scan sorted tmps to generate sequence of DROP */ /* scan sorted tmps to generate sequence of DROP */
for (table=thd->temporary_tables; table; table= next) for (table= thd->temporary_tables; table; table= next)
{ {
if (query // we might be out of memory, but this is not fatal if (is_user_table(table))
&& table->s->table_name[0] != '#')
{ {
char *end_cur;
/* Set pseudo_thread_id to be that of the processed table */ /* Set pseudo_thread_id to be that of the processed table */
thd->variables.pseudo_thread_id= tmpkeyval(thd, table); thd->variables.pseudo_thread_id= tmpkeyval(thd, table);
/* Loop forward through all tables within the sublist of /* Loop forward through all tables within the sublist of
common pseudo_thread_id to create single DROP query */ common pseudo_thread_id to create single DROP query */
for (end_cur= end; for (s_query.length(stub_len);
table && table->s->table_name[0] != '#' && table && is_user_table(table) &&
tmpkeyval(thd, table) == thd->variables.pseudo_thread_id; tmpkeyval(thd, table) == thd->variables.pseudo_thread_id;
table= next) table= next)
{ {
end_cur= strxmov(end_cur, "`", table->s->db, "`.`", /*
table->s->table_name, "`,", NullS); We are going to add 4 ` around the db/table names and possible more
due to special characters in the names
*/
append_identifier(thd, &s_query, table->table_cache_key, strlen(table->table_cache_key));
s_query.q_append('.');
append_identifier(thd, &s_query, table->real_name,
strlen(table->real_name));
s_query.q_append(',');
next= table->next; next= table->next;
close_temporary(table, 1); close_temporary(table, 1);
} }
thd->clear_error(); thd->clear_error();
/* The -1 is to remove last ',' */ Query_log_event qinfo(thd, s_query.ptr(),
Query_log_event qinfo(thd, query, (ulong)(end_cur - query) - 1, 0, FALSE); s_query.length() - 1 /* to remove trailing ',' */,
0, FALSE);
/* /*
Imagine the thread had created a temp table, then was doing a SELECT, and 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 the SELECT was killed. Then it's not clever to mark the statement above as
...@@ -739,7 +728,7 @@ void close_temporary_tables(THD *thd) ...@@ -739,7 +728,7 @@ void close_temporary_tables(THD *thd)
rightfully causing the slave to stop. rightfully causing the slave to stop.
*/ */
qinfo.error_code= 0; qinfo.error_code= 0;
mysql_bin_log.write(&qinfo); write_binlog_with_system_charset(thd, &qinfo);
} }
else else
{ {
...@@ -747,6 +736,8 @@ void close_temporary_tables(THD *thd) ...@@ -747,6 +736,8 @@ void close_temporary_tables(THD *thd)
close_temporary(table, 1); close_temporary(table, 1);
} }
} }
if (!was_quote_show)
thd->options &= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */
thd->temporary_tables=0; thd->temporary_tables=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