summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc603
1 files changed, 578 insertions, 25 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 019fd55e3d8..066acfb015a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2008, 2013, Monty Program Ab
+ Copyright (c) 2008, 2014, Monty Program Ab
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
@@ -103,6 +103,14 @@
#include "../storage/maria/ha_maria.h"
#endif
+#include "wsrep_mysqld.h"
+#include "wsrep_thd.h"
+
+#ifdef WITH_WSREP
+static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
+ Parser_state *parser_state);
+#endif /* WITH_WSREP */
+
/**
@defgroup Runtime_Environment Runtime Environment
@{
@@ -890,6 +898,19 @@ bool do_command(THD *thd)
enum enum_server_command command;
DBUG_ENTER("do_command");
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ {
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->wsrep_query_state= QUERY_IDLE;
+ if (thd->wsrep_conflict_state==MUST_ABORT)
+ {
+ wsrep_client_rollback(thd);
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+#endif /* WITH_WSREP */
+
/*
indicator of uninitialized lex => normal flow of errors handling
(see my_message_sql)
@@ -937,6 +958,29 @@ bool do_command(THD *thd)
thd->m_server_idle= TRUE;
packet_length= my_net_read(net);
thd->m_server_idle= FALSE;
+#ifdef WITH_WSREP
+ if (WSREP(thd)) {
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+
+ /* these THD's are aborted or are aborting during being idle */
+ if (thd->wsrep_conflict_state == ABORTING)
+ {
+ while (thd->wsrep_conflict_state == ABORTING) {
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ my_sleep(1000);
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ }
+ thd->store_globals();
+ }
+ else if (thd->wsrep_conflict_state == ABORTED)
+ {
+ thd->store_globals();
+ }
+
+ thd->wsrep_query_state= QUERY_EXEC;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+#endif /* WITH_WSREP */
if (packet_length == packet_error)
{
@@ -944,6 +988,19 @@ bool do_command(THD *thd)
net->error,
vio_description(net->vio)));
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ {
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_conflict_state == MUST_ABORT)
+ {
+ DBUG_PRINT("wsrep",("aborted for wsrep rollback: %lu", thd->real_id));
+ wsrep_client_rollback(thd);
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+#endif /* WITH_WSREP */
+
/* Instrument this broken statement as "statement/com/error" */
thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
com_statement_info[COM_END].
@@ -998,12 +1055,71 @@ bool do_command(THD *thd)
vio_description(net->vio), command,
command_name[command].str));
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ {
+ /*
+ * bail out if DB snapshot has not been installed. We however,
+ * allow queries "SET" and "SHOW", they are trapped later in execute_command
+ */
+ if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready &&
+ command != COM_QUERY &&
+ command != COM_PING &&
+ command != COM_QUIT &&
+ command != COM_PROCESS_INFO &&
+ command != COM_PROCESS_KILL &&
+ command != COM_SET_OPTION &&
+ command != COM_SHUTDOWN &&
+ command != COM_SLEEP &&
+ command != COM_STATISTICS &&
+ command != COM_TIME &&
+ command != COM_END
+ ) {
+ my_message(ER_UNKNOWN_COM_ERROR,
+ "WSREP has not yet prepared node for application use",
+ MYF(0));
+ thd->protocol->end_statement();
+ return_value= FALSE;
+ goto out;
+ }
+ }
+#endif /* WITH_WSREP */
/* Restore read timeout value */
my_net_set_read_timeout(net, thd->variables.net_read_timeout);
DBUG_ASSERT(packet_length);
DBUG_ASSERT(!thd->apc_target.is_enabled());
return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1));
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ {
+ while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT)
+ {
+ WSREP_DEBUG("Retry autocommit for: %s\n", thd->wsrep_retry_query);
+ CHARSET_INFO *current_charset = thd->variables.character_set_client;
+ if (!is_supported_parser_charset(current_charset))
+ {
+ /* Do not use non-supported parser character sets */
+ WSREP_WARN("Current client character set is non-supported parser "
+ "character set: %s", current_charset->csname);
+ thd->variables.character_set_client = &my_charset_latin1;
+ WSREP_WARN("For retry temporally setting character set to : %s",
+ my_charset_latin1.csname);
+ }
+ return_value= dispatch_command(command, thd, thd->wsrep_retry_query,
+ thd->wsrep_retry_query_len);
+ thd->variables.character_set_client = current_charset;
+ }
+
+ if (thd->wsrep_retry_query && thd->wsrep_conflict_state != REPLAYING)
+ {
+ my_free(thd->wsrep_retry_query);
+ thd->wsrep_retry_query = NULL;
+ thd->wsrep_retry_query_len = 0;
+ thd->wsrep_retry_command = COM_CONNECT;
+ }
+ }
+#endif /* WITH_WSREP */
DBUG_ASSERT(!thd->apc_target.is_enabled());
out:
@@ -1027,7 +1143,7 @@ out:
@retval FALSE The statement isn't updating any relevant tables.
*/
-static my_bool deny_updates_if_read_only_option(THD *thd,
+my_bool deny_updates_if_read_only_option(THD *thd,
TABLE_LIST *all_tables)
{
DBUG_ENTER("deny_updates_if_read_only_option");
@@ -1081,6 +1197,7 @@ static my_bool deny_updates_if_read_only_option(THD *thd,
DBUG_RETURN(FALSE);
}
+
/**
Perform one connection-level (COM_XXXX) command.
@@ -1110,6 +1227,43 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_ENTER("dispatch_command");
DBUG_PRINT("info", ("command: %d", command));
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ {
+ if (!thd->in_multi_stmt_transaction_mode())
+ {
+ thd->wsrep_PA_safe= true;
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->wsrep_query_state= QUERY_EXEC;
+ if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT)
+ {
+ thd->wsrep_conflict_state= NO_CONFLICT;
+ }
+ if (thd->wsrep_conflict_state== MUST_ABORT)
+ {
+ wsrep_client_rollback(thd);
+ }
+ if (thd->wsrep_conflict_state== ABORTED)
+ {
+ my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
+ WSREP_DEBUG("Deadlock error for: %s", thd->query());
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ thd->killed = NOT_KILLED;
+ thd->mysys_var->abort = 0;
+ thd->wsrep_conflict_state = NO_CONFLICT;
+ thd->wsrep_retry_counter = 0;
+ /*
+ Increment threads running to compensate dec_thread_running() called
+ after dispatch_end label.
+ */
+ inc_thread_running();
+ goto dispatch_end;
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+#endif /* WITH_WSREP */
#if defined(ENABLED_PROFILING)
thd->profiling.start_new_query();
#endif
@@ -1306,7 +1460,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (parser_state.init(thd, thd->query(), thd->query_length()))
break;
- mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
+#ifdef WITH_WSREP
+ if (WSREP_ON)
+ wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
+ else
+#endif /* WITH_WSREP */
+ mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) &&
! thd->is_error())
@@ -1380,10 +1539,20 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
Count each statement from the client.
*/
statistic_increment(thd->status_var.questions, &LOCK_status);
- thd->set_time(); /* Reset the query start time. */
+
+ if(IF_WSREP(!WSREP(thd), 1))
+ thd->set_time(); /* Reset the query start time. */
+
parser_state.reset(beginning_of_next_stmt, length);
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
- mysql_parse(thd, beginning_of_next_stmt, length, &parser_state);
+
+#ifdef WITH_WSREP
+ if (WSREP_ON)
+ wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state);
+ else
+#endif /* WITH_WSREP */
+ mysql_parse(thd, beginning_of_next_stmt, length, &parser_state);
+
}
DBUG_PRINT("info",("query ready"));
@@ -1720,15 +1889,39 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
- DBUG_ASSERT(thd->derived_tables == NULL &&
- (thd->open_tables == NULL ||
+#ifdef WITH_WSREP
+ dispatch_end:
+
+ if (WSREP(thd))
+ {
+ /* wsrep BF abort in query exec phase */
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if ((thd->wsrep_conflict_state != REPLAYING) &&
+ (thd->wsrep_conflict_state != RETRY_AUTOCOMMIT))
+ {
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ thd->update_server_status();
+ thd->protocol->end_statement();
+ query_cache_end_of_result(thd);
+ }
+ else
+ {
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+ }
+ else
+#endif /* WITH_WSREP */
+ {
+ DBUG_ASSERT(thd->derived_tables == NULL &&
+ (thd->open_tables == NULL ||
(thd->locked_tables_mode == LTM_LOCK_TABLES)));
- thd_proc_info(thd, "updating status");
- /* Finalize server status flags after executing a command. */
- thd->update_server_status();
- thd->protocol->end_statement();
- query_cache_end_of_result(thd);
+ thd_proc_info(thd, "updating status");
+ /* Finalize server status flags after executing a command. */
+ thd->update_server_status();
+ thd->protocol->end_statement();
+ query_cache_end_of_result(thd);
+ }
if (!thd->is_error() && !thd->killed_errno())
mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0);
@@ -2381,7 +2574,47 @@ mysql_execute_command(THD *thd)
#ifdef HAVE_REPLICATION
} /* endif unlikely slave */
#endif
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ {
+ /*
+ change LOCK TABLE WRITE to transaction
+ */
+ if (lex->sql_command== SQLCOM_LOCK_TABLES && wsrep_convert_LOCK_to_trx)
+ {
+ for (TABLE_LIST *table= all_tables; table; table= table->next_global)
+ {
+ if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ lex->sql_command= SQLCOM_BEGIN;
+ thd->wsrep_converted_lock_session= true;
+ break;
+ }
+ }
+ }
+ if (lex->sql_command== SQLCOM_UNLOCK_TABLES &&
+ thd->wsrep_converted_lock_session)
+ {
+ thd->wsrep_converted_lock_session= false;
+ lex->sql_command= SQLCOM_COMMIT;
+ lex->tx_release= TVL_NO;
+ }
+ /*
+ * bail out if DB snapshot has not been installed. We however,
+ * allow SET and SHOW queries
+ */
+ if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready &&
+ lex->sql_command != SQLCOM_SET_OPTION &&
+ !wsrep_is_show_query(lex->sql_command))
+ {
+ my_message(ER_UNKNOWN_COM_ERROR,
+ "WSREP has not yet prepared node for application use",
+ MYF(0));
+ goto error;
+ }
+ }
+#endif /* WITH_WSREP */
status_var_increment(thd->status_var.com_stat[lex->sql_command]);
thd->progress.report_to_client= MY_TEST(sql_command_flags[lex->sql_command] &
CF_REPORT_PROGRESS);
@@ -2423,12 +2656,16 @@ mysql_execute_command(THD *thd)
{
/* Commit the normal transaction if one is active. */
if (trans_commit_implicit(thd))
+ {
+ thd->mdl_context.release_transactional_locks();
+ WSREP_DEBUG("implicit commit failed, MDL released: %lu", thd->thread_id);
goto error;
+ }
/* Release metadata locks acquired in this transaction. */
thd->mdl_context.release_transactional_locks();
}
}
-
+
#ifndef DBUG_OFF
if (lex->sql_command != SQLCOM_SET_OPTION)
DEBUG_SYNC(thd,"before_execute_sql_command");
@@ -2481,6 +2718,10 @@ mysql_execute_command(THD *thd)
#endif
case SQLCOM_SHOW_STATUS:
{
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd))
+ goto error;
+#endif /* WITH_WSREP */
execute_show_status(thd, all_tables);
break;
}
@@ -2513,6 +2754,11 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_SHOW_STATUS_PROC:
case SQLCOM_SHOW_STATUS_FUNC:
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd))
+ goto error;
+#endif /* WITH_WSREP */
+
case SQLCOM_SHOW_DATABASES:
case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_TRIGGERS:
@@ -2521,16 +2767,27 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_PLUGINS:
case SQLCOM_SHOW_FIELDS:
case SQLCOM_SHOW_KEYS:
+#ifndef WITH_WSREP
case SQLCOM_SHOW_VARIABLES:
case SQLCOM_SHOW_CHARSETS:
case SQLCOM_SHOW_COLLATIONS:
case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SHOW_PROFILE:
+#endif /* WITH_WSREP */
case SQLCOM_SHOW_CLIENT_STATS:
case SQLCOM_SHOW_USER_STATS:
case SQLCOM_SHOW_TABLE_STATS:
case SQLCOM_SHOW_INDEX_STATS:
case SQLCOM_SELECT:
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd))
+ goto error;
+ case SQLCOM_SHOW_VARIABLES:
+ case SQLCOM_SHOW_CHARSETS:
+ case SQLCOM_SHOW_COLLATIONS:
+ case SQLCOM_SHOW_STORAGE_ENGINES:
+ case SQLCOM_SHOW_PROFILE:
+#endif /* WITH_WSREP */
{
thd->status_var.last_query_cost= 0.0;
@@ -2554,7 +2811,7 @@ mysql_execute_command(THD *thd)
res= execute_sqlcom_select(thd, all_tables);
break;
}
-case SQLCOM_PREPARE:
+ case SQLCOM_PREPARE:
{
mysql_sql_stmt_prepare(thd);
break;
@@ -2888,7 +3145,7 @@ case SQLCOM_PREPARE:
*/
if(lex->ignore)
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT);
-
+
if(lex->duplicates == DUP_REPLACE)
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT);
@@ -2900,9 +3157,9 @@ case SQLCOM_PREPARE:
raise a warning, as it may cause problems
(see 'NAME_CONST issues' in 'Binary Logging of Stored Programs')
*/
- if (thd->query_name_consts &&
+ if (thd->query_name_consts &&
mysql_bin_log.is_open() &&
- thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
+ WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT &&
!mysql_bin_log.is_query_in_union(thd, thd->query_id))
{
List_iterator_fast<Item> it(select_lex->item_list);
@@ -3017,6 +3274,15 @@ case SQLCOM_PREPARE:
}
else
{
+#ifdef WITH_WSREP
+ /* in STATEMENT format, we probably have to replicate also temporary
+ tables, like mysql replication does
+ */
+ if (WSREP_ON && (!thd->is_current_stmt_binlog_format_row() ||
+ !(create_info.options & HA_LEX_CREATE_TMP_TABLE)))
+ WSREP_TO_ISOLATION_BEGIN(create_table->db, create_table->table_name,
+ NULL)
+#endif /* WITH_WSREP */
/* Regular CREATE TABLE */
res= mysql_create_table(thd, create_table,
&create_info, &alter_info);
@@ -3055,6 +3321,7 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
+ WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL)
/*
Currently CREATE INDEX or DROP INDEX cause a full table rebuild
and thus classify as slow administrative statements just like
@@ -3172,6 +3439,7 @@ end_with_restore_list:
#endif /* HAVE_REPLICATION */
case SQLCOM_RENAME_TABLE:
{
+ WSREP_TO_ISOLATION_BEGIN(0, 0, first_table)
if (execute_rename_table(thd, first_table, all_tables))
goto error;
break;
@@ -3192,13 +3460,19 @@ end_with_restore_list:
#endif
#endif /* EMBEDDED_LIBRARY */
case SQLCOM_SHOW_CREATE:
+ {
DBUG_ASSERT(first_table == all_tables && first_table != 0);
#ifdef DONT_ALLOW_SHOW_COMMANDS
my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
MYF(0)); /* purecov: inspected */
goto error;
#else
- {
+
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd))
+ goto error;
+#endif /* WITH_WSREP */
+
/*
Access check:
SHOW CREATE TABLE require any privileges on the table level (ie
@@ -3256,11 +3530,16 @@ end_with_restore_list:
/* Access is granted. Execute the command. */
res= mysqld_show_create(thd, first_table);
break;
- }
#endif
+ }
case SQLCOM_CHECKSUM:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd))
+ goto error;
+#endif /* WITH_WSREP */
+
if (check_table_access(thd, SELECT_ACL, all_tables,
FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
@@ -3272,6 +3551,12 @@ end_with_restore_list:
{
ha_rows found= 0, updated= 0;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE))
+ goto error;
+#endif /* WITH_WSREP */
+
if (update_precheck(thd, all_tables))
break;
@@ -3308,6 +3593,11 @@ end_with_restore_list:
/* if we switched from normal update, rights are checked */
if (up_result != 2)
{
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE))
+ goto error;
+#endif /* WITH_WSREP */
if ((res= multi_update_precheck(thd, all_tables)))
break;
}
@@ -3377,6 +3667,12 @@ end_with_restore_list:
break;
}
case SQLCOM_REPLACE:
+ {
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE))
+ goto error;
+#endif /* WITH_WSREP */
#ifndef DBUG_OFF
if (mysql_bin_log.is_open())
{
@@ -3411,10 +3707,17 @@ end_with_restore_list:
DBUG_PRINT("debug", ("Just after generate_incident()"));
}
#endif
+ }
case SQLCOM_INSERT:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE))
+ goto error;
+#endif /* WITH_WSREP */
+
/*
Since INSERT DELAYED doesn't support temporary tables, we could
not pre-open temporary tables for SQLCOM_INSERT / SQLCOM_REPLACE.
@@ -3469,8 +3772,22 @@ end_with_restore_list:
select_result *sel_result;
bool explain= MY_TEST(lex->describe);
DBUG_ASSERT(first_table == all_tables && first_table != 0);
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE))
+ goto error;
+#endif /* WITH_WSREP */
+
if ((res= insert_precheck(thd, all_tables)))
break;
+#ifdef WITH_WSREP
+ if (WSREP(thd) && thd->wsrep_consistency_check == CONSISTENCY_CHECK_DECLARED)
+ {
+ thd->wsrep_consistency_check = CONSISTENCY_CHECK_RUNNING;
+ WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL);
+ }
+#endif /* WITH_WSREP */
+
/*
INSERT...SELECT...ON DUPLICATE KEY UPDATE/REPLACE SELECT/
INSERT...IGNORE...SELECT can be unsafe, unless ORDER BY PRIMARY KEY
@@ -3561,6 +3878,12 @@ end_with_restore_list:
{
select_result *sel_result=lex->result;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE))
+ goto error;
+#endif /* WITH_WSREP */
+
if ((res= delete_precheck(thd, all_tables)))
break;
DBUG_ASSERT(select_lex->offset_limit == 0);
@@ -3617,6 +3940,11 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
multi_delete *result;
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE))
+ goto error;
+#endif /* WITH_WSREP */
if ((res= multi_delete_precheck(thd, all_tables)))
break;
@@ -3687,6 +4015,21 @@ 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
+ if (WSREP(thd))
+ {
+ for (TABLE_LIST *table= all_tables; table; table= table->next_global)
+ {
+ if (!lex->drop_temporary &&
+ (!thd->is_current_stmt_binlog_format_row() ||
+ !find_temporary_table(thd, table)))
+ {
+ WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables);
+ break;
+ }
+ }
+ }
+#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
@@ -3700,8 +4043,8 @@ end_with_restore_list:
/* DDL and binlog write order are protected by metadata locks. */
res= mysql_rm_table(thd, first_table, lex->check_exists,
lex->drop_temporary);
+ break;
}
- break;
case SQLCOM_SHOW_PROCESSLIST:
if (!thd->security_ctx->priv_user[0] &&
check_global_access(thd,PROCESS_ACL))
@@ -3891,6 +4234,7 @@ end_with_restore_list:
#endif
if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0))
break;
+ WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL)
res= mysql_create_db(thd, lex->name.str, &create_info, 0);
break;
}
@@ -3922,6 +4266,7 @@ end_with_restore_list:
#endif
if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0))
break;
+ WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL)
res= mysql_rm_db(thd, lex->name.str, lex->check_exists, 0);
break;
}
@@ -3953,6 +4298,7 @@ end_with_restore_list:
res= 1;
break;
}
+ WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL)
res= mysql_upgrade_db(thd, db);
if (!res)
my_ok(thd);
@@ -3988,6 +4334,7 @@ end_with_restore_list:
#endif
if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0))
break;
+ WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL)
res= mysql_alter_db(thd, db->str, &create_info);
break;
}
@@ -4026,6 +4373,7 @@ end_with_restore_list:
if (res)
break;
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
{
@@ -4060,6 +4408,7 @@ end_with_restore_list:
lex->spname->m_name);
break;
case SQLCOM_DROP_EVENT:
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (!(res= Events::drop_event(thd,
lex->spname->m_db, lex->spname->m_name,
lex->check_exists)))
@@ -4074,6 +4423,7 @@ end_with_restore_list:
if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 0))
break;
#ifdef HAVE_DLOPEN
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (!(res = mysql_create_function(thd, &lex->udf)))
my_ok(thd);
#else
@@ -4089,6 +4439,7 @@ end_with_restore_list:
if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
/* Conditionally writes to binlog */
if (!(res= mysql_create_user(thd, lex->users_list,
lex->sql_command == SQLCOM_CREATE_ROLE)))
@@ -4102,6 +4453,7 @@ end_with_restore_list:
check_global_access(thd,CREATE_USER_ACL))
break;
/* Conditionally writes to binlog */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (!(res= mysql_drop_user(thd, lex->users_list,
lex->sql_command == SQLCOM_DROP_ROLE)))
my_ok(thd);
@@ -4113,6 +4465,7 @@ end_with_restore_list:
check_global_access(thd,CREATE_USER_ACL))
break;
/* Conditionally writes to binlog */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (!(res= mysql_rename_user(thd, lex->users_list)))
my_ok(thd);
break;
@@ -4124,6 +4477,7 @@ end_with_restore_list:
break;
/* Conditionally writes to binlog */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (!(res = mysql_revoke_all(thd, lex->users_list)))
my_ok(thd);
break;
@@ -4206,6 +4560,7 @@ end_with_restore_list:
lex->type == TYPE_ENUM_PROCEDURE, 0))
goto error;
/* Conditionally writes to binlog */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= mysql_routine_grant(thd, all_tables,
lex->type == TYPE_ENUM_PROCEDURE,
lex->users_list, grants,
@@ -4219,6 +4574,7 @@ end_with_restore_list:
all_tables, FALSE, UINT_MAX, FALSE))
goto error;
/* Conditionally writes to binlog */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= mysql_table_grant(thd, all_tables, lex->users_list,
lex->columns, lex->grant,
lex->sql_command == SQLCOM_REVOKE);
@@ -4234,6 +4590,7 @@ end_with_restore_list:
}
else
{
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
/* Conditionally writes to binlog */
res= mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
lex->sql_command == SQLCOM_REVOKE,
@@ -4402,6 +4759,7 @@ end_with_restore_list:
able to open it (with SQLCOM_HA_OPEN) in the first place.
*/
unit->set_limit(select_lex);
+
res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
lex->insert_list, lex->ha_rkey_mode, select_lex->where,
unit->select_limit_cnt, unit->offset_limit_cnt);
@@ -4410,7 +4768,11 @@ end_with_restore_list:
case SQLCOM_BEGIN:
DBUG_PRINT("info", ("Executing SQLCOM_BEGIN thd: %p", thd));
if (trans_begin(thd, lex->start_transaction_opt))
+ {
+ thd->mdl_context.release_transactional_locks();
+ WSREP_DEBUG("BEGIN failed, MDL released: %lu", thd->thread_id);
goto error;
+ }
my_ok(thd);
break;
case SQLCOM_COMMIT:
@@ -4424,7 +4786,11 @@ end_with_restore_list:
(thd->variables.completion_type == 2 &&
lex->tx_release != TVL_NO));
if (trans_commit(thd))
+ {
+ thd->mdl_context.release_transactional_locks();
+ WSREP_DEBUG("COMMIT failed, MDL released: %lu", thd->thread_id);
goto error;
+ }
thd->mdl_context.release_transactional_locks();
/* Begin transaction with the same isolation level. */
if (tx_chain)
@@ -4444,7 +4810,17 @@ end_with_restore_list:
thd->killed= KILL_CONNECTION;
thd->print_aborted_warning(3, "RELEASE");
}
- my_ok(thd);
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ {
+ if (thd->wsrep_conflict_state == NO_CONFLICT ||
+ thd->wsrep_conflict_state == REPLAYING)
+ {
+ my_ok(thd);
+ }
+ } else
+#endif /* WITH_WSREP */
+ my_ok(thd);
break;
}
case SQLCOM_ROLLBACK:
@@ -4459,7 +4835,11 @@ end_with_restore_list:
lex->tx_release != TVL_NO));
if (trans_rollback(thd))
+ {
+ thd->mdl_context.release_transactional_locks();
+ WSREP_DEBUG("rollback failed, MDL released: %lu", thd->thread_id);
goto error;
+ }
thd->mdl_context.release_transactional_locks();
/* Begin transaction with the same isolation level. */
if (tx_chain)
@@ -4476,8 +4856,17 @@ end_with_restore_list:
/* Disconnect the current client connection. */
if (tx_release)
thd->killed= KILL_CONNECTION;
- my_ok(thd);
- break;
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ {
+ if (thd->wsrep_conflict_state == NO_CONFLICT) {
+ my_ok(thd);
+ }
+ }
+ else
+#endif /* WITH_WSREP */
+ my_ok(thd);
+ break;
}
case SQLCOM_RELEASE_SAVEPOINT:
if (trans_release_savepoint(thd, lex->ident))
@@ -4545,6 +4934,7 @@ end_with_restore_list:
if (sp_process_definer(thd))
goto create_sp_error;
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= (sp_result= sp_create_routine(thd, lex->sphead->m_type, lex->sphead));
switch (sp_result) {
case SP_OK: {
@@ -4826,6 +5216,7 @@ create_sp_error:
if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
goto error;
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
/* Conditionally writes to binlog */
sp_result= sp_drop_routine(thd, type, lex->spname);
@@ -4943,6 +5334,7 @@ create_sp_error:
Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands
as specified through the thd->lex->create_view_mode flag.
*/
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
break;
}
@@ -4951,12 +5343,14 @@ create_sp_error:
if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE))
goto error;
/* Conditionally writes to binlog. */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
break;
}
case SQLCOM_CREATE_TRIGGER:
{
/* Conditionally writes to binlog. */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= mysql_create_or_drop_trigger(thd, all_tables, 1);
break;
@@ -4964,6 +5358,7 @@ create_sp_error:
case SQLCOM_DROP_TRIGGER:
{
/* Conditionally writes to binlog. */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= mysql_create_or_drop_trigger(thd, all_tables, 0);
break;
}
@@ -4984,7 +5379,11 @@ create_sp_error:
break;
case SQLCOM_XA_COMMIT:
if (trans_xa_commit(thd))
+ {
+ thd->mdl_context.release_transactional_locks();
+ WSREP_DEBUG("XA commit failed, MDL released: %lu", thd->thread_id);
goto error;
+ }
thd->mdl_context.release_transactional_locks();
/*
We've just done a commit, reset transaction
@@ -4996,7 +5395,11 @@ create_sp_error:
break;
case SQLCOM_XA_ROLLBACK:
if (trans_xa_rollback(thd))
+ {
+ thd->mdl_context.release_transactional_locks();
+ WSREP_DEBUG("XA rollback failed, MDL released: %lu", thd->thread_id);
goto error;
+ }
thd->mdl_context.release_transactional_locks();
/*
We've just done a rollback, reset transaction
@@ -5016,11 +5419,13 @@ create_sp_error:
my_ok(thd);
break;
case SQLCOM_INSTALL_PLUGIN:
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (! (res= mysql_install_plugin(thd, &thd->lex->comment,
&thd->lex->ident)))
my_ok(thd);
break;
case SQLCOM_UNINSTALL_PLUGIN:
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment,
&thd->lex->ident)))
my_ok(thd);
@@ -5169,6 +5574,9 @@ finish:
/* Free tables */
close_thread_tables(thd);
+#ifdef WITH_WSREP
+ thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK;
+#endif /* WITH_WSREP */
#ifndef DBUG_OFF
if (lex->sql_command != SQLCOM_SET_OPTION && ! thd->in_sub_stmt)
@@ -5222,6 +5630,22 @@ finish:
{
thd->mdl_context.release_statement_locks();
}
+ WSREP_TO_ISOLATION_END;
+
+#ifdef WITH_WSREP
+ /*
+ Force release of transactional locks if not in active MST and wsrep is on.
+ */
+ if (WSREP(thd) &&
+ ! thd->in_sub_stmt &&
+ ! thd->in_active_multi_stmt_transaction() &&
+ thd->mdl_context.has_transactional_locks())
+ {
+ WSREP_DEBUG("Forcing release of transactional locks for thd %lu",
+ thd->thread_id);
+ thd->mdl_context.release_transactional_locks();
+ }
+#endif /* WITH_WSREP */
DBUG_RETURN(res || thd->is_error());
}
@@ -5322,6 +5746,10 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
status_var_increment(thd->status_var.empty_queries);
else
status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count());
+#ifdef WITH_WSREP
+ if (WSREP_ON && lex->sql_command == SQLCOM_SHOW_STATUS)
+ wsrep_free_status(thd);
+#endif /* WITH_WSREP */
return res;
}
@@ -6160,6 +6588,27 @@ void THD::reset_for_next_command()
thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
+#ifdef WITH_WSREP
+ /*
+ Autoinc variables should be adjusted only for locally executed
+ transactions. Appliers and replayers are either processing ROW
+ events or get autoinc variable values from Query_log_event.
+ */
+ if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE)
+ {
+ if (wsrep_auto_increment_control)
+ {
+ if (thd->variables.auto_increment_offset !=
+ global_system_variables.auto_increment_offset)
+ thd->variables.auto_increment_offset=
+ global_system_variables.auto_increment_offset;
+ if (thd->variables.auto_increment_increment !=
+ global_system_variables.auto_increment_increment)
+ thd->variables.auto_increment_increment=
+ global_system_variables.auto_increment_increment;
+ }
+ }
+#endif /* WITH_WSREP */
thd->query_start_used= 0;
thd->query_start_sec_part_used= 0;
thd->is_fatal_error= thd->time_zone_used= 0;
@@ -6363,6 +6812,109 @@ void mysql_init_multi_delete(LEX *lex)
lex->query_tables_last= &lex->query_tables;
}
+#ifdef WITH_WSREP
+static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
+ Parser_state *parser_state)
+{
+ bool is_autocommit=
+ !thd->in_multi_stmt_transaction_mode() &&
+ thd->wsrep_conflict_state == NO_CONFLICT &&
+ !thd->wsrep_applier &&
+ wsrep_read_only_option(thd, thd->lex->query_tables);
+
+ do
+ {
+ if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT)
+ {
+ thd->wsrep_conflict_state= NO_CONFLICT;
+ /* Performance Schema Interface instrumentation, begin */
+ thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
+ com_statement_info[thd->get_command()].m_key);
+ MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(),
+ thd->query_length());
+ }
+ mysql_parse(thd, rawbuf, length, parser_state);
+
+ if (WSREP(thd)) {
+ /* wsrep BF abort in query exec phase */
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_conflict_state == MUST_ABORT) {
+ wsrep_client_rollback(thd);
+
+ WSREP_DEBUG("abort in exec query state, avoiding autocommit");
+ }
+
+ if (thd->wsrep_conflict_state== MUST_REPLAY)
+ {
+ wsrep_replay_transaction(thd);
+ }
+
+ /* setting error code for BF aborted trxs */
+ if (thd->wsrep_conflict_state == ABORTED ||
+ thd->wsrep_conflict_state == CERT_FAILURE)
+ {
+ mysql_reset_thd_for_next_command(thd);
+ thd->killed= NOT_KILLED;
+ if (is_autocommit &&
+ thd->lex->sql_command != SQLCOM_SELECT &&
+ (thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit))
+ {
+ WSREP_DEBUG("wsrep retrying AC query: %s",
+ (thd->query()) ? thd->query() : "void");
+
+ /* Performance Schema Interface instrumentation, end */
+ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
+ thd->m_statement_psi= NULL;
+ close_thread_tables(thd);
+
+ thd->wsrep_conflict_state= RETRY_AUTOCOMMIT;
+ thd->wsrep_retry_counter++; // grow
+ wsrep_copy_query(thd);
+ thd->set_time();
+ parser_state->reset(rawbuf, length);
+ }
+ else
+ {
+ WSREP_DEBUG("%s, thd: %lu is_AC: %d, retry: %lu - %lu SQL: %s",
+ (thd->wsrep_conflict_state == ABORTED) ?
+ "BF Aborted" : "cert failure",
+ thd->thread_id, is_autocommit, thd->wsrep_retry_counter,
+ thd->variables.wsrep_retry_autocommit, thd->query());
+ my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
+ thd->killed= NOT_KILLED;
+ thd->wsrep_conflict_state= NO_CONFLICT;
+ if (thd->wsrep_conflict_state != REPLAYING)
+ thd->wsrep_retry_counter= 0; // reset
+ }
+ }
+ else
+ {
+ set_if_smaller(thd->wsrep_retry_counter, 0); // reset; eventually ok
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+
+ /* If retry is requested clean up explain structure */
+ if (thd->wsrep_conflict_state == RETRY_AUTOCOMMIT && thd->lex->explain)
+ delete_explain_query(thd->lex);
+
+ } while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT);
+
+ if (thd->wsrep_retry_query)
+ {
+ WSREP_DEBUG("releasing retry_query: conf %d sent %d kill %d errno %d SQL %s",
+ thd->wsrep_conflict_state,
+ thd->get_stmt_da()->is_sent(),
+ thd->killed,
+ thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->sql_errno() : 0,
+ thd->wsrep_retry_query);
+ my_free(thd->wsrep_retry_query);
+ thd->wsrep_retry_query = NULL;
+ thd->wsrep_retry_query_len = 0;
+ thd->wsrep_retry_command = COM_CONNECT;
+ }
+}
+#endif /* WITH_WSREP */
/*
When you modify mysql_parse(), you may need to mofify
@@ -7392,8 +7944,9 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ
faster and do a harder kill than KILL_SYSTEM_THREAD;
*/
- if ((thd->security_ctx->master_access & SUPER_ACL) ||
- thd->security_ctx->user_matches(tmp->security_ctx))
+ if (((thd->security_ctx->master_access & SUPER_ACL) ||
+ thd->security_ctx->user_matches(tmp->security_ctx)) &&
+ IF_WSREP(!wsrep_thd_is_BF((void *)tmp, true), 1))
{
tmp->awake(kill_signal);
error=0;