summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <guilhem@mysql.com>2005-02-04 22:43:54 +0100
committerunknown <guilhem@mysql.com>2005-02-04 22:43:54 +0100
commitededf83143df115f5feaabbbcfeea2494d7d65d5 (patch)
tree30803a4814ce3ee6e629553369014c8092e0fb51
parent1a3a4ee3e64c6418300d9afa0ba0e402407917c8 (diff)
downloadmariadb-git-ededf83143df115f5feaabbbcfeea2494d7d65d5.tar.gz
Fix for BUG#8055 "Trouble with replication from temporary tables and ignores":
when we close the session's temp tables at session end, we automatically write to binlog *one* DROP TEMPORARY TABLE *per tmp table*. mysql-test/r/drop_temp_table.result: result update (note: one DROP TEMPORARY TABLE per tmp table) mysql-test/t/drop_temp_table.test: checking that we have one DROP TEMPORARY TABLE per tmp table now, not one multi-table DROP. Hiding columns Log_pos/End_log_pos per Monty's request. sql/sql_base.cc: When we close the session's temp tables at session end, we automatically write to binlog one DROP TEMPORARY TABLE per tmp table, not one single multi-table DROP TEMPORARY TABLE (because it causes problems if slave has --replicate*table rules).
-rw-r--r--mysql-test/r/drop_temp_table.result16
-rw-r--r--mysql-test/t/drop_temp_table.test3
-rw-r--r--sql/sql_base.cc66
3 files changed, 45 insertions, 40 deletions
diff --git a/mysql-test/r/drop_temp_table.result b/mysql-test/r/drop_temp_table.result
index 266196877c8..a486964feb2 100644
--- a/mysql-test/r/drop_temp_table.result
+++ b/mysql-test/r/drop_temp_table.result
@@ -1,7 +1,9 @@
reset master;
create database `drop-temp+table-test`;
use `drop-temp+table-test`;
+create temporary table shortn1 (a int);
create temporary table `table:name` (a int);
+create temporary table shortn2 (a int);
select get_lock("a",10);
get_lock("a",10)
1
@@ -10,9 +12,13 @@ get_lock("a",10)
1
show binlog events;
Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
-master-bin.000001 79 Query 1 79 create database `drop-temp+table-test`
-master-bin.000001 168 Query 1 168 use `drop-temp+table-test`; create temporary table `table:name` (a int)
-master-bin.000001 262 Query 1 262 use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`table:name`
-master-bin.000001 391 Query 1 391 use `drop-temp+table-test`; DO RELEASE_LOCK("a")
+master-bin.000001 # Start 1 # Server ver: VERSION, Binlog ver: 3
+master-bin.000001 # Query 1 # create database `drop-temp+table-test`
+master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn1 (a int)
+master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table `table:name` (a int)
+master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn2 (a int)
+master-bin.000001 # Query 1 # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`shortn2`
+master-bin.000001 # Query 1 # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`table:name`
+master-bin.000001 # Query 1 # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`shortn1`
+master-bin.000001 # Query 1 # use `drop-temp+table-test`; DO RELEASE_LOCK("a")
drop database `drop-temp+table-test`;
diff --git a/mysql-test/t/drop_temp_table.test b/mysql-test/t/drop_temp_table.test
index 1a7d8796bb3..dcd95721179 100644
--- a/mysql-test/t/drop_temp_table.test
+++ b/mysql-test/t/drop_temp_table.test
@@ -4,7 +4,9 @@ connection con1;
reset master;
create database `drop-temp+table-test`;
use `drop-temp+table-test`;
+create temporary table shortn1 (a int);
create temporary table `table:name` (a int);
+create temporary table shortn2 (a int);
select get_lock("a",10);
disconnect con1;
@@ -15,5 +17,6 @@ connection con2;
select get_lock("a",10);
let $VERSION=`select version()`;
--replace_result $VERSION VERSION
+--replace_column 2 # 5 #
show binlog events;
drop database `drop-temp+table-test`;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 7434897ab90..fe1f268e277 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -485,62 +485,58 @@ void close_temporary(TABLE *table,bool delete_table)
void close_temporary_tables(THD *thd)
{
TABLE *table,*next;
- char *query, *end;
- uint query_buf_size;
- bool found_user_tables = 0;
+ char *query, *name_in_query, *end;
+ uint greatest_key_length= 0;
if (!thd->temporary_tables)
return;
+ /*
+ We write a DROP TEMPORARY TABLE for each temp table left, so that our
+ replication slave can clean them up. Not one multi-table DROP TABLE binlog
+ event: this would cause problems if slave uses --replicate-*-table.
+ */
LINT_INIT(end);
- query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS
+ /* We'll re-use always same buffer so make it big enough for longest name */
for (table=thd->temporary_tables ; table ; table=table->next)
- /*
- We are going to add 4 ` around the db/table names, so 1 does 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.
- */
- query_buf_size+= table->key_length+1;
+ greatest_key_length= max(greatest_key_length, table->key_length);
- if ((query = alloc_root(thd->mem_root, query_buf_size)))
+ if ((query = alloc_root(thd->mem_root, greatest_key_length+50)))
// Better add "if exists", in case a RESET MASTER has been done
- end=strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ");
+ name_in_query= strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `");
for (table=thd->temporary_tables ; table ; table=next)
{
- if (query) // we might be out of memory, but this is not fatal
+ /*
+ In we are OOM for 'query' this is not fatal. We skip temporary tables
+ not created directly by the user.
+ */
+ if (query && mysql_bin_log.is_open() && (table->real_name[0] != '#'))
{
- // skip temporary tables not created directly by the user
- if (table->real_name[0] != '#')
- found_user_tables = 1;
/*
Here we assume table_cache_key always starts
with \0 terminated db name
*/
- end = strxmov(end,"`",table->table_cache_key,"`.`",
- table->real_name,"`,", NullS);
+ end = strxmov(name_in_query, table->table_cache_key, "`.`",
+ table->real_name, "`", NullS);
+ Query_log_event qinfo(thd, query, (ulong)(end-query), 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. And, if thread is
+ killed now, it's not clever either.
+ 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);
}
next=table->next;
close_temporary(table);
}
- if (query && found_user_tables && mysql_bin_log.is_open())
- {
- /* 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;
}