Commit 04c6b03c authored by sjaakola's avatar sjaakola Committed by Jan Lindström

Refs: MW-360 * merged relevant parts of DROP TABLE query splitting from mysql-wsrep-features

parent a754387a
......@@ -4030,26 +4030,6 @@ case SQLCOM_PREPARE:
/* 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 @@ case SQLCOM_PREPARE:
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));
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;
}
}
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;
}
}
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;
}
return true;
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_) \
......
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