Commit 5c143349 authored by sjaakola's avatar sjaakola Committed by Julius Goryavsky

MDEV-30456 ALTER TABLE algorithm clause not replicated

If user has specified the desired alter algorithm by using session
variable alter_algorithm, and not specifying the algorithm in the
ALTER SQL statement, then the ALTER will be processed in sending node
according the algorithm chosen by the alter_algorithm variable.
But in receiving nodes, appliers cannot see this session variable,
and will use the default algorithm when executing the ALTER.

The fix in this commit, will check if user has set alter_algorithm
variable and has not specified the algorithm clause in the ALTER
statement, and in such case will rewrite the original ALTER statement
appended by the algorithm clause. This rewritten ALTER statement will
be used in replication.

The commit has also new mtr test: galera.galera_alter_table_algorithm
which verifies that ALTER query rewrite happens when needed
Signed-off-by: default avatarJulius Goryavsky <julius.goryavsky@mariadb.com>
parent 011d666a
connection node_2;
connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
connection node_2;
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
connection node_1;
ALTER TABLE t1 ADD COLUMN f2 INTEGER, ALGORITHM=INSTANT;
show binlog events limit 1 offset 4;
Log_name Pos Event_type Server_id End_log_pos Info
binlog.000001 367 Query 1 489 use `test`; ALTER TABLE t1 ADD COLUMN f2 INTEGER, ALGORITHM=INSTANT
connection node_2;
show binlog events limit 1 offset 4;
Log_name Pos Event_type Server_id End_log_pos Info
binlog.000001 367 Query 1 489 use `test`; ALTER TABLE t1 ADD COLUMN f2 INTEGER, ALGORITHM=INSTANT
connection node_1;
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
connection node_2;
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
connection node_1;
SET SESSION alter_algorithm='INSTANT';
ALTER TABLE t1 ADD COLUMN f3 INTEGER;
show binlog events limit 1 offset 4;
Log_name Pos Event_type Server_id End_log_pos Info
binlog.000001 367 Query 1 470 use `test`; ALTER TABLE t1 ADD COLUMN f3 INTEGER
connection node_2;
show binlog events limit 1 offset 4;
Log_name Pos Event_type Server_id End_log_pos Info
binlog.000001 367 Query 1 489 use `test`; ALTER TABLE t1 ADD COLUMN f3 INTEGER ,ALGORITHM=INSTANT
connection node_1;
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
connection node_2;
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
connection node_1;
SET SESSION alter_algorithm='INSTANT';
ALTER TABLE t1 ADD COLUMN f4 INTEGER, ALGORITHM=COPY;
show binlog events limit 1 offset 4;
Log_name Pos Event_type Server_id End_log_pos Info
binlog.000001 367 Query 1 486 use `test`; ALTER TABLE t1 ADD COLUMN f4 INTEGER, ALGORITHM=COPY
connection node_2;
show binlog events limit 1 offset 4;
Log_name Pos Event_type Server_id End_log_pos Info
binlog.000001 367 Query 1 486 use `test`; ALTER TABLE t1 ADD COLUMN f4 INTEGER, ALGORITHM=COPY
connection node_1;
DROP TABLE t1;
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
connection node_2;
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
!include ../galera_2nodes.cnf
[mysqld.1]
log_slave_updates=ON
log_bin=binlog
[mysqld.2]
log_slave_updates=ON
log_bin=binlog
--source include/galera_cluster.inc
--source include/have_innodb.inc
#
# Test
#
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
--connection node_2
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
--connection node_1
ALTER TABLE t1 ADD COLUMN f2 INTEGER, ALGORITHM=INSTANT;
show binlog events limit 1 offset 4;
--connection node_2
show binlog events limit 1 offset 4;
# Phase 2, setting algorithm before alter statement
--connection node_1
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
--connection node_2
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
--connection node_1
SET SESSION alter_algorithm='INSTANT';
ALTER TABLE t1 ADD COLUMN f3 INTEGER;
show binlog events limit 1 offset 4;
--connection node_2
show binlog events limit 1 offset 4;
# Phase 3, setting different algorithm before alter statement
--connection node_1
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
--connection node_2
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
--connection node_1
SET SESSION alter_algorithm='INSTANT';
ALTER TABLE t1 ADD COLUMN f4 INTEGER, ALGORITHM=COPY;
show binlog events limit 1 offset 4;
--connection node_2
show binlog events limit 1 offset 4;
#Cleanup
--connection node_1
DROP TABLE t1;
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
--connection node_2
set global wsrep_on=OFF;
reset master;
set global wsrep_on=ON;
......@@ -188,6 +188,12 @@ class Alter_info
void apply_statistics_deletes_renames(THD *thd, TABLE *table);
private:
#ifdef WITH_WSREP
/* wsrep patch needs to peak the algorithm clause used in ALTER statement
in order to see if ALTER statement needs to be rewritten for replication
*/
public:
#endif /* WITH_WSREP */
// Type of ALTER TABLE algorithm.
enum_alter_table_algorithm requested_algorithm;
......
......@@ -2213,34 +2213,51 @@ int wsrep_to_buf_helper(
return ret;
}
static int
wsrep_alter_query_string(THD *thd, String *buf)
static int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len)
{
/* Append the "ALTER" part of the query */
if (buf->append(STRING_WITH_LEN("ALTER ")))
return 1;
/* Append definer */
append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host));
/* Append the left part of thd->query after event name part */
if (buf->append(thd->lex->stmt_definition_begin,
thd->lex->stmt_definition_end -
thd->lex->stmt_definition_begin))
String log_query;
/* build the ALTER statement, with definer */
if (log_query.append(STRING_WITH_LEN("ALTER "))
|| append_definer(thd, &log_query, &(thd->lex->definer->user), &(thd->lex->definer->host))
|| log_query.append(thd->lex->stmt_definition_begin,
thd->lex->stmt_definition_end -
thd->lex->stmt_definition_begin))
{
WSREP_WARN("events alter string failed: schema: %s, query: %s",
thd->get_db(), thd->query());
return 1;
}
return 0;
return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(),
buf, buf_len);
}
static int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len)
static int wsrep_alter_table_query(THD *thd, uchar** buf, size_t* buf_len,
Alter_info *alter_info)
{
String log_query;
log_query.append(thd->query());
if (wsrep_alter_query_string(thd, &log_query))
/*
if user has specified the alter algorithm by session variable alter_algorithm
and the ALTER statement does not contain ALGORITHM= clause, then
build for replication new ALTER query with the ALGORITHM clause
*/
if (thd->variables.alter_algorithm != Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT &&
alter_info->requested_algorithm == Alter_info::ALTER_TABLE_ALGORITHM_NONE)
{
WSREP_WARN("events alter string failed: schema: %s, query: %s",
thd->get_db(), thd->query());
return 1;
if (log_query.append(" ,") ||
log_query.append(alter_info->algorithm_clause(thd)))
{
WSREP_WARN("alter table string failed: schema: %s, query: %s",
thd->get_db(), thd->query());
return 1;
}
}
return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(),
buf, buf_len);
}
#include "sql_show.h"
......@@ -2613,7 +2630,7 @@ static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
}
static int wsrep_TOI_event_buf(THD* thd, uchar** buf, size_t* buf_len)
static int wsrep_TOI_event_buf(THD* thd, uchar** buf, size_t* buf_len, Alter_info *alter_info)
{
int err;
switch (thd->lex->sql_command)
......@@ -2634,6 +2651,9 @@ static int wsrep_TOI_event_buf(THD* thd, uchar** buf, size_t* buf_len)
case SQLCOM_ALTER_EVENT:
err= wsrep_alter_event_query(thd, buf, buf_len);
break;
case SQLCOM_ALTER_TABLE:
err= wsrep_alter_table_query(thd, buf, buf_len, alter_info);
break;
case SQLCOM_DROP_TABLE:
err= wsrep_drop_table_query(thd, buf, buf_len);
break;
......@@ -2707,8 +2727,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
int buf_err;
int rc;
buf_err= wsrep_TOI_event_buf(thd, &buf, &buf_len);
buf_err= wsrep_TOI_event_buf(thd, &buf, &buf_len, alter_info);
if (buf_err) {
WSREP_ERROR("Failed to create TOI event buf: %d", buf_err);
my_message(ER_UNKNOWN_ERROR,
......
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