Refs: MW-360 * merged relevant parts of DROP TABLE query splitting from mysql-wsrep-features
This commit is contained in:
parent
a754387a09
commit
04c6b03c9b
@ -4030,26 +4030,6 @@ end_with_restore_list:
|
||||
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
|
||||
thd->variables.option_bits|= OPTION_KEEP_LOG;
|
||||
}
|
||||
#ifdef WITH_WSREP
|
||||
bool has_tmp_tables= false;
|
||||
for (TABLE_LIST *table= all_tables; table; table= table->next_global)
|
||||
{
|
||||
if (lex->drop_temporary || find_temporary_table(thd, table))
|
||||
{
|
||||
has_tmp_tables= true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_tmp_tables)
|
||||
{
|
||||
wsrep_replicate_drop_query(thd, first_table, lex->check_exists,
|
||||
lex->drop_temporary, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables);
|
||||
}
|
||||
#endif /* WITH_WSREP */
|
||||
/*
|
||||
If we are a slave, we should add IF EXISTS if the query executed
|
||||
on the master without an error. This will help a slave to
|
||||
@ -4060,6 +4040,7 @@ end_with_restore_list:
|
||||
slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT)
|
||||
lex->check_exists= 1;
|
||||
|
||||
WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables);
|
||||
/* DDL and binlog write order are protected by metadata locks. */
|
||||
res= mysql_rm_table(thd, first_table, lex->check_exists,
|
||||
lex->drop_temporary);
|
||||
|
@ -2156,94 +2156,6 @@ static uint32 comment_length(THD *thd, uint32 comment_pos,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
static void
|
||||
wsrep_append_name(THD *thd, String *packet, const char *name, uint length,
|
||||
const CHARSET_INFO *from_cs, const CHARSET_INFO *to_cs)
|
||||
{
|
||||
const char *to_name= name;
|
||||
size_t to_length= length;
|
||||
String to_string(name,length, from_cs);
|
||||
if (from_cs != NULL && to_cs != NULL && from_cs != to_cs)
|
||||
thd->convert_string(&to_string, from_cs, to_cs);
|
||||
|
||||
if (to_cs != NULL)
|
||||
{
|
||||
to_name= to_string.c_ptr();
|
||||
to_length= to_string.length();
|
||||
}
|
||||
packet->append(to_name, to_length, packet->charset());
|
||||
}
|
||||
|
||||
int wsrep_replicate_drop_query(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
bool drop_temporary, bool dont_log_query)
|
||||
{
|
||||
TABLE_LIST *table;
|
||||
int error= 0;
|
||||
String built_query;
|
||||
bool non_tmp_table_deleted= FALSE;
|
||||
|
||||
DBUG_ENTER("wsrep_build_drop_query");
|
||||
|
||||
if (!dont_log_query)
|
||||
{
|
||||
if (!drop_temporary)
|
||||
{
|
||||
built_query.set_charset(system_charset_info);
|
||||
if (if_exists)
|
||||
built_query.append("DROP TABLE IF EXISTS ");
|
||||
else
|
||||
built_query.append("DROP TABLE ");
|
||||
}
|
||||
}
|
||||
|
||||
for (table= tables; table; table= table->next_local)
|
||||
{
|
||||
char *db=table->db;
|
||||
int db_len= table->db_length;
|
||||
|
||||
DBUG_PRINT("table", ("table_l: '%s'.'%s' table: 0x%lx s: 0x%lx",
|
||||
table->db, table->table_name, (long) table->table,
|
||||
table->table ? (long) table->table->s : (long) -1));
|
||||
|
||||
if (!find_temporary_table(thd, table))
|
||||
{
|
||||
non_tmp_table_deleted= TRUE;
|
||||
|
||||
if (thd->db == NULL || strcmp(db,thd->db) != 0)
|
||||
{
|
||||
wsrep_append_name(thd, &built_query, db, db_len,
|
||||
system_charset_info, thd->charset());
|
||||
built_query.append(".");
|
||||
}
|
||||
|
||||
thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
|
||||
wsrep_append_name(thd, &built_query, table->table_name,
|
||||
strlen(table->table_name), system_charset_info,
|
||||
thd->charset());
|
||||
built_query.append(",");
|
||||
}
|
||||
}
|
||||
|
||||
if (non_tmp_table_deleted)
|
||||
{
|
||||
/* Chop of the last comma */
|
||||
built_query.chop();
|
||||
built_query.append(" /* generated by server */");
|
||||
WSREP_DEBUG("TOI for %s", built_query.ptr());
|
||||
if (WSREP_TO_ISOLATION_BEGIN_QUERY(built_query.ptr(), NULL, NULL, tables))
|
||||
{
|
||||
WSREP_DEBUG("TOI failed for DROP TABLE: %s", WSREP_QUERY(thd));
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
#endif /* WITH_WSREP */
|
||||
/**
|
||||
Execute the drop of a normal or temporary table.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
the Free Software Foundation; version 2 of the License.x1
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ -16,6 +16,7 @@
|
||||
#include <mysqld.h>
|
||||
#include <sql_class.h>
|
||||
#include <sql_parse.h>
|
||||
#include <sql_base.h> /* find_temporary_table() */
|
||||
#include "wsrep_priv.h"
|
||||
#include "wsrep_thd.h"
|
||||
#include "wsrep_sst.h"
|
||||
@ -948,86 +949,66 @@ static bool wsrep_prepare_keys_for_isolation(THD* thd,
|
||||
const TABLE_LIST* table_list,
|
||||
wsrep_key_arr_t* ka)
|
||||
{
|
||||
ka->keys= 0;
|
||||
ka->keys_len= 0;
|
||||
ka->keys= 0;
|
||||
ka->keys_len= 0;
|
||||
|
||||
extern TABLE* find_temporary_table(THD*, const TABLE_LIST*);
|
||||
|
||||
if (db || table)
|
||||
if (db || table)
|
||||
{
|
||||
if (!(ka->keys= (wsrep_key_t*)my_malloc(sizeof(wsrep_key_t), MYF(0))))
|
||||
{
|
||||
TABLE_LIST tmp_table;
|
||||
MDL_request mdl_request;
|
||||
|
||||
memset(&tmp_table, 0, sizeof(tmp_table));
|
||||
tmp_table.table_name= (char*)table;
|
||||
tmp_table.db= (char*)db;
|
||||
tmp_table.mdl_request.init(MDL_key::GLOBAL, (db) ? db : "",
|
||||
(table) ? table : "",
|
||||
MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT);
|
||||
|
||||
if (!table || !find_temporary_table(thd, &tmp_table))
|
||||
{
|
||||
if (!(ka->keys= (wsrep_key_t*)my_malloc(sizeof(wsrep_key_t), MYF(0))))
|
||||
{
|
||||
WSREP_ERROR("Can't allocate memory for key_array");
|
||||
goto err;
|
||||
}
|
||||
ka->keys_len= 1;
|
||||
if (!(ka->keys[0].key_parts= (wsrep_buf_t*)
|
||||
my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
|
||||
{
|
||||
WSREP_ERROR("Can't allocate memory for key_parts");
|
||||
goto err;
|
||||
}
|
||||
ka->keys[0].key_parts_num= 2;
|
||||
if (!wsrep_prepare_key_for_isolation(
|
||||
db, table,
|
||||
(wsrep_buf_t*)ka->keys[0].key_parts,
|
||||
&ka->keys[0].key_parts_num))
|
||||
{
|
||||
WSREP_ERROR("Preparing keys for isolation failed");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
WSREP_ERROR("Can't allocate memory for key_array");
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (const TABLE_LIST* table= table_list; table; table= table->next_global)
|
||||
ka->keys_len= 1;
|
||||
if (!(ka->keys[0].key_parts= (wsrep_buf_t*)
|
||||
my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
|
||||
{
|
||||
if (!find_temporary_table(thd, table))
|
||||
{
|
||||
wsrep_key_t* tmp;
|
||||
tmp= (wsrep_key_t*)my_realloc(
|
||||
ka->keys, (ka->keys_len + 1) * sizeof(wsrep_key_t),
|
||||
MYF(MY_ALLOW_ZERO_PTR));
|
||||
|
||||
if (!tmp)
|
||||
{
|
||||
WSREP_ERROR("Can't allocate memory for key_array");
|
||||
goto err;
|
||||
}
|
||||
ka->keys= tmp;
|
||||
if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*)
|
||||
my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
|
||||
{
|
||||
WSREP_ERROR("Can't allocate memory for key_parts");
|
||||
goto err;
|
||||
}
|
||||
ka->keys[ka->keys_len].key_parts_num= 2;
|
||||
++ka->keys_len;
|
||||
if (!wsrep_prepare_key_for_isolation(
|
||||
table->db, table->table_name,
|
||||
(wsrep_buf_t*)ka->keys[ka->keys_len - 1].key_parts,
|
||||
&ka->keys[ka->keys_len - 1].key_parts_num))
|
||||
{
|
||||
WSREP_ERROR("Preparing keys for isolation failed");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
WSREP_ERROR("Can't allocate memory for key_parts");
|
||||
goto err;
|
||||
}
|
||||
ka->keys[0].key_parts_num= 2;
|
||||
if (!wsrep_prepare_key_for_isolation(
|
||||
db, table,
|
||||
(wsrep_buf_t*)ka->keys[0].key_parts,
|
||||
&ka->keys[0].key_parts_num))
|
||||
{
|
||||
WSREP_ERROR("Preparing keys for isolation failed (1)");
|
||||
goto err;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const TABLE_LIST* table= table_list; table; table= table->next_global)
|
||||
{
|
||||
wsrep_key_t* tmp;
|
||||
tmp= (wsrep_key_t*)my_realloc(ka->keys,
|
||||
(ka->keys_len + 1) * sizeof(wsrep_key_t),
|
||||
MYF(0));
|
||||
if (!tmp)
|
||||
{
|
||||
WSREP_ERROR("Can't allocate memory for key_array");
|
||||
goto err;
|
||||
}
|
||||
ka->keys= tmp;
|
||||
if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*)
|
||||
my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
|
||||
{
|
||||
WSREP_ERROR("Can't allocate memory for key_parts");
|
||||
goto err;
|
||||
}
|
||||
ka->keys[ka->keys_len].key_parts_num= 2;
|
||||
++ka->keys_len;
|
||||
if (!wsrep_prepare_key_for_isolation(table->db, table->table_name,
|
||||
(wsrep_buf_t*)ka->keys[ka->keys_len - 1].key_parts,
|
||||
&ka->keys[ka->keys_len - 1].key_parts_num))
|
||||
{
|
||||
WSREP_ERROR("Preparing keys for isolation failed (2)");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
wsrep_keys_free(ka);
|
||||
return false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -1205,6 +1186,144 @@ create_view_query(THD *thd, uchar** buf, size_t* buf_len)
|
||||
return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len);
|
||||
}
|
||||
|
||||
/*
|
||||
Rewrite DROP TABLE for TOI. Temporary tables are eliminated from
|
||||
the query as they are visible only to client connection.
|
||||
|
||||
TODO: See comments for sql_base.cc:drop_temporary_table() and refine
|
||||
the function to deal with transactional locked tables.
|
||||
*/
|
||||
static int wsrep_drop_table_query(THD* thd, uchar** buf, size_t* buf_len)
|
||||
{
|
||||
|
||||
LEX* lex= thd->lex;
|
||||
SELECT_LEX* select_lex= &lex->select_lex;
|
||||
TABLE_LIST* first_table= select_lex->table_list.first;
|
||||
String buff;
|
||||
|
||||
DBUG_ASSERT(!lex->drop_temporary);
|
||||
|
||||
bool found_temp_table= false;
|
||||
for (TABLE_LIST* table= first_table; table; table= table->next_global)
|
||||
{
|
||||
if (find_temporary_table(thd, table->db, table->table_name))
|
||||
{
|
||||
found_temp_table= true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_temp_table)
|
||||
{
|
||||
buff.append("DROP TABLE ");
|
||||
if (lex->check_exists)
|
||||
buff.append("IF EXISTS ");
|
||||
|
||||
for (TABLE_LIST* table= first_table; table; table= table->next_global)
|
||||
{
|
||||
if (!find_temporary_table(thd, table->db, table->table_name))
|
||||
{
|
||||
append_identifier(thd, &buff, table->db, strlen(table->db));
|
||||
buff.append(".");
|
||||
append_identifier(thd, &buff, table->table_name,
|
||||
strlen(table->table_name));
|
||||
buff.append(",");
|
||||
}
|
||||
}
|
||||
|
||||
/* Chop the last comma */
|
||||
buff.chop();
|
||||
buff.append(" /* generated by wsrep */");
|
||||
|
||||
WSREP_DEBUG("Rewrote '%s' as '%s'", thd->query(), buff.ptr());
|
||||
|
||||
return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
return wsrep_to_buf_helper(thd, thd->query(), thd->query_length(),
|
||||
buf, buf_len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Decide if statement should run in TOI.
|
||||
|
||||
Look if table or table_list contain temporary tables. If the
|
||||
statement affects only temporary tables, statement should not run
|
||||
in TOI. If the table list contains mix of regular and temporary tables
|
||||
(DROP TABLE, OPTIMIZE, ANALYZE), statement should be run in TOI but
|
||||
should be rewritten at later time for replication to contain only
|
||||
non-temporary tables.
|
||||
*/
|
||||
static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
|
||||
const TABLE_LIST *table_list)
|
||||
{
|
||||
DBUG_ASSERT(!table || db);
|
||||
DBUG_ASSERT(table_list || db);
|
||||
|
||||
LEX* lex= thd->lex;
|
||||
SELECT_LEX* select_lex= &lex->select_lex;
|
||||
TABLE_LIST* first_table= select_lex->table_list.first;
|
||||
|
||||
switch (lex->sql_command)
|
||||
{
|
||||
case SQLCOM_CREATE_TABLE:
|
||||
DBUG_ASSERT(!table_list);
|
||||
if (thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case SQLCOM_CREATE_VIEW:
|
||||
|
||||
DBUG_ASSERT(!table_list);
|
||||
DBUG_ASSERT(first_table); /* First table is view name */
|
||||
/*
|
||||
If any of the remaining tables refer to temporary table error
|
||||
is returned to client, so TOI can be skipped
|
||||
*/
|
||||
for (TABLE_LIST* it= first_table->next_global; it; it= it->next_global)
|
||||
{
|
||||
if (find_temporary_table(thd, it))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
case SQLCOM_CREATE_TRIGGER:
|
||||
|
||||
DBUG_ASSERT(!table_list);
|
||||
DBUG_ASSERT(first_table);
|
||||
|
||||
if (find_temporary_table(thd, first_table))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
if (table && !find_temporary_table(thd, db, table))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (table_list)
|
||||
{
|
||||
for (TABLE_LIST* table= first_table; table; table= table->next_global)
|
||||
{
|
||||
if (!find_temporary_table(thd, table->db, table->table_name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return !(table || table_list);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
returns:
|
||||
0: statement was replicated as TOI
|
||||
@ -1220,6 +1339,12 @@ static int wsrep_TOI_begin(THD *thd, const char *query, char *db_, char *table_,
|
||||
int buf_err;
|
||||
int rc= 0;
|
||||
|
||||
if (wsrep_can_run_in_toi(thd, db_, table_, table_list) == false)
|
||||
{
|
||||
WSREP_DEBUG("No TOI for %s", WSREP_QUERY(thd));
|
||||
return 1;
|
||||
}
|
||||
|
||||
WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
|
||||
thd->wsrep_exec_mode, thd->query() );
|
||||
switch (thd->lex->sql_command)
|
||||
@ -1255,9 +1380,9 @@ static int wsrep_TOI_begin(THD *thd, const char *query, char *db_, char *table_,
|
||||
|
||||
wsrep_key_arr_t key_arr= {0, 0};
|
||||
struct wsrep_buf buff = { buf, buf_len };
|
||||
if (!buf_err &&
|
||||
wsrep_prepare_keys_for_isolation(thd, db_, table_, table_list, &key_arr)&&
|
||||
key_arr.keys_len > 0 &&
|
||||
if (!buf_err &&
|
||||
!wsrep_prepare_keys_for_isolation(thd, db_, table_, table_list, &key_arr) &&
|
||||
key_arr.keys_len > 0 &&
|
||||
WSREP_OK == (ret = wsrep->to_execute_start(wsrep, thd->thread_id,
|
||||
key_arr.keys, key_arr.keys_len,
|
||||
&buff, 1,
|
||||
@ -1453,9 +1578,12 @@ int wsrep_to_isolation_begin(THD *thd, const char *query, char *db_, char *table
|
||||
if (thd->variables.wsrep_on && thd->wsrep_exec_mode==LOCAL_STATE)
|
||||
{
|
||||
switch (thd->variables.wsrep_OSU_method) {
|
||||
case WSREP_OSU_TOI: ret = wsrep_TOI_begin(thd, query, db_, table_,
|
||||
table_list); break;
|
||||
case WSREP_OSU_RSU: ret = wsrep_RSU_begin(thd, db_, table_); break;
|
||||
case WSREP_OSU_TOI:
|
||||
ret = wsrep_TOI_begin(thd, query, db_, table_, table_list);
|
||||
break;
|
||||
case WSREP_OSU_RSU:
|
||||
ret = wsrep_RSU_begin(thd, db_, table_);
|
||||
break;
|
||||
default:
|
||||
WSREP_ERROR("Unsupported OSU method: %lu",
|
||||
thd->variables.wsrep_OSU_method);
|
||||
|
@ -337,9 +337,6 @@ void wsrep_init_sidno(const wsrep_uuid_t&);
|
||||
|
||||
bool wsrep_node_is_donor();
|
||||
bool wsrep_node_is_synced();
|
||||
int wsrep_replicate_drop_query(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
bool drop_temporary, bool dont_log_query);
|
||||
|
||||
|
||||
#define WSREP_MYSQL_DB (char *)"mysql"
|
||||
#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) \
|
||||
|
Loading…
x
Reference in New Issue
Block a user