Loading mysql-test/r/rpl_temporary.result +8 −5 Original line number Diff line number Diff line Loading @@ -89,14 +89,17 @@ f 7 drop table t1,t2; create temporary table t3 (f int); set @session.pseudo_thread_id=100; set @@session.pseudo_thread_id=100; create temporary table t101 (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 `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); set @con1_id=connection_id(); kill @con1_id; create temporary table `t``201` (id int); create temporary table `#sql_not_user_table202` (id int); set @@session.pseudo_thread_id=300; create temporary table t301 (id int); create temporary table t302 (id int); create temporary table `#sql_not_user_table303` (id int); create table t1(f int); insert into t1 values (1); select * from t1 /* must be 1 */; Loading mysql-test/t/rpl_temporary.test +10 −5 Original line number Diff line number Diff line Loading @@ -135,14 +135,19 @@ sync_with_master; # value was set up at the moment of temp table creation # connection con1; set @session.pseudo_thread_id=100; set @@session.pseudo_thread_id=100; create temporary table t101 (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 `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); set @con1_id=connection_id(); kill @con1_id; 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); set @@session.pseudo_thread_id=300; create temporary table t301 (id int); create temporary table t302 (id int); create temporary table `#sql_not_user_table303` (id int); disconnect con1; #now do something to show that slave is ok after DROP temp tables connection master; Loading sql/mysql_priv.h +16 −0 Original line number Diff line number Diff line Loading @@ -1275,6 +1275,11 @@ inline int hexchar_to_int(char c) 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; Loading @@ -1283,6 +1288,17 @@ inline void write_binlog_with_system_charset(THD * thd, Query_log_event * 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 server Loading sql/sql_base.cc +69 −78 Original line number Diff line number Diff line Loading @@ -493,46 +493,51 @@ static inline uint tmpkeyval(THD *thd, TABLE *table) void close_temporary_tables(THD *thd) { TABLE *next, *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; TABLE *table; if (!thd->temporary_tables) return; LINT_INIT(end); query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS if (!mysql_bin_log.is_open()) { 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 of sublists of equal pseudo_thread_id */ for (prev_table= thd->temporary_tables, table= prev_table->next, found_user_tables= (prev_table->real_name[0] != '#'); for (prev_table= thd->temporary_tables, table= prev_table->next; table; prev_table= table, table= table->next) { TABLE *prev_sorted /* same as for prev_table */, *sorted; /* 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->real_name[0] == '#') continue; else TABLE *prev_sorted /* same as for prev_table */, *sorted; if (is_user_table(table)) { found_user_tables = 1; } if (!found_user_tables) found_user_tables= true; for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; prev_sorted= sorted, sorted= sorted->next) { if (sorted->real_name[0] == '#' || tmpkeyval(thd, sorted) > tmpkeyval(thd, table)) if (!is_user_table(sorted) || tmpkeyval(thd, sorted) > tmpkeyval(thd, table)) { /* move into the sorted part of the list from the unsorted */ prev_table->next= table->next; Loading @@ -550,61 +555,45 @@ void close_temporary_tables(THD *thd) } } } /* 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->real_name[0] != '#'; table=table->next) { uint tmp_names_len; for (tmp_names_len= table->key_length + 1; table->next && table->real_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->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 "); /* We always quote db,table names though it is slight overkill */ if (found_user_tables && !(was_quote_show= (thd->options & OPTION_QUOTE_SHOW_CREATE))) { thd->options |= OPTION_QUOTE_SHOW_CREATE; } /* 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 && table->real_name[0] != '#') if (is_user_table(table)) { char *end_cur; /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); /* Loop forward through all tables within the sublist of common pseudo_thread_id to create single DROP query */ for (end_cur= end; table && table->real_name[0] != '#' && for (s_query.length(stub_len); table && is_user_table(table) && tmpkeyval(thd, table) == thd->variables.pseudo_thread_id; table= next) { end_cur= strxmov(end_cur, "`", table->table_cache_key, "`.`", table->real_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; close_temporary(table, 1); } thd->clear_error(); /* The -1 is to remove last ',' */ Query_log_event qinfo(thd, query, (ulong)(end_cur - query) - 1, 0, FALSE); Query_log_event qinfo(thd, s_query.ptr(), s_query.length() - 1 /* to remove trailing ',' */, 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 Loading @@ -623,6 +612,8 @@ void close_temporary_tables(THD *thd) close_temporary(table, 1); } } if (!was_quote_show) thd->options &= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */ thd->temporary_tables=0; } Loading Loading
mysql-test/r/rpl_temporary.result +8 −5 Original line number Diff line number Diff line Loading @@ -89,14 +89,17 @@ f 7 drop table t1,t2; create temporary table t3 (f int); set @session.pseudo_thread_id=100; set @@session.pseudo_thread_id=100; create temporary table t101 (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 `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); set @con1_id=connection_id(); kill @con1_id; create temporary table `t``201` (id int); create temporary table `#sql_not_user_table202` (id int); set @@session.pseudo_thread_id=300; create temporary table t301 (id int); create temporary table t302 (id int); create temporary table `#sql_not_user_table303` (id int); create table t1(f int); insert into t1 values (1); select * from t1 /* must be 1 */; Loading
mysql-test/t/rpl_temporary.test +10 −5 Original line number Diff line number Diff line Loading @@ -135,14 +135,19 @@ sync_with_master; # value was set up at the moment of temp table creation # connection con1; set @session.pseudo_thread_id=100; set @@session.pseudo_thread_id=100; create temporary table t101 (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 `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); set @con1_id=connection_id(); kill @con1_id; 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); set @@session.pseudo_thread_id=300; create temporary table t301 (id int); create temporary table t302 (id int); create temporary table `#sql_not_user_table303` (id int); disconnect con1; #now do something to show that slave is ok after DROP temp tables connection master; Loading
sql/mysql_priv.h +16 −0 Original line number Diff line number Diff line Loading @@ -1275,6 +1275,11 @@ inline int hexchar_to_int(char c) 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; Loading @@ -1283,6 +1288,17 @@ inline void write_binlog_with_system_charset(THD * thd, Query_log_event * 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 server Loading
sql/sql_base.cc +69 −78 Original line number Diff line number Diff line Loading @@ -493,46 +493,51 @@ static inline uint tmpkeyval(THD *thd, TABLE *table) void close_temporary_tables(THD *thd) { TABLE *next, *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; TABLE *table; if (!thd->temporary_tables) return; LINT_INIT(end); query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS if (!mysql_bin_log.is_open()) { 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 of sublists of equal pseudo_thread_id */ for (prev_table= thd->temporary_tables, table= prev_table->next, found_user_tables= (prev_table->real_name[0] != '#'); for (prev_table= thd->temporary_tables, table= prev_table->next; table; prev_table= table, table= table->next) { TABLE *prev_sorted /* same as for prev_table */, *sorted; /* 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->real_name[0] == '#') continue; else TABLE *prev_sorted /* same as for prev_table */, *sorted; if (is_user_table(table)) { found_user_tables = 1; } if (!found_user_tables) found_user_tables= true; for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; prev_sorted= sorted, sorted= sorted->next) { if (sorted->real_name[0] == '#' || tmpkeyval(thd, sorted) > tmpkeyval(thd, table)) if (!is_user_table(sorted) || tmpkeyval(thd, sorted) > tmpkeyval(thd, table)) { /* move into the sorted part of the list from the unsorted */ prev_table->next= table->next; Loading @@ -550,61 +555,45 @@ void close_temporary_tables(THD *thd) } } } /* 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->real_name[0] != '#'; table=table->next) { uint tmp_names_len; for (tmp_names_len= table->key_length + 1; table->next && table->real_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->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 "); /* We always quote db,table names though it is slight overkill */ if (found_user_tables && !(was_quote_show= (thd->options & OPTION_QUOTE_SHOW_CREATE))) { thd->options |= OPTION_QUOTE_SHOW_CREATE; } /* 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 && table->real_name[0] != '#') if (is_user_table(table)) { char *end_cur; /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); /* Loop forward through all tables within the sublist of common pseudo_thread_id to create single DROP query */ for (end_cur= end; table && table->real_name[0] != '#' && for (s_query.length(stub_len); table && is_user_table(table) && tmpkeyval(thd, table) == thd->variables.pseudo_thread_id; table= next) { end_cur= strxmov(end_cur, "`", table->table_cache_key, "`.`", table->real_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; close_temporary(table, 1); } thd->clear_error(); /* The -1 is to remove last ',' */ Query_log_event qinfo(thd, query, (ulong)(end_cur - query) - 1, 0, FALSE); Query_log_event qinfo(thd, s_query.ptr(), s_query.length() - 1 /* to remove trailing ',' */, 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 Loading @@ -623,6 +612,8 @@ void close_temporary_tables(THD *thd) close_temporary(table, 1); } } if (!was_quote_show) thd->options &= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */ thd->temporary_tables=0; } Loading