Commit 2737a722 authored by Mattias Jonsson's avatar Mattias Jonsson

Bug#58147: ALTER TABLE w/ TRUNCATE PARTITION fails

           but the statement is written to binlog

TRUNCATE PARTITION was written to the binlog
even if it failed before calling any partition's
truncate function.

Solved by adding an argument to truncate_partition,
to flag if it should be written to the binlog or not.

It should be written to the binlog when a call to any
partitions truncate function is done.

mysql-test/r/partition_binlog.result:
  New result file
mysql-test/t/partition_binlog.test:
  New test file, including DROP PARTITION binlog test
sql/ha_partition.cc:
  Added argument to avoid binlogging failed truncate_partition that
  have not yet changed any data.
sql/ha_partition.h:
  Added argument to avoid excessive binlogging
sql/sql_partition_admin.cc:
  Avoid to binlog TRUNCATE PARTITION if it fails before
  any partition has tried to truncate.
parent 45e17739
DROP TABLE IF EXISTS t1;
#
# Bug#58147: ALTER TABLE w/ TRUNCATE PARTITION fails
# but the statement is written to binlog
#
CREATE TABLE t1(id INT)
PARTITION BY RANGE (id)
(PARTITION p0 VALUES LESS THAN (100),
PARTITION pmax VALUES LESS THAN (MAXVALUE));
INSERT INTO t1 VALUES (1), (10), (100), (1000);
ALTER TABLE t1 TRUNCATE PARTITION p1;
ERROR HY000: Incorrect partition name
ALTER TABLE t1 DROP PARTITION p1;
ERROR HY000: Error in list of partitions to DROP
# No error returned, output in table format instead:
ALTER TABLE t1 ANALYZE PARTITION p1;
Table Op Msg_type Msg_text
test.t1 analyze error Error in list of partitions to test.t1
ALTER TABLE t1 CHECK PARTITION p1;
Table Op Msg_type Msg_text
test.t1 check error Error in list of partitions to test.t1
ALTER TABLE t1 OPTIMIZE PARTITION p1;
Table Op Msg_type Msg_text
test.t1 optimize error Error in list of partitions to test.t1
ALTER TABLE t1 REPAIR PARTITION p1;
Table Op Msg_type Msg_text
test.t1 repair error Error in list of partitions to test.t1
ALTER TABLE t1 ANALYZE PARTITION p0;
Table Op Msg_type Msg_text
test.t1 analyze status OK
ALTER TABLE t1 CHECK PARTITION p0;
Table Op Msg_type Msg_text
test.t1 check status OK
ALTER TABLE t1 OPTIMIZE PARTITION p0;
Table Op Msg_type Msg_text
test.t1 optimize status OK
ALTER TABLE t1 REPAIR PARTITION p0;
Table Op Msg_type Msg_text
test.t1 repair status OK
ALTER TABLE t1 TRUNCATE PARTITION p0;
ALTER TABLE t1 DROP PARTITION p0;
show binlog events in 'master-bin.000001' from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; CREATE TABLE t1(id INT)
PARTITION BY RANGE (id)
(PARTITION p0 VALUES LESS THAN (100),
PARTITION pmax VALUES LESS THAN (MAXVALUE))
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1), (10), (100), (1000)
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; ALTER TABLE t1 ANALYZE PARTITION p0
master-bin.000001 # Query # # use `test`; ALTER TABLE t1 OPTIMIZE PARTITION p0
master-bin.000001 # Query # # use `test`; ALTER TABLE t1 REPAIR PARTITION p0
master-bin.000001 # Query # # use `test`; ALTER TABLE t1 TRUNCATE PARTITION p0
master-bin.000001 # Query # # use `test`; ALTER TABLE t1 DROP PARTITION p0
DROP TABLE t1;
--source include/have_log_bin.inc
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
--echo #
--echo # Bug#58147: ALTER TABLE w/ TRUNCATE PARTITION fails
--echo # but the statement is written to binlog
--echo #
--let $binlog_file=query_get_value(SHOW MASTER STATUS, File, 1)
--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1)
CREATE TABLE t1(id INT)
PARTITION BY RANGE (id)
(PARTITION p0 VALUES LESS THAN (100),
PARTITION pmax VALUES LESS THAN (MAXVALUE));
INSERT INTO t1 VALUES (1), (10), (100), (1000);
--error ER_WRONG_PARTITION_NAME
ALTER TABLE t1 TRUNCATE PARTITION p1;
--error ER_DROP_PARTITION_NON_EXISTENT
ALTER TABLE t1 DROP PARTITION p1;
--echo # No error returned, output in table format instead:
ALTER TABLE t1 ANALYZE PARTITION p1;
ALTER TABLE t1 CHECK PARTITION p1;
ALTER TABLE t1 OPTIMIZE PARTITION p1;
ALTER TABLE t1 REPAIR PARTITION p1;
ALTER TABLE t1 ANALYZE PARTITION p0;
ALTER TABLE t1 CHECK PARTITION p0;
ALTER TABLE t1 OPTIMIZE PARTITION p0;
ALTER TABLE t1 REPAIR PARTITION p0;
ALTER TABLE t1 TRUNCATE PARTITION p0;
ALTER TABLE t1 DROP PARTITION p0;
--source include/show_binlog_events.inc
DROP TABLE t1;
......@@ -3428,7 +3428,7 @@ int ha_partition::truncate()
ALTER TABLE t TRUNCATE PARTITION ...
*/
int ha_partition::truncate_partition(Alter_info *alter_info)
int ha_partition::truncate_partition(Alter_info *alter_info, bool *to_binlog)
{
int error= 0;
List_iterator<partition_element> part_it(m_part_info->partitions);
......@@ -3440,6 +3440,9 @@ int ha_partition::truncate_partition(Alter_info *alter_info)
PART_ADMIN);
DBUG_ENTER("ha_partition::truncate_partition");
/* Only binlog when it starts any call to the partitions handlers */
*to_binlog= false;
/*
TRUNCATE also means resetting auto_increment. Hence, reset
it so that it will be initialized again at the next use.
......@@ -3453,6 +3456,8 @@ int ha_partition::truncate_partition(Alter_info *alter_info)
(!(alter_info->flags & ALTER_ALL_PARTITION)))
DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
*to_binlog= true;
do
{
partition_element *part_elem= part_it++;
......
......@@ -362,7 +362,7 @@ class ha_partition :public handler
@remark This method is a partitioning-specific hook
and thus not a member of the general SE API.
*/
int truncate_partition(Alter_info *);
int truncate_partition(Alter_info *, bool *to_binlog);
virtual bool is_fatal_error(int error, uint flags)
{
......
......@@ -110,6 +110,7 @@ bool Alter_table_truncate_partition_statement::execute(THD *thd)
ha_partition *partition;
ulong timeout= thd->variables.lock_wait_timeout;
TABLE_LIST *first_table= thd->lex->select_lex.table_list.first;
bool to_binlog;
DBUG_ENTER("Alter_table_truncate_partition_statement::execute");
/*
......@@ -161,16 +162,18 @@ bool Alter_table_truncate_partition_statement::execute(THD *thd)
partition= (ha_partition *) first_table->table->file;
/* Invoke the handler method responsible for truncating the partition. */
if ((error= partition->truncate_partition(&thd->lex->alter_info)))
if ((error= partition->truncate_partition(&thd->lex->alter_info,
&to_binlog)))
first_table->table->file->print_error(error, MYF(0));
/*
All effects of a truncate operation are committed even if the
operation fails. Thus, the query must be written to the binary
log. The only exception is a unimplemented truncate method. Also,
it is logged in statement format, regardless of the binlog format.
log. The exception is a unimplemented truncate method or failure
before any call to handler::truncate() is done.
Also, it is logged in statement format, regardless of the binlog format.
*/
if (error != HA_ERR_WRONG_COMMAND)
if (error != HA_ERR_WRONG_COMMAND && to_binlog)
error|= write_bin_log(thd, !error, thd->query(), thd->query_length());
/*
......
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