summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <guilhem@mysql.com>2005-02-14 23:47:17 +0100
committerunknown <guilhem@mysql.com>2005-02-14 23:47:17 +0100
commit4cead8c8a500f45952e6f9956293320d36ed505c (patch)
treec9d594111c2eec0cddde20026bcfd437d4324e76
parente2b6480162743d7eaa62bf7b64e92778191b25d9 (diff)
downloadmariadb-git-4cead8c8a500f45952e6f9956293320d36ed505c.tar.gz
1) undoing my fix for BUG#8055 "Trouble with replication from temporary tables and ignores"
and fixing it another way (per Monty; a simpler solution which does not increase the number of binlog events is to always execute DROP TEMPORARY TABLE IF EXISTS on slave). A new test rpl_drop_temp. 2) fixing BUG#8436 "Multiple "stacked" SQL statements cause replication to stop" by setting thd->query_length to the length of the query being executed, not counting the next queries if this is a multi-query. Should also improve display of SHOW PROCESSLIST. A new test rpl_multi_query. mysql-test/r/drop_temp_table.result: back to one single DROP sql/sql_base.cc: undoing the fix I had made some days ago: we are back to one single DROP TEMPORARY TABLE for all temp tables. sql/sql_parse.cc: 1) set thd->query_length to the length of the query being executed, excluding the other next queries if this is a multi-query. The setting happens ASAP, ie. just after we know it's a multi-query, ie. just after yyparse(). Don't include the ';' in thd->query_length, because this is not good for storage in binlog. 2) always execute a DROP TEMPORARY TABLE IF EXISTS on slave, don't skip it even if --replicate-ignore-table
-rw-r--r--mysql-test/r/drop_temp_table.result4
-rw-r--r--mysql-test/r/rpl_drop_temp.result12
-rw-r--r--mysql-test/r/rpl_multi_query.result32
-rw-r--r--mysql-test/t/rpl_drop_temp-slave.opt2
-rw-r--r--mysql-test/t/rpl_drop_temp.test13
-rw-r--r--mysql-test/t/rpl_multi_query.test26
-rw-r--r--sql/sql_base.cc66
-rw-r--r--sql/sql_parse.cc26
8 files changed, 144 insertions, 37 deletions
diff --git a/mysql-test/r/drop_temp_table.result b/mysql-test/r/drop_temp_table.result
index a486964feb2..5f1f142cde5 100644
--- a/mysql-test/r/drop_temp_table.result
+++ b/mysql-test/r/drop_temp_table.result
@@ -17,8 +17,6 @@ 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`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`shortn2`,`drop-temp+table-test`.`table:name`,`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/r/rpl_drop_temp.result b/mysql-test/r/rpl_drop_temp.result
new file mode 100644
index 00000000000..e00309cac8f
--- /dev/null
+++ b/mysql-test/r/rpl_drop_temp.result
@@ -0,0 +1,12 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+create database if not exists mysqltest;
+create temporary table mysqltest.t1 (n int);
+create temporary table mysqltest.t2 (n int);
+show status like 'Slave_open_temp_tables';
+Variable_name Value
+Slave_open_temp_tables 0
diff --git a/mysql-test/r/rpl_multi_query.result b/mysql-test/r/rpl_multi_query.result
new file mode 100644
index 00000000000..2521dbe1ed9
--- /dev/null
+++ b/mysql-test/r/rpl_multi_query.result
@@ -0,0 +1,32 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+drop database if exists mysqltest;
+create database mysqltest;
+create table mysqltest.t1 ( n int);
+insert into mysqltest.t1 values(1)/
+insert into mysqltest.t1 values(2);
+insert into mysqltest.t1 values(3);
+insert into mysqltest.t1 values(4);
+insert into mysqltest.t1 values(5)/
+select * from mysqltest.t1;
+n
+1
+2
+3
+4
+5
+show binlog events from 79;
+Log_name Pos Event_type Server_id Orig_log_pos Info
+master-bin.000001 # Query 1 # drop database if exists mysqltest
+master-bin.000001 # Query 1 # create database mysqltest
+master-bin.000001 # Query 1 # use `test`; create table mysqltest.t1 ( n int)
+master-bin.000001 # Query 1 # use `test`; insert into mysqltest.t1 values(1)
+master-bin.000001 # Query 1 # use `test`; insert into mysqltest.t1 values(2)
+master-bin.000001 # Query 1 # use `test`; insert into mysqltest.t1 values(3)
+master-bin.000001 # Query 1 # use `test`; insert into mysqltest.t1 values(4)
+master-bin.000001 # Query 1 # use `test`; insert into mysqltest.t1 values(5)
+drop database mysqltest;
diff --git a/mysql-test/t/rpl_drop_temp-slave.opt b/mysql-test/t/rpl_drop_temp-slave.opt
new file mode 100644
index 00000000000..2f9244c65ff
--- /dev/null
+++ b/mysql-test/t/rpl_drop_temp-slave.opt
@@ -0,0 +1,2 @@
+--replicate-ignore-table=mysqltest.t2
+
diff --git a/mysql-test/t/rpl_drop_temp.test b/mysql-test/t/rpl_drop_temp.test
new file mode 100644
index 00000000000..73d691d9d90
--- /dev/null
+++ b/mysql-test/t/rpl_drop_temp.test
@@ -0,0 +1,13 @@
+source include/master-slave.inc;
+--disable_warnings
+create database if not exists mysqltest;
+--enable_warnings
+
+create temporary table mysqltest.t1 (n int);
+create temporary table mysqltest.t2 (n int);
+sync_slave_with_master;
+connection master;
+disconnect master;
+connection slave;
+--real_sleep 3; # time for DROP to be written
+show status like 'Slave_open_temp_tables';
diff --git a/mysql-test/t/rpl_multi_query.test b/mysql-test/t/rpl_multi_query.test
new file mode 100644
index 00000000000..15f5d288759
--- /dev/null
+++ b/mysql-test/t/rpl_multi_query.test
@@ -0,0 +1,26 @@
+# Test for BUG#8436: verify that a multi-query (i.e. one query
+# containing several queries (assuming client has
+# CLIENT_MULTI_STATEMENTS) will be binlogged ONE-query-per-event (not
+# one binlog event containing all queries)
+
+source include/master-slave.inc;
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+
+delimiter /;
+create table mysqltest.t1 ( n int);
+insert into mysqltest.t1 values(1)/
+insert into mysqltest.t1 values(2);
+insert into mysqltest.t1 values(3);
+insert into mysqltest.t1 values(4);
+insert into mysqltest.t1 values(5)/
+delimiter ;/
+sync_slave_with_master;
+select * from mysqltest.t1;
+connection master;
+--replace_column 2 # 5 #
+show binlog events from 79;
+drop database mysqltest;
+sync_slave_with_master;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index fe1f268e277..7434897ab90 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -485,58 +485,62 @@ void close_temporary(TABLE *table,bool delete_table)
void close_temporary_tables(THD *thd)
{
TABLE *table,*next;
- char *query, *name_in_query, *end;
- uint greatest_key_length= 0;
+ char *query, *end;
+ uint query_buf_size;
+ bool found_user_tables = 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)
- greatest_key_length= max(greatest_key_length, table->key_length);
+ /*
+ 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;
- if ((query = alloc_root(thd->mem_root, greatest_key_length+50)))
+ if ((query = alloc_root(thd->mem_root, query_buf_size)))
// Better add "if exists", in case a RESET MASTER has been done
- name_in_query= 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)
{
- /*
- 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] != '#'))
+ if (query) // we might be out of memory, but this is not fatal
{
+ // 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(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);
+ end = strxmov(end,"`",table->table_cache_key,"`.`",
+ table->real_name,"`,", NullS);
}
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;
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e66eeb279d2..f25255ac455 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1472,6 +1472,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
if (alloc_query(thd, packet, packet_length))
break; // fatal error is set
+ char *packet_end= thd->query + thd->query_length;
mysql_log.write(thd,command,"%s",thd->query);
DBUG_PRINT("query",("%-.4096s",thd->query));
mysql_parse(thd,thd->query, thd->query_length);
@@ -1487,7 +1488,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (thd->lock || thd->open_tables || thd->derived_tables)
close_thread_tables(thd);
#endif
- ulong length= thd->query_length-(ulong)(packet-thd->query);
+ ulong length= (ulong)(packet_end-packet);
/* Remove garbage at start of query */
while (my_isspace(thd->charset(), *packet) && length > 0)
@@ -1924,9 +1925,14 @@ mysql_execute_command(THD *thd)
}
/*
Skip if we are in the slave thread, some table rules have been
- given and the table list says the query should not be replicated
+ given and the table list says the query should not be replicated.
+ Exception is DROP TEMPORARY TABLE IF EXISTS: we always execute it
+ (otherwise we have stale files on slave caused by exclusion of one tmp
+ table).
*/
- if (all_tables_not_ok(thd,tables))
+ if (!(lex->sql_command == SQLCOM_DROP_TABLE &&
+ lex->drop_temporary && lex->drop_if_exists) &&
+ all_tables_not_ok(thd,tables))
{
/* we warn the slave SQL thread */
my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
@@ -4118,6 +4124,20 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
send_error(thd, 0, NullS);
else
{
+ /*
+ Binlog logs a string starting from thd->query and having length
+ thd->query_length; so we set thd->query_length correctly (to not
+ log several statements in one event, when we executed only first).
+ We set it to not see the ';' (otherwise it would get into binlog
+ and Query_log_event::print() would give ';;' output).
+ This also helps display only the current query in SHOW
+ PROCESSLIST.
+ Note that we don't need LOCK_thread_count to modify query_length.
+ */
+ if (lex->found_colon &&
+ (thd->query_length= (ulong)(lex->found_colon - thd->query)))
+ thd->query_length--;
+ /* Actually execute the query */
mysql_execute_command(thd);
query_cache_end_of_result(thd);
}