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.cc1202
1 files changed, 654 insertions, 548 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 6eb147d0480..3d43305431b 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -56,13 +56,6 @@
#include "sql_rename.h" // mysql_rename_tables
#include "sql_tablespace.h" // mysql_alter_tablespace
#include "hostname.h" // hostname_cache_refresh
-#include "sql_acl.h" // *_ACL, check_grant, is_acl_user,
- // has_any_table_level_privileges,
- // mysql_drop_user, mysql_rename_user,
- // check_grant_routine,
- // mysql_routine_grant,
- // mysql_show_grants,
- // sp_grant_privileges, ...
#include "sql_test.h" // mysql_print_status
#include "sql_select.h" // handle_select, mysql_select,
// mysql_explain_union
@@ -101,6 +94,7 @@
#include "sql_bootstrap.h"
#include "sql_sequence.h"
#include "opt_trace.h"
+#include "mysql/psi/mysql_sp.h"
#include "my_json_writer.h"
@@ -133,6 +127,10 @@ static void sql_kill_user(THD *thd, LEX_USER *user, killed_state state);
static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables);
static bool execute_show_status(THD *, TABLE_LIST *);
static bool check_rename_table(THD *, TABLE_LIST *, TABLE_LIST *);
+static bool generate_incident_event(THD *thd);
+static int show_create_db(THD *thd, LEX *lex);
+static bool alter_routine(THD *thd, LEX *lex);
+static bool drop_routine(THD *thd, LEX *lex);
const char *any_db="*any*"; // Special symbol for check_access
@@ -439,16 +437,13 @@ bool stmt_causes_implicit_commit(THD *thd, uint mask)
DBUG_RETURN(FALSE);
switch (lex->sql_command) {
- case SQLCOM_DROP_TABLE:
- case SQLCOM_DROP_SEQUENCE:
- skip= (lex->tmp_table() ||
- (thd->variables.option_bits & OPTION_GTID_BEGIN));
- break;
case SQLCOM_ALTER_TABLE:
case SQLCOM_ALTER_SEQUENCE:
/* If ALTER TABLE of non-temporary table, do implicit commit */
skip= (lex->tmp_table());
break;
+ case SQLCOM_DROP_TABLE:
+ case SQLCOM_DROP_SEQUENCE:
case SQLCOM_CREATE_TABLE:
case SQLCOM_CREATE_SEQUENCE:
/*
@@ -679,7 +674,7 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_SHOW_CREATE_USER]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND;
- sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_BINLOG_STAT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND;
@@ -990,7 +985,7 @@ int bootstrap(MYSQL_FILE *file)
thd->bootstrap=1;
my_net_init(&thd->net,(st_vio*) 0, thd, MYF(0));
thd->max_client_packet_length= thd->net.max_packet;
- thd->security_ctx->master_access= ~(ulong)0;
+ thd->security_ctx->master_access= ALL_KNOWN_ACL;
#ifndef EMBEDDED_LIBRARY
mysql_thread_set_psi_id(thd->thread_id);
@@ -1002,7 +997,8 @@ int bootstrap(MYSQL_FILE *file)
thd->thread_stack= (char*) &thd;
thd->store_globals();
- thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
+ thd->security_ctx->user= (char*) my_strdup(key_memory_MPVIO_EXT_auth_info,
+ "boot", MYF(MY_WME));
thd->security_ctx->priv_user[0]= thd->security_ctx->priv_host[0]=
thd->security_ctx->priv_role[0]= 0;
/*
@@ -1101,7 +1097,7 @@ int bootstrap(MYSQL_FILE *file)
thd->reset_kill_query(); /* Ensure that killed_errmsg is released */
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
+ thd->transaction->free();
thd->lex->restore_set_statement_var();
}
delete thd;
@@ -1289,7 +1285,7 @@ bool do_command(THD *thd)
Aborted by background rollbacker thread.
Handle error here and jump straight to out
*/
- if (wsrep_before_command(thd))
+ if (unlikely(wsrep_service_started) && wsrep_before_command(thd))
{
thd->store_globals();
WSREP_LOG_THD(thd, "enter found BF aborted");
@@ -1366,7 +1362,8 @@ out:
if (packet_length != packet_error)
{
/* there was a command to process, and before_command() has been called */
- wsrep_after_command_after_result(thd);
+ if (unlikely(wsrep_service_started))
+ wsrep_after_command_after_result(thd);
}
#endif /* WITH_WSREP */
DBUG_RETURN(return_value);
@@ -1397,8 +1394,7 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables)
LEX *lex= thd->lex;
/* Super user is allowed to do changes */
- if (((ulong)(thd->security_ctx->master_access & SUPER_ACL) ==
- (ulong)SUPER_ACL))
+ if ((thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) != NO_ACL)
DBUG_RETURN(FALSE);
/* Check if command doesn't update anything */
@@ -1438,10 +1434,10 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables)
static my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables)
{
int opt_readonly_saved = opt_readonly;
- ulong flag_saved = (ulong)(thd->security_ctx->master_access & SUPER_ACL);
+ privilege_t flag_saved= thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY;
opt_readonly = 0;
- thd->security_ctx->master_access &= ~SUPER_ACL;
+ thd->security_ctx->master_access &= ~PRIV_IGNORE_READ_ONLY;
my_bool ret = !deny_updates_if_read_only_option(thd, all_tables);
@@ -1458,7 +1454,7 @@ static void wsrep_copy_query(THD *thd)
if (thd->wsrep_retry_query) {
my_free(thd->wsrep_retry_query);
}
- thd->wsrep_retry_query = (char *)my_malloc(
+ thd->wsrep_retry_query = (char *)my_malloc(PSI_INSTRUMENT_ME,
thd->wsrep_retry_query_len + 1, MYF(0));
strncpy(thd->wsrep_retry_query, thd->query(), thd->wsrep_retry_query_len);
thd->wsrep_retry_query[thd->wsrep_retry_query_len] = '\0';
@@ -1506,6 +1502,31 @@ uint maria_multi_check(THD *thd, char *packet, size_t packet_length)
}
+#if defined(WITH_ARIA_STORAGE_ENGINE)
+class Silence_all_errors : public Internal_error_handler
+{
+ char m_message[MYSQL_ERRMSG_SIZE];
+ int error;
+public:
+ Silence_all_errors():error(0) {}
+ virtual ~Silence_all_errors() {}
+
+ virtual bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sql_state,
+ Sql_condition::enum_warning_level *level,
+ const char* msg,
+ Sql_condition ** cond_hdl)
+ {
+ error= sql_errno;
+ *cond_hdl= NULL;
+ strmake_buf(m_message, msg);
+ return true; // Error handled
+ }
+};
+#endif
+
+
/**
Perform one connection-level (COM_XXXX) command.
@@ -1658,14 +1679,20 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
thd->status_var.com_other++;
#ifdef WITH_WSREP
- wsrep_after_command_ignore_result(thd);
- wsrep_close(thd);
+ if (unlikely(wsrep_service_started))
+ {
+ wsrep_after_command_ignore_result(thd);
+ wsrep_close(thd);
+ }
#endif /* WITH_WSREP */
thd->change_user();
thd->clear_error(); // if errors from rollback
#ifdef WITH_WSREP
- wsrep_open(thd);
- wsrep_before_command(thd);
+ if (unlikely(wsrep_service_started))
+ {
+ wsrep_open(thd);
+ wsrep_before_command(thd);
+ }
#endif /* WITH_WSREP */
/* Restore original charset from client authentication packet.*/
if(thd->org_charset)
@@ -1679,13 +1706,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
status_var_increment(thd->status_var.com_other);
#ifdef WITH_WSREP
- wsrep_after_command_ignore_result(thd);
- wsrep_close(thd);
+ if (unlikely(wsrep_service_started))
+ {
+ wsrep_after_command_ignore_result(thd);
+ wsrep_close(thd);
+ }
#endif /* WITH_WSREP */
thd->change_user();
#ifdef WITH_WSREP
- wsrep_open(thd);
- wsrep_before_command(thd);
+ if (unlikely(wsrep_service_started))
+ {
+ wsrep_open(thd);
+ wsrep_before_command(thd);
+ }
#endif /* WITH_WSREP */
thd->clear_error(); // if errors from rollback
@@ -1719,7 +1752,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
else
auth_rc= acl_authenticate(thd, packet_length);
- mysql_audit_notify_connection_change_user(thd);
+ mysql_audit_notify_connection_change_user(thd, &save_security_ctx);
if (auth_rc)
{
/* Free user if allocated by acl_authenticate */
@@ -1846,8 +1879,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
*/
char *beginning_of_next_stmt= (char*) parser_state.m_lip.found_semicolon;
- ha_maria_implicit_commit(thd, FALSE);
-
/* Finalize server status flags after executing a statement. */
thd->update_server_status();
thd->protocol->end_statement();
@@ -1900,8 +1931,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
com_statement_info[command].m_key,
thd->db.str, thd->db.length,
- thd->charset());
- THD_STAGE_INFO(thd, stage_init);
+ thd->charset(), NULL);
+ THD_STAGE_INFO(thd, stage_starting);
MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, beginning_of_next_stmt,
length);
@@ -2043,7 +2074,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
mysqld_list_fields(thd,&table_list,fields);
thd->lex->unit.cleanup();
/* No need to rollback statement transaction, it's not started. */
- DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ DBUG_ASSERT(thd->transaction->stmt.is_empty());
close_thread_tables(thd);
thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
@@ -2083,7 +2114,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
status_var_increment(thd->status_var.com_other);
thd->query_plan_flags|= QPLAN_ADMIN;
- if (check_global_access(thd, REPL_SLAVE_ACL))
+ if (check_global_access(thd, PRIV_COM_BINLOG_DUMP))
break;
/* TODO: The following has to be changed to an 8 byte integer */
@@ -2213,13 +2244,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
my_snprintf(buff, buff_len - 1,
"Uptime: %lu Threads: %d Questions: %lu "
- "Slow queries: %lu Opens: %lu Flush tables: %lld "
+ "Slow queries: %lu Opens: %lu "
"Open tables: %u Queries per second avg: %u.%03u",
uptime,
(int) thread_count, (ulong) thd->query_id,
current_global_status_var->long_query_count,
current_global_status_var->opened_tables,
- tdc_refresh_version(),
tc_records(),
(uint) (queries_per_second1000 / 1000),
(uint) (queries_per_second1000 % 1000));
@@ -2240,12 +2270,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_PROCESS_INFO:
status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]);
if (!thd->security_ctx->priv_user[0] &&
- check_global_access(thd, PROCESS_ACL))
+ check_global_access(thd, PRIV_COM_PROCESS_INFO))
break;
general_log_print(thd, command, NullS);
mysqld_list_processes(thd,
- thd->security_ctx->master_access & PROCESS_ACL ?
- NullS : thd->security_ctx->priv_user, 0);
+ thd->security_ctx->master_access & PRIV_COM_PROCESS_INFO ?
+ NullS : thd->security_ctx->priv_user, 0);
break;
case COM_PROCESS_KILL:
{
@@ -2277,7 +2307,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_DEBUG:
status_var_increment(thd->status_var.com_other);
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_DEBUG))
break; /* purecov: inspected */
mysql_print_status();
general_log_print(thd, command, NullS);
@@ -2374,46 +2404,52 @@ com_multi_end:
}
dispatch_end:
+ do_end_of_statement= true;
#ifdef WITH_WSREP
/*
- BF aborted before sending response back to client
+ Next test should really be WSREP(thd), but that causes a failure when doing
+ 'set WSREP_ON=0'
*/
- if (thd->killed == KILL_QUERY)
- {
- WSREP_DEBUG("THD is killed at dispatch_end");
- }
- wsrep_after_command_before_result(thd);
- if (wsrep_current_error(thd) &&
- !(command == COM_STMT_PREPARE ||
- command == COM_STMT_FETCH ||
- command == COM_STMT_SEND_LONG_DATA ||
- command == COM_STMT_CLOSE
- ))
- {
- /* todo: Pass wsrep client state current error to override */
- wsrep_override_error(thd, wsrep_current_error(thd),
- wsrep_current_error_status(thd));
- WSREP_LOG_THD(thd, "leave");
- }
- if (WSREP(thd))
+ if (unlikely(wsrep_service_started))
{
/*
- MDEV-10812
- In the case of COM_QUIT/COM_STMT_CLOSE thread status should be disabled.
+ BF aborted before sending response back to client
*/
- DBUG_ASSERT((command != COM_QUIT && command != COM_STMT_CLOSE)
+ if (thd->killed == KILL_QUERY)
+ {
+ WSREP_DEBUG("THD is killed at dispatch_end");
+ }
+ wsrep_after_command_before_result(thd);
+ if (wsrep_current_error(thd) &&
+ !(command == COM_STMT_PREPARE ||
+ command == COM_STMT_FETCH ||
+ command == COM_STMT_SEND_LONG_DATA ||
+ command == COM_STMT_CLOSE
+ ))
+ {
+ /* todo: Pass wsrep client state current error to override */
+ wsrep_override_error(thd, wsrep_current_error(thd),
+ wsrep_current_error_status(thd));
+ WSREP_LOG_THD(thd, "leave");
+ }
+ if (WSREP(thd))
+ {
+ /*
+ MDEV-10812
+ In the case of COM_QUIT/COM_STMT_CLOSE thread status should be disabled.
+ */
+ DBUG_ASSERT((command != COM_QUIT && command != COM_STMT_CLOSE)
|| thd->get_stmt_da()->is_disabled());
- DBUG_ASSERT(thd->wsrep_trx().state() != wsrep::transaction::s_replaying);
- /* wsrep BF abort in query exec phase */
- mysql_mutex_lock(&thd->LOCK_thd_kill);
- do_end_of_statement= thd_is_connection_alive(thd);
- mysql_mutex_unlock(&thd->LOCK_thd_kill);
+ DBUG_ASSERT(thd->wsrep_trx().state() != wsrep::transaction::s_replaying);
+ /* wsrep BF abort in query exec phase */
+ mysql_mutex_lock(&thd->LOCK_thd_kill);
+ do_end_of_statement= thd_is_connection_alive(thd);
+ mysql_mutex_unlock(&thd->LOCK_thd_kill);
+ }
}
- else
- do_end_of_statement= true;
-
#endif /* WITH_WSREP */
+
if (do_end_of_statement)
{
DBUG_ASSERT(thd->derived_tables == NULL &&
@@ -2671,6 +2707,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
/* 'parent_lex' is used in init_query() so it must be before it. */
schema_select_lex->parent_lex= lex;
schema_select_lex->init_query();
+ schema_select_lex->select_number= 0;
if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
MDL_SHARED_READ))
DBUG_RETURN(1);
@@ -2831,7 +2868,7 @@ bool sp_process_definer(THD *thd)
!my_strcasecmp(system_charset_info, d->host.str,
thd->security_ctx->priv_host);
if (!curuserhost && !currole &&
- check_global_access(thd, SUPER_ACL, false))
+ check_global_access(thd, PRIV_DEFINER_CLAUSE, false))
DBUG_RETURN(TRUE);
}
@@ -2863,7 +2900,8 @@ bool sp_process_definer(THD *thd)
@return FALSE in case of success, TRUE in case of error.
*/
-static bool lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
+static bool __attribute__ ((noinline))
+lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
{
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
MDL_deadlock_and_lock_abort_error_handler deadlock_handler;
@@ -3024,7 +3062,8 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
}
-static int mysql_create_routine(THD *thd, LEX *lex)
+static int __attribute__ ((noinline))
+mysql_create_routine(THD *thd, LEX *lex)
{
DBUG_ASSERT(lex->sphead != 0);
DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
@@ -3053,7 +3092,7 @@ static int mysql_create_routine(THD *thd, LEX *lex)
const LEX_CSTRING *name= lex->sphead->name();
#ifdef HAVE_DLOPEN
- if (lex->sphead->m_handler->type() == TYPE_ENUM_FUNCTION)
+ if (lex->sphead->m_handler->type() == SP_TYPE_FUNCTION)
{
udf_func *udf = find_udf(name->str, name->length);
@@ -3069,6 +3108,7 @@ static int mysql_create_routine(THD *thd, LEX *lex)
return true;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
if (!lex->sphead->m_handler->sp_create_routine(thd, lex->sphead))
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -3086,14 +3126,13 @@ static int mysql_create_routine(THD *thd, LEX *lex)
statement takes metadata locks should be detected by a deadlock
detector in MDL subsystem and reported as errors.
- No need to commit/rollback statement transaction, it's not started.
-
TODO: Long-term we should either ensure that implicit GRANT statement
is written into binary log as a separate statement or make both
creation of routine and implicit GRANT parts of one fully atomic
statement.
*/
- DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ if (trans_commit_stmt(thd))
+ goto wsrep_error_label;
close_thread_tables(thd);
/*
Check if the definer exists on slave,
@@ -3137,7 +3176,9 @@ static int mysql_create_routine(THD *thd, LEX *lex)
#endif
return false;
}
-#ifdef WITH_WSREP
+ (void) trans_commit_stmt(thd);
+
+#if !defined(NO_EMBEDDED_ACCESS_CHECKS) || defined(WITH_WSREP)
wsrep_error_label:
#endif
return true;
@@ -3159,7 +3200,8 @@ wsrep_error_label:
from other cases: bad database error, no access error.
This can be done by testing thd->is_error().
*/
-static bool prepare_db_action(THD *thd, ulong want_access, LEX_CSTRING *dbname)
+static bool prepare_db_action(THD *thd, privilege_t want_access,
+ LEX_CSTRING *dbname)
{
if (check_db_name((LEX_STRING*)dbname))
{
@@ -3313,7 +3355,7 @@ mysql_execute_command(THD *thd)
DBUG_RETURN(1);
}
- DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt);
+ DBUG_ASSERT(thd->transaction->stmt.is_empty() || thd->in_sub_stmt);
/*
Each statement or replication event which might produce deadlock
should handle transaction rollback on its own. So by the start of
@@ -3389,7 +3431,8 @@ mysql_execute_command(THD *thd)
according to slave filtering rules.
Returning success without producing any errors in this case.
*/
- if (!thd->lex->create_info.if_exists())
+ if (!thd->lex->create_info.if_exists() &&
+ !(thd->variables.option_bits & OPTION_IF_EXISTS))
DBUG_RETURN(0);
/*
DROP TRIGGER IF NOT EXISTS will return without an error later
@@ -3539,7 +3582,7 @@ mysql_execute_command(THD *thd)
thd->progress.report_to_client= MY_TEST(sql_command_flags[lex->sql_command] &
CF_REPORT_PROGRESS);
- DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
+ DBUG_ASSERT(thd->transaction->stmt.modified_non_trans_table == FALSE);
/* store old value of binlog format */
enum_binlog_format orig_binlog_format,orig_current_stmt_binlog_format;
@@ -3696,7 +3739,7 @@ mysql_execute_command(THD *thd)
*/
DBUG_ASSERT(! thd->in_sub_stmt);
/* Statement transaction still should not be started. */
- DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ DBUG_ASSERT(thd->transaction->stmt.is_empty());
if (!(thd->variables.option_bits & OPTION_GTID_BEGIN))
{
/* Commit the normal transaction if one is active. */
@@ -3710,7 +3753,7 @@ mysql_execute_command(THD *thd)
goto error;
}
}
- thd->transaction.stmt.mark_trans_did_ddl();
+ thd->transaction->stmt.mark_trans_did_ddl();
#ifdef WITH_WSREP
/* Clean up the previous transaction on implicit commit */
if (wsrep_thd_is_local(thd) && wsrep_after_statement(thd))
@@ -3816,7 +3859,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_EXPLAIN:
{
if (!thd->security_ctx->priv_user[0] &&
- check_global_access(thd,PROCESS_ACL))
+ check_global_access(thd, PRIV_STMT_SHOW_EXPLAIN))
break;
/*
@@ -3880,8 +3923,8 @@ mysql_execute_command(THD *thd)
lex->exchange != NULL implies SELECT .. INTO OUTFILE and this
requires FILE_ACL access.
*/
- ulong privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL :
- SELECT_ACL;
+ privilege_t privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL :
+ SELECT_ACL;
if (all_tables)
res= check_table_access(thd,
@@ -3934,7 +3977,7 @@ mysql_execute_command(THD *thd)
#ifndef EMBEDDED_LIBRARY
case SQLCOM_PURGE:
{
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_PURGE_BINLOG))
goto error;
/* PURGE MASTER LOGS TO 'file' */
res = purge_master_logs(thd, lex->to_log);
@@ -3944,7 +3987,7 @@ mysql_execute_command(THD *thd)
{
Item *it;
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_PURGE_BINLOG))
goto error;
/* PURGE MASTER LOGS BEFORE 'data' */
it= (Item *)lex->value_list.head();
@@ -3991,16 +4034,23 @@ mysql_execute_command(THD *thd)
#ifdef HAVE_REPLICATION
case SQLCOM_SHOW_SLAVE_HOSTS:
{
- if (check_global_access(thd, REPL_SLAVE_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_SLAVE_HOSTS))
goto error;
res = show_slave_hosts(thd);
break;
}
- case SQLCOM_SHOW_RELAYLOG_EVENTS: /* fall through */
+ case SQLCOM_SHOW_RELAYLOG_EVENTS:
+ {
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
+ if (check_global_access(thd, PRIV_STMT_SHOW_RELAYLOG_EVENTS))
+ goto error;
+ res = mysql_show_binlog_events(thd);
+ break;
+ }
case SQLCOM_SHOW_BINLOG_EVENTS:
{
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
- if (check_global_access(thd, REPL_SLAVE_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_BINLOG_EVENTS))
goto error;
res = mysql_show_binlog_events(thd);
break;
@@ -4037,7 +4087,7 @@ mysql_execute_command(THD *thd)
bool new_master= 0;
bool master_info_added;
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_CHANGE_MASTER))
goto error;
/*
In this code it's ok to use LOCK_active_mi as we are adding new things
@@ -4091,35 +4141,11 @@ mysql_execute_command(THD *thd)
mysql_mutex_unlock(&LOCK_active_mi);
break;
}
- case SQLCOM_SHOW_SLAVE_STAT:
- {
- /* Accept one of two privileges */
- if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
- goto error;
- if (lex->verbose)
- {
- mysql_mutex_lock(&LOCK_active_mi);
- res= show_all_master_info(thd);
- mysql_mutex_unlock(&LOCK_active_mi);
- }
- else
- {
- LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
- Master_info *mi;
- if ((mi= get_master_info(&lex_mi->connection_name,
- Sql_condition::WARN_LEVEL_ERROR)))
- {
- res= show_master_info(thd, mi, 0);
- mi->release();
- }
- }
- break;
- }
- case SQLCOM_SHOW_MASTER_STAT:
+ case SQLCOM_SHOW_BINLOG_STAT:
{
/* Accept one of two privileges */
- if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_BINLOG_STATUS))
goto error;
res = show_binlog_info(thd);
break;
@@ -4128,20 +4154,23 @@ mysql_execute_command(THD *thd)
#endif /* HAVE_REPLICATION */
case SQLCOM_SHOW_ENGINE_STATUS:
{
- if (check_global_access(thd, PROCESS_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_ENGINE_STATUS))
goto error;
res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS);
break;
}
case SQLCOM_SHOW_ENGINE_MUTEX:
{
- if (check_global_access(thd, PROCESS_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_ENGINE_MUTEX))
goto error;
res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
break;
}
- case SQLCOM_CREATE_INDEX:
case SQLCOM_DROP_INDEX:
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+ /* fall through */
+ case SQLCOM_CREATE_INDEX:
/*
CREATE INDEX and DROP INDEX are implemented by calling ALTER
TABLE with proper arguments.
@@ -4161,16 +4190,18 @@ mysql_execute_command(THD *thd)
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.str, first_table->table_name.str, NULL);
bzero((char*) &create_info, sizeof(create_info));
create_info.db_type= 0;
create_info.row_type= ROW_TYPE_NOT_USED;
create_info.default_table_charset= thd->variables.collation_database;
+ create_info.alter_info= &alter_info;
+
+ WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL);
res= mysql_alter_table(thd, &first_table->db, &first_table->table_name,
&create_info, first_table, &alter_info,
- 0, (ORDER*) 0, 0);
+ 0, (ORDER*) 0, 0, lex->if_exists());
break;
}
#ifdef HAVE_REPLICATION
@@ -4282,7 +4313,10 @@ mysql_execute_command(THD *thd)
WSREP_TO_ISOLATION_BEGIN(0, 0, first_table);
- if (mysql_rename_tables(thd, first_table, 0))
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+
+ if (mysql_rename_tables(thd, first_table, 0, lex->if_exists()))
goto error;
break;
}
@@ -4294,7 +4328,7 @@ mysql_execute_command(THD *thd)
goto error;
#else
{
- if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
+ if (check_global_access(thd, PRIV_STMT_SHOW_BINARY_LOGS))
goto error;
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
res = show_binlogs(thd);
@@ -4368,7 +4402,7 @@ mysql_execute_command(THD *thd)
select_lex->where,
select_lex->order_list.elements,
select_lex->order_list.first,
- unit->select_limit_cnt,
+ unit->lim.get_select_limit(),
lex->ignore, &found, &updated);
MYSQL_UPDATE_DONE(res, found, updated);
/* mysql_update return 2 if we need to switch to multi-update */
@@ -4431,7 +4465,7 @@ mysql_execute_command(THD *thd)
if (res)
break;
if (opt_readonly &&
- !(thd->security_ctx->master_access & SUPER_ACL) &&
+ !(thd->security_ctx->master_access & PRIV_IGNORE_READ_ONLY) &&
some_non_temp_table_to_be_updated(thd, all_tables))
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
@@ -4468,44 +4502,13 @@ mysql_execute_command(THD *thd)
break;
}
case SQLCOM_REPLACE:
-#ifndef DBUG_OFF
- if (mysql_bin_log.is_open())
- {
- /*
- Generate an incident log event before writing the real event
- to the binary log. We put this event is before the statement
- since that makes it simpler to check that the statement was
- not executed on the slave (since incidents usually stop the
- slave).
-
- Observe that any row events that are generated will be
- generated before.
-
- This is only for testing purposes and will not be present in a
- release build.
- */
-
- Incident incident= INCIDENT_NONE;
- DBUG_PRINT("debug", ("Just before generate_incident()"));
- DBUG_EXECUTE_IF("incident_database_resync_on_replace",
- incident= INCIDENT_LOST_EVENTS;);
- if (incident)
- {
- Incident_log_event ev(thd, incident);
- (void) mysql_bin_log.write(&ev); /* error is ignored */
- if (mysql_bin_log.rotate_and_purge(true))
- {
- res= 1;
- break;
- }
- }
- DBUG_PRINT("debug", ("Just after generate_incident()"));
- }
-#endif
+ if ((res= generate_incident_event(thd)))
+ break;
/* fall through */
case SQLCOM_INSERT:
{
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
+ select_result *sel_result= NULL;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
@@ -4526,9 +4529,41 @@ mysql_execute_command(THD *thd)
break;
MYSQL_INSERT_START(thd->query());
+ Protocol* save_protocol=NULL;
+
+ if (lex->has_returning())
+ {
+ status_var_increment(thd->status_var.feature_insert_returning);
+
+ /* This is INSERT ... RETURNING. It will return output to the client */
+ if (thd->lex->analyze_stmt)
+ {
+ /*
+ Actually, it is ANALYZE .. INSERT .. RETURNING. We need to produce
+ output and then discard it.
+ */
+ sel_result= new (thd->mem_root) select_send_analyze(thd);
+ save_protocol= thd->protocol;
+ thd->protocol= new Protocol_discard(thd);
+ }
+ else
+ {
+ if (!(sel_result= new (thd->mem_root) select_send(thd)))
+ goto error;
+ }
+ }
+
res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
- lex->update_list, lex->value_list,
- lex->duplicates, lex->ignore);
+ lex->update_list, lex->value_list,
+ lex->duplicates, lex->ignore, sel_result);
+ if (save_protocol)
+ {
+ delete thd->protocol;
+ thd->protocol= save_protocol;
+ }
+ if (!res && thd->lex->analyze_stmt)
+ res= thd->lex->explain->send_explain(thd);
+ delete sel_result;
MYSQL_INSERT_DONE(res, (ulong) thd->get_row_count_func());
/*
If we have inserted into a VIEW, and the base table has
@@ -4543,12 +4578,8 @@ mysql_execute_command(THD *thd)
#ifdef ENABLED_DEBUG_SYNC
DBUG_EXECUTE_IF("after_mysql_insert",
{
- const char act1[]=
- "now "
- "wait_for signal.continue";
- const char act2[]=
- "now "
- "signal signal.continued";
+ const char act1[]= "now wait_for signal.continue";
+ const char act2[]= "now signal signal.continued";
DBUG_ASSERT(debug_sync_service);
DBUG_ASSERT(!debug_sync_set_action(thd,
STRING_WITH_LEN(act1)));
@@ -4564,6 +4595,7 @@ mysql_execute_command(THD *thd)
{
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
select_insert *sel_result;
+ select_result *result= NULL;
bool explain= MY_TEST(lex->describe);
DBUG_ASSERT(first_table == all_tables && first_table != 0);
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
@@ -4612,6 +4644,31 @@ mysql_execute_command(THD *thd)
Only the INSERT table should be merged. Other will be handled by
select.
*/
+
+ Protocol* save_protocol=NULL;
+
+ if (lex->has_returning())
+ {
+ status_var_increment(thd->status_var.feature_insert_returning);
+
+ /* This is INSERT ... RETURNING. It will return output to the client */
+ if (thd->lex->analyze_stmt)
+ {
+ /*
+ Actually, it is ANALYZE .. INSERT .. RETURNING. We need to produce
+ output and then discard it.
+ */
+ result= new (thd->mem_root) select_send_analyze(thd);
+ save_protocol= thd->protocol;
+ thd->protocol= new Protocol_discard(thd);
+ }
+ else
+ {
+ if (!(result= new (thd->mem_root) select_send(thd)))
+ goto error;
+ }
+ }
+
/* Skip first table, which is the table we are inserting in */
TABLE_LIST *second_table= first_table->next_local;
/*
@@ -4622,17 +4679,19 @@ mysql_execute_command(THD *thd)
be done properly as well)
*/
select_lex->table_list.first= second_table;
- select_lex->context.table_list=
+ select_lex->context.table_list=
select_lex->context.first_name_resolution_table= second_table;
- res= mysql_insert_select_prepare(thd);
- if (!res && (sel_result= new (thd->mem_root) select_insert(thd,
- first_table,
- first_table->table,
- &lex->field_list,
- &lex->update_list,
- &lex->value_list,
- lex->duplicates,
- lex->ignore)))
+ res= mysql_insert_select_prepare(thd, result);
+ if (!res &&
+ (sel_result= new (thd->mem_root)
+ select_insert(thd, first_table,
+ first_table->table,
+ &lex->field_list,
+ &lex->update_list,
+ &lex->value_list,
+ lex->duplicates,
+ lex->ignore,
+ result)))
{
if (lex->analyze_stmt)
((select_result_interceptor*)sel_result)->disable_my_ok_calls();
@@ -4668,7 +4727,20 @@ mysql_execute_command(THD *thd)
}
delete sel_result;
}
-
+ else if (res < 0)
+ {
+ /*
+ Insert should be ignored but we have to log the query in statement
+ format in the binary log
+ */
+ res= thd->binlog_current_query_unfiltered();
+ }
+ delete result;
+ if (save_protocol)
+ {
+ delete thd->protocol;
+ thd->protocol= save_protocol;
+ }
if (!res && (explain || lex->analyze_stmt))
res= thd->lex->explain->send_explain(thd);
@@ -4701,10 +4773,9 @@ mysql_execute_command(THD *thd)
unit->set_limit(select_lex);
MYSQL_DELETE_START(thd->query());
- Protocol * UNINIT_VAR(save_protocol);
- bool replaced_protocol= false;
+ Protocol *save_protocol= NULL;
- if (!select_lex->item_list.is_empty())
+ if (lex->has_returning())
{
/* This is DELETE ... RETURNING. It will return output to the client */
if (thd->lex->analyze_stmt)
@@ -4714,7 +4785,6 @@ mysql_execute_command(THD *thd)
output and then discard it.
*/
sel_result= new (thd->mem_root) select_send_analyze(thd);
- replaced_protocol= true;
save_protocol= thd->protocol;
thd->protocol= new Protocol_discard(thd);
}
@@ -4727,10 +4797,10 @@ mysql_execute_command(THD *thd)
res = mysql_delete(thd, all_tables,
select_lex->where, &select_lex->order_list,
- unit->select_limit_cnt, select_lex->options,
+ unit->lim.get_select_limit(), select_lex->options,
lex->result ? lex->result : sel_result);
- if (replaced_protocol)
+ if (save_protocol)
{
delete thd->protocol;
thd->protocol= save_protocol;
@@ -4784,7 +4854,6 @@ mysql_execute_command(THD *thd)
goto multi_delete_error;
res= mysql_select(thd,
select_lex->get_table_list(),
- select_lex->with_wild,
select_lex->item_list,
select_lex->where,
0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
@@ -4832,6 +4901,8 @@ mysql_execute_command(THD *thd)
}
else
{
+ if (thd->transaction->xid_state.check_has_uncommitted_xa())
+ goto error;
status_var_decrement(thd->status_var.com_stat[lex->sql_command]);
status_var_increment(thd->status_var.com_drop_tmp_table);
@@ -4844,10 +4915,12 @@ mysql_execute_command(THD *thd)
recover from multi-table DROP TABLE that was aborted in the
middle.
*/
- if (thd->slave_thread && !thd->slave_expected_error &&
- slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT)
+ if ((thd->slave_thread && !thd->slave_expected_error &&
+ slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT) ||
+ thd->variables.option_bits & OPTION_IF_EXISTS)
lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+#ifdef WITH_WSREP
if (WSREP(thd))
{
for (TABLE_LIST *table= all_tables; table; table= table->next_global)
@@ -4861,10 +4934,11 @@ mysql_execute_command(THD *thd)
}
}
}
-
+#endif /* WITH_WSREP */
+
/* DDL and binlog write order are protected by metadata locks. */
res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table(),
- lex->table_type == TABLE_TYPE_SEQUENCE);
+ lex->table_type == TABLE_TYPE_SEQUENCE, 0);
/*
When dropping temporary tables if @@session_track_state_change is ON
@@ -4872,19 +4946,19 @@ mysql_execute_command(THD *thd)
*/
if(!res && (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
- SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
+ thd->session_tracker.state_change.mark_as_changed(thd);
}
break;
}
case SQLCOM_SHOW_PROCESSLIST:
if (!thd->security_ctx->priv_user[0] &&
- check_global_access(thd,PROCESS_ACL))
+ check_global_access(thd, PRIV_STMT_SHOW_PROCESSLIST))
break;
mysqld_list_processes(thd,
- (thd->security_ctx->master_access & PROCESS_ACL ?
- NullS :
- thd->security_ctx->priv_user),
- lex->verbose);
+ (thd->security_ctx->master_access & PRIV_STMT_SHOW_PROCESSLIST ?
+ NullS :
+ thd->security_ctx->priv_user),
+ lex->verbose);
break;
case SQLCOM_SHOW_AUTHORS:
res= mysqld_show_authors(thd);
@@ -4919,17 +4993,18 @@ mysql_execute_command(THD *thd)
case SQLCOM_LOAD:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- uint privilege= (lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | DELETE_ACL : INSERT_ACL) |
- (lex->local_file ? 0 : FILE_ACL);
+ privilege_t privilege= (lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL) |
+ (lex->local_file ? NO_ACL : FILE_ACL);
if (lex->local_file)
{
if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
!opt_local_infile)
{
- my_message(ER_NOT_ALLOWED_COMMAND, ER_THD(thd, ER_NOT_ALLOWED_COMMAND), MYF(0));
- goto error;
+ my_message(ER_LOAD_INFILE_CAPABILITY_DISABLED,
+ ER_THD(thd, ER_LOAD_INFILE_CAPABILITY_DISABLED), MYF(0));
+ goto error;
}
}
@@ -4979,9 +5054,11 @@ mysql_execute_command(THD *thd)
if (thd->variables.option_bits & OPTION_TABLE_LOCK)
{
res= trans_commit_implicit(thd);
- thd->locked_tables_list.unlock_locked_tables(thd);
+ if (thd->locked_tables_list.unlock_locked_tables(thd))
+ res= 1;
thd->mdl_context.release_transactional_locks();
thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
+ thd->reset_binlog_for_next_statement();
}
if (thd->global_read_lock.is_acquired() &&
thd->current_backup_stage == BACKUP_FINISHED)
@@ -4993,7 +5070,8 @@ mysql_execute_command(THD *thd)
case SQLCOM_LOCK_TABLES:
/* We must end the transaction first, regardless of anything */
res= trans_commit_implicit(thd);
- thd->locked_tables_list.unlock_locked_tables(thd);
+ if (thd->locked_tables_list.unlock_locked_tables(thd))
+ res= 1;
/* Release transactional metadata locks. */
thd->mdl_context.release_transactional_locks();
if (res)
@@ -5074,16 +5152,23 @@ mysql_execute_command(THD *thd)
(CREATE_ACL | DROP_ACL) : CREATE_ACL,
&lex->name))
break;
+
WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL);
+
res= mysql_create_db(thd, &lex->name,
lex->create_info, &lex->create_info);
break;
}
case SQLCOM_DROP_DB:
{
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+
if (prepare_db_action(thd, DROP_ACL, &lex->name))
break;
+
WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL);
+
res= mysql_rm_db(thd, &lex->name, lex->if_exists());
break;
}
@@ -5115,7 +5200,9 @@ mysql_execute_command(THD *thd)
res= 1;
break;
}
+
WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL);
+
res= mysql_upgrade_db(thd, db);
if (!res)
my_ok(thd);
@@ -5126,31 +5213,16 @@ mysql_execute_command(THD *thd)
LEX_CSTRING *db= &lex->name;
if (prepare_db_action(thd, ALTER_ACL, db))
break;
+
WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL);
+
res= mysql_alter_db(thd, db, &lex->create_info);
break;
}
case SQLCOM_SHOW_CREATE_DB:
- {
- char db_name_buff[NAME_LEN+1];
- LEX_CSTRING db_name;
- DBUG_EXECUTE_IF("4x_server_emul",
- my_error(ER_UNKNOWN_ERROR, MYF(0)); goto error;);
-
- db_name.str= db_name_buff;
- db_name.length= lex->name.length;
- strmov(db_name_buff, lex->name.str);
-
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
-
- if (check_db_name((LEX_STRING*) &db_name))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
- break;
- }
- res= mysqld_show_create_db(thd, &db_name, &lex->name, lex->create_info);
+ res= show_create_db(thd, lex);
break;
- }
case SQLCOM_CREATE_EVENT:
case SQLCOM_ALTER_EVENT:
#ifdef HAVE_EVENT_SCHEDULER
@@ -5217,6 +5289,7 @@ mysql_execute_command(THD *thd)
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
@@ -5234,7 +5307,9 @@ mysql_execute_command(THD *thd)
"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)))
@@ -5247,8 +5322,10 @@ mysql_execute_command(THD *thd)
if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
- /* Conditionally writes to binlog */
+
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
+ /* Conditionally writes to binlog */
if (!(res= mysql_drop_user(thd, lex->users_list,
lex->sql_command == SQLCOM_DROP_ROLE)))
my_ok(thd);
@@ -5260,8 +5337,10 @@ mysql_execute_command(THD *thd)
if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
- /* Conditionally writes to binlog */
+
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
+ /* Conditionally writes to binlog */
if (lex->sql_command == SQLCOM_ALTER_USER)
res= mysql_alter_user(thd, lex->users_list);
else
@@ -5276,123 +5355,19 @@ mysql_execute_command(THD *thd)
check_global_access(thd,CREATE_USER_ACL))
break;
- /* Conditionally writes to binlog */
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
+ /* Conditionally writes to binlog */
if (!(res = mysql_revoke_all(thd, lex->users_list)))
my_ok(thd);
break;
}
- case SQLCOM_REVOKE:
- case SQLCOM_GRANT:
- {
- if (lex->type != TYPE_ENUM_PROXY &&
- check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
- first_table ? first_table->db.str : select_lex->db.str,
- first_table ? &first_table->grant.privilege : NULL,
- first_table ? &first_table->grant.m_internal : NULL,
- first_table ? 0 : 1, 0))
- goto error;
-
- /* Replicate current user as grantor */
- thd->binlog_invoker(false);
-
- if (thd->security_ctx->user) // If not replication
- {
- LEX_USER *user;
- bool first_user= TRUE;
- List_iterator <LEX_USER> user_list(lex->users_list);
- while ((user= user_list++))
- {
- if (specialflag & SPECIAL_NO_RESOLVE &&
- hostname_requires_resolving(user->host.str))
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARN_HOSTNAME_WONT_WORK,
- ER_THD(thd, ER_WARN_HOSTNAME_WONT_WORK));
-
- /*
- GRANT/REVOKE PROXY has the target user as a first entry in the list.
- */
- if (lex->type == TYPE_ENUM_PROXY && first_user)
- {
- if (!(user= get_current_user(thd, user)) || !user->host.str)
- goto error;
-
- first_user= FALSE;
- if (acl_check_proxy_grant_access (thd, user->host.str, user->user.str,
- lex->grant & GRANT_ACL))
- goto error;
- }
- }
- }
- if (first_table)
- {
- const Sp_handler *sph= Sp_handler::handler((stored_procedure_type)
- lex->type);
- if (sph)
- {
- uint grants= lex->all_privileges
- ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
- : lex->grant;
- if (check_grant_routine(thd, grants | GRANT_ACL, all_tables, sph, 0))
- goto error;
- /* Conditionally writes to binlog */
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
- res= mysql_routine_grant(thd, all_tables, sph,
- lex->users_list, grants,
- lex->sql_command == SQLCOM_REVOKE, TRUE);
- if (!res)
- my_ok(thd);
- }
- else
- {
- if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL),
- 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);
- }
- }
- else
- {
- if (lex->columns.elements || (lex->type && lex->type != TYPE_ENUM_PROXY))
- {
- my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER_THD(thd, ER_ILLEGAL_GRANT_FOR_TABLE),
- MYF(0));
- goto error;
- }
- else
- {
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
- /* Conditionally writes to binlog */
- res= mysql_grant(thd, select_lex->db.str, lex->users_list, lex->grant,
- lex->sql_command == SQLCOM_REVOKE,
- lex->type == TYPE_ENUM_PROXY);
- }
- if (!res)
- {
- if (lex->sql_command == SQLCOM_GRANT)
- {
- List_iterator <LEX_USER> str_list(lex->users_list);
- LEX_USER *user, *tmp_user;
- while ((tmp_user=str_list++))
- {
- if (!(user= get_current_user(thd, tmp_user)))
- goto error;
- reset_mqh(user, 0);
- }
- }
- }
- }
- break;
- }
case SQLCOM_REVOKE_ROLE:
case SQLCOM_GRANT_ROLE:
{
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
if (!(res= mysql_grant_role(thd, lex->users_list,
lex->sql_command != SQLCOM_GRANT_ROLE)))
my_ok(thd);
@@ -5606,7 +5581,8 @@ mysql_execute_command(THD *thd)
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);
+ unit->lim.get_select_limit(),
+ unit->lim.get_offset_limit());
break;
case SQLCOM_BEGIN:
@@ -5721,159 +5697,35 @@ mysql_execute_command(THD *thd)
break; /* break super switch */
} /* end case group bracket */
case SQLCOM_COMPOUND:
+ {
+ sp_head *sp= lex->sphead;
DBUG_ASSERT(all_tables == 0);
DBUG_ASSERT(thd->in_sub_stmt == 0);
- lex->sphead->m_sql_mode= thd->variables.sql_mode;
+ sp->m_sql_mode= thd->variables.sql_mode;
+ sp->m_sp_share= MYSQL_GET_SP_SHARE(sp->m_handler->type(),
+ sp->m_db.str, static_cast<uint>(sp->m_db.length),
+ sp->m_name.str, static_cast<uint>(sp->m_name.length));
if (do_execute_sp(thd, lex->sphead))
goto error;
break;
+ }
case SQLCOM_ALTER_PROCEDURE:
case SQLCOM_ALTER_FUNCTION:
- {
- int sp_result;
- const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
- if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db,
- &lex->spname->m_name, sph, 0))
- goto error;
-
- /*
- Note that if you implement the capability of ALTER FUNCTION to
- alter the body of the function, this command should be made to
- follow the restrictions that log-bin-trust-function-creators=0
- already puts on CREATE FUNCTION.
- */
- /* Conditionally writes to binlog */
- sp_result= sph->sp_update_routine(thd, lex->spname, &lex->sp_chistics);
- switch (sp_result)
- {
- case SP_OK:
- my_ok(thd);
- break;
- case SP_KEY_NOT_FOUND:
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
- sph->type_str(), ErrConvDQName(lex->spname).ptr());
- goto error;
- default:
- my_error(ER_SP_CANT_ALTER, MYF(0),
- sph->type_str(), ErrConvDQName(lex->spname).ptr());
- goto error;
- }
- break;
- }
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+ if (alter_routine(thd, lex))
+ goto error;
+ break;
case SQLCOM_DROP_PROCEDURE:
case SQLCOM_DROP_FUNCTION:
case SQLCOM_DROP_PACKAGE:
case SQLCOM_DROP_PACKAGE_BODY:
- {
-#ifdef HAVE_DLOPEN
- if (lex->sql_command == SQLCOM_DROP_FUNCTION &&
- ! lex->spname->m_explicit_name)
- {
- /* DROP FUNCTION <non qualified name> */
- enum drop_udf_result rc= mysql_drop_function(thd,
- &lex->spname->m_name);
- if (rc == UDF_DEL_RESULT_DELETED)
- {
- my_ok(thd);
- break;
- }
-
- if (rc == UDF_DEL_RESULT_ERROR)
- goto error;
-
- DBUG_ASSERT(rc == UDF_DEL_RESULT_ABSENT);
-
- // If there was no current database, so it can not be SP
- if (lex->spname->m_db.str == NULL)
- {
- if (lex->if_exists())
- {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_SP_DOES_NOT_EXIST, ER_THD(thd, ER_SP_DOES_NOT_EXIST),
- "FUNCTION (UDF)", lex->spname->m_name.str);
- res= FALSE;
- my_ok(thd);
- break;
- }
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
- "FUNCTION (UDF)", lex->spname->m_name.str);
- goto error;
- }
- /* Fall thought to test for a stored function */
- }
-#endif
-
- int sp_result;
- const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
-
- if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db, &lex->spname->m_name,
- Sp_handler::handler(lex->sql_command), 0))
- goto error;
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
-
- /* Conditionally writes to binlog */
- sp_result= sph->sp_drop_routine(thd, lex->spname);
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /*
- We're going to issue an implicit REVOKE statement so we close all
- open tables. We have to keep metadata locks as this ensures that
- this statement is atomic against concurent FLUSH TABLES WITH READ
- LOCK. Deadlocks which can arise due to fact that this implicit
- statement takes metadata locks should be detected by a deadlock
- detector in MDL subsystem and reported as errors.
-
- No need to commit/rollback statement transaction, it's not started.
-
- TODO: Long-term we should either ensure that implicit REVOKE statement
- is written into binary log as a separate statement or make both
- dropping of routine and implicit REVOKE parts of one fully atomic
- statement.
- */
- DBUG_ASSERT(thd->transaction.stmt.is_empty());
- close_thread_tables(thd);
-
- if (sp_result != SP_KEY_NOT_FOUND &&
- sp_automatic_privileges && !opt_noacl &&
- sp_revoke_privileges(thd, lex->spname->m_db.str, lex->spname->m_name.str,
- Sp_handler::handler(lex->sql_command)))
- {
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_PROC_AUTO_REVOKE_FAIL,
- ER_THD(thd, ER_PROC_AUTO_REVOKE_FAIL));
- /* If this happens, an error should have been reported. */
- goto error;
- }
-#endif
-
- res= sp_result;
- switch (sp_result) {
- case SP_OK:
- my_ok(thd);
- break;
- case SP_KEY_NOT_FOUND:
- if (lex->if_exists())
- {
- res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_SP_DOES_NOT_EXIST, ER_THD(thd, ER_SP_DOES_NOT_EXIST),
- sph->type_str(),
- ErrConvDQName(lex->spname).ptr());
- if (!res)
- my_ok(thd);
- break;
- }
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
- sph->type_str(), ErrConvDQName(lex->spname).ptr());
- goto error;
- default:
- my_error(ER_SP_DROP_FAILED, MYF(0),
- sph->type_str(), ErrConvDQName(lex->spname).ptr());
- goto error;
- }
- break;
- }
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+ if (drop_routine(thd, lex))
+ goto error;
+ break;
case SQLCOM_SHOW_CREATE_PROC:
case SQLCOM_SHOW_CREATE_FUNC:
case SQLCOM_SHOW_CREATE_PACKAGE:
@@ -5937,8 +5789,13 @@ mysql_execute_command(THD *thd)
{
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);
+
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+
+ /* Conditionally writes to binlog. */
res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
break;
}
@@ -5951,6 +5808,9 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_DROP_TRIGGER:
{
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
+
/* Conditionally writes to binlog. */
res= mysql_create_or_drop_trigger(thd, all_tables, 0);
break;
@@ -6038,7 +5898,7 @@ mysql_execute_command(THD *thd)
{
DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER"));
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_CREATE_SERVER))
break;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
@@ -6051,7 +5911,7 @@ mysql_execute_command(THD *thd)
int error;
DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER"));
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_ALTER_SERVER))
break;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
@@ -6071,7 +5931,7 @@ mysql_execute_command(THD *thd)
int err_code;
DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER"));
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, PRIV_STMT_DROP_SERVER))
break;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
@@ -6104,12 +5964,19 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(first_table == all_tables && first_table != 0);
/* fall through */
case SQLCOM_ALTER_SEQUENCE:
+ case SQLCOM_SHOW_SLAVE_STAT:
case SQLCOM_SIGNAL:
case SQLCOM_RESIGNAL:
case SQLCOM_GET_DIAGNOSTICS:
case SQLCOM_CALL:
+ case SQLCOM_REVOKE:
+ case SQLCOM_GRANT:
+ if (thd->variables.option_bits & OPTION_IF_EXISTS)
+ lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
DBUG_ASSERT(lex->m_sql_cmd != NULL);
res= lex->m_sql_cmd->execute(thd);
+ DBUG_PRINT("result", ("res: %d killed: %d is_error(): %d",
+ res, thd->killed, thd->is_error()));
break;
default:
@@ -6170,7 +6037,6 @@ finish:
trans_commit_stmt(thd);
thd->get_stmt_da()->set_overwrite_status(false);
}
- ha_maria_implicit_commit(thd, FALSE);
}
/* Free tables. Set stage 'closing tables' */
@@ -6238,7 +6104,7 @@ finish:
#ifdef WITH_WSREP
thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK;
-
+
WSREP_TO_ISOLATION_END;
/*
Force release of transactional locks if not in active MST and wsrep is on.
@@ -6313,8 +6179,8 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
/*
Do like the original select_describe did: remove OFFSET from the
top-level LIMIT
- */
- result->reset_offset_limit();
+ */
+ result->remove_offset_limit();
if (lex->explain_json)
{
lex->explain->print_explain_json(result, lex->analyze_stmt);
@@ -6392,7 +6258,15 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
}
-static bool execute_show_status(THD *thd, TABLE_LIST *all_tables)
+/**
+ SHOW STATUS
+
+ Notes: This is noinline as we don't want to have system_status_var (> 3K)
+ to be on the stack of mysql_execute_command()
+*/
+
+static bool __attribute__ ((noinline))
+execute_show_status(THD *thd, TABLE_LIST *all_tables)
{
bool res;
system_status_var old_status_var= thd->status_var;
@@ -6402,6 +6276,7 @@ static bool execute_show_status(THD *thd, TABLE_LIST *all_tables)
UINT_MAX, FALSE)))
res= execute_sqlcom_select(thd, all_tables);
+ thd->initial_status_var= NULL;
/* Don't log SHOW STATUS commands to slow query log */
thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED |
SERVER_QUERY_NO_GOOD_INDEX_USED);
@@ -6477,8 +6352,9 @@ static TABLE *find_temporary_table_for_rename(THD *thd,
}
-static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
- TABLE_LIST *all_tables)
+static bool __attribute__ ((noinline))
+check_rename_table(THD *thd, TABLE_LIST *first_table,
+ TABLE_LIST *all_tables)
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *table;
@@ -6517,6 +6393,223 @@ static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
return 0;
}
+/*
+ Generate an incident log event before writing the real event
+ to the binary log. We put this event is before the statement
+ since that makes it simpler to check that the statement was
+ not executed on the slave (since incidents usually stop the
+ slave).
+
+ Observe that any row events that are generated will be generated before.
+
+ This is only for testing purposes and will not be present in a release build.
+*/
+
+#ifndef DBUG_OFF
+static bool __attribute__ ((noinline)) generate_incident_event(THD *thd)
+{
+ if (mysql_bin_log.is_open())
+ {
+
+ Incident incident= INCIDENT_NONE;
+ DBUG_PRINT("debug", ("Just before generate_incident()"));
+ DBUG_EXECUTE_IF("incident_database_resync_on_replace",
+ incident= INCIDENT_LOST_EVENTS;);
+ if (incident)
+ {
+ Incident_log_event ev(thd, incident);
+ (void) mysql_bin_log.write(&ev); /* error is ignored */
+ if (mysql_bin_log.rotate_and_purge(true))
+ return 1;
+ }
+ DBUG_PRINT("debug", ("Just after generate_incident()"));
+ }
+ return 0;
+}
+#else
+static bool generate_incident_event(THD *thd)
+{
+ return 0;
+}
+#endif
+
+
+static int __attribute__ ((noinline))
+show_create_db(THD *thd, LEX *lex)
+{
+ char db_name_buff[NAME_LEN+1];
+ LEX_CSTRING db_name;
+ DBUG_EXECUTE_IF("4x_server_emul",
+ my_error(ER_UNKNOWN_ERROR, MYF(0)); return 1;);
+
+ db_name.str= db_name_buff;
+ db_name.length= lex->name.length;
+ strmov(db_name_buff, lex->name.str);
+
+ if (check_db_name((LEX_STRING*) &db_name))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
+ return 1;
+ }
+ return mysqld_show_create_db(thd, &db_name, &lex->name, lex->create_info);
+}
+
+
+/**
+ Called on SQLCOM_ALTER_PROCEDURE and SQLCOM_ALTER_FUNCTION
+*/
+
+static bool __attribute__ ((noinline))
+alter_routine(THD *thd, LEX *lex)
+{
+ int sp_result;
+ const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
+ if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db,
+ &lex->spname->m_name, sph, 0))
+ return 1;
+ /*
+ Note that if you implement the capability of ALTER FUNCTION to
+ alter the body of the function, this command should be made to
+ follow the restrictions that log-bin-trust-function-creators=0
+ already puts on CREATE FUNCTION.
+ */
+ /* Conditionally writes to binlog */
+ sp_result= sph->sp_update_routine(thd, lex->spname, &lex->sp_chistics);
+ switch (sp_result) {
+ case SP_OK:
+ my_ok(thd);
+ return 0;
+ case SP_KEY_NOT_FOUND:
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ sph->type_str(), ErrConvDQName(lex->spname).ptr());
+ return 1;
+ default:
+ my_error(ER_SP_CANT_ALTER, MYF(0),
+ sph->type_str(), ErrConvDQName(lex->spname).ptr());
+ return 1;
+ }
+ return 0; /* purecov: deadcode */
+}
+
+
+static bool __attribute__ ((noinline))
+drop_routine(THD *thd, LEX *lex)
+{
+ int sp_result;
+#ifdef HAVE_DLOPEN
+ if (lex->sql_command == SQLCOM_DROP_FUNCTION &&
+ ! lex->spname->m_explicit_name)
+ {
+ /* DROP FUNCTION <non qualified name> */
+ enum drop_udf_result rc= mysql_drop_function(thd, &lex->spname->m_name);
+ switch (rc) {
+ case UDF_DEL_RESULT_DELETED:
+ my_ok(thd);
+ return 0;
+ case UDF_DEL_RESULT_ERROR:
+ return 1;
+ case UDF_DEL_RESULT_ABSENT:
+ goto absent;
+ }
+
+ DBUG_ASSERT("wrong return code" == 0);
+absent:
+ // If there was no current database, so it cannot be SP
+ if (!lex->spname->m_db.str)
+ {
+ if (lex->if_exists())
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_SP_DOES_NOT_EXIST,
+ ER_THD(thd, ER_SP_DOES_NOT_EXIST),
+ "FUNCTION (UDF)", lex->spname->m_name.str);
+ my_ok(thd);
+ return 0;
+ }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ "FUNCTION (UDF)", lex->spname->m_name.str);
+ return 1;
+ }
+ /* Fall trough to test for a stored function */
+ }
+#endif /* HAVE_DLOPEN */
+
+ const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
+
+ if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db,
+ &lex->spname->m_name,
+ Sp_handler::handler(lex->sql_command), 0))
+ return 1;
+
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
+ /* Conditionally writes to binlog */
+ sp_result= sph->sp_drop_routine(thd, lex->spname);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ We're going to issue an implicit REVOKE statement so we close all
+ open tables. We have to keep metadata locks as this ensures that
+ this statement is atomic against concurent FLUSH TABLES WITH READ
+ LOCK. Deadlocks which can arise due to fact that this implicit
+ statement takes metadata locks should be detected by a deadlock
+ detector in MDL subsystem and reported as errors.
+
+ TODO: Long-term we should either ensure that implicit REVOKE statement
+ is written into binary log as a separate statement or make both
+ dropping of routine and implicit REVOKE parts of one fully atomic
+ statement.
+ */
+ if (trans_commit_stmt(thd))
+ sp_result= SP_INTERNAL_ERROR;
+ close_thread_tables(thd);
+
+ if (sp_result != SP_KEY_NOT_FOUND &&
+ sp_automatic_privileges && !opt_noacl &&
+ sp_revoke_privileges(thd, lex->spname->m_db.str, lex->spname->m_name.str,
+ Sp_handler::handler(lex->sql_command)))
+ {
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_PROC_AUTO_REVOKE_FAIL,
+ ER_THD(thd, ER_PROC_AUTO_REVOKE_FAIL));
+ /* If this happens, an error should have been reported. */
+ return 1;
+ }
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+ switch (sp_result) {
+ case SP_OK:
+ my_ok(thd);
+ return 0;
+ case SP_KEY_NOT_FOUND:
+ int res;
+ if (lex->if_exists())
+ {
+ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_SP_DOES_NOT_EXIST,
+ ER_THD(thd, ER_SP_DOES_NOT_EXIST),
+ sph->type_str(),
+ ErrConvDQName(lex->spname).ptr());
+ if (res)
+ return 1;
+ my_ok(thd);
+ return 0;
+ }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ sph->type_str(), ErrConvDQName(lex->spname).ptr());
+ return 1;
+ default:
+ my_error(ER_SP_DROP_FAILED, MYF(0),
+ sph->type_str(), ErrConvDQName(lex->spname).ptr());
+ return 1;
+ }
+
+#ifdef WITH_WSREP
+wsrep_error_label:
+ return 1;
+#endif
+}
/**
@brief Compare requested privileges with the privileges acquired from the
@@ -6546,7 +6639,8 @@ static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
*/
bool
-check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
+check_access(THD *thd, privilege_t want_access,
+ const char *db, privilege_t *save_priv,
GRANT_INTERNAL_INFO *grant_internal_info,
bool dont_check_global_grants, bool no_errors)
{
@@ -6556,7 +6650,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
return false;
#else
Security_context *sctx= thd->security_ctx;
- ulong db_access;
+ privilege_t db_access(NO_ACL);
/*
GRANT command:
@@ -6568,17 +6662,19 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
set db_is_pattern according to 'dont_check_global_grants' value.
*/
bool db_is_pattern= ((want_access & GRANT_ACL) && dont_check_global_grants);
- ulong dummy;
+ privilege_t dummy(NO_ACL);
DBUG_ENTER("check_access");
- DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
- db ? db : "", want_access, sctx->master_access));
+ DBUG_PRINT("enter",("db: %s want_access: %llx master_access: %llx",
+ db ? db : "",
+ (longlong) want_access,
+ (longlong) sctx->master_access));
if (save_priv)
- *save_priv=0;
+ *save_priv= NO_ACL;
else
{
save_priv= &dummy;
- dummy= 0;
+ dummy= NO_ACL;
}
/* check access may be called twice in a row. Don't change to same stage */
@@ -6696,8 +6792,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
}
else
db_access= sctx->db_access;
- DBUG_PRINT("info",("db_access: %lu want_access: %lu",
- db_access, want_access));
+ DBUG_PRINT("info",("db_access: %llx want_access: %llx",
+ (longlong) db_access, (longlong) want_access));
/*
Save the union of User-table and the intersection between Db-table and
@@ -6765,7 +6861,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
1 access denied, error is sent to client
*/
-bool check_single_table_access(THD *thd, ulong privilege,
+bool check_single_table_access(THD *thd, privilege_t privilege,
TABLE_LIST *all_tables, bool no_errors)
{
Switch_to_definer_security_ctx backup_sctx(thd, all_tables);
@@ -6806,7 +6902,8 @@ bool check_single_table_access(THD *thd, ulong privilege,
1 access denied, error is sent to client
*/
-bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
+bool check_one_table_access(THD *thd, privilege_t privilege,
+ TABLE_LIST *all_tables)
{
if (check_single_table_access (thd,privilege,all_tables, FALSE))
return 1;
@@ -6958,7 +7055,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
*/
bool
-check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
+check_table_access(THD *thd, privilege_t requirements, TABLE_LIST *tables,
bool any_combination_of_privileges_will_do,
uint number, bool no_errors)
{
@@ -6977,7 +7074,7 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
tables->correspondent_table : tables;
Switch_to_definer_security_ctx backup_ctx(thd, table_ref);
- ulong want_access= requirements;
+ privilege_t want_access(requirements);
/*
Register access for view underlying table.
@@ -7020,7 +7117,7 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
bool
-check_routine_access(THD *thd, ulong want_access, const LEX_CSTRING *db,
+check_routine_access(THD *thd, privilege_t want_access, const LEX_CSTRING *db,
const LEX_CSTRING *name,
const Sp_handler *sph, bool no_errors)
{
@@ -7042,7 +7139,7 @@ check_routine_access(THD *thd, ulong want_access, const LEX_CSTRING *db,
as long as this code path is not abused to create routines.
The assert enforce that.
*/
- DBUG_ASSERT((want_access & CREATE_PROC_ACL) == 0);
+ DBUG_ASSERT((want_access & CREATE_PROC_ACL) == NO_ACL);
if ((thd->security_ctx->master_access & want_access) == want_access)
tables->grant.privilege= want_access;
else if (check_access(thd, want_access, db->str,
@@ -7071,7 +7168,7 @@ check_routine_access(THD *thd, ulong want_access, const LEX_CSTRING *db,
bool check_some_routine_access(THD *thd, const char *db, const char *name,
const Sp_handler *sph)
{
- ulong save_priv;
+ privilege_t save_priv(NO_ACL);
/*
The following test is just a shortcut for check_access() (to avoid
calculating db_access)
@@ -7102,16 +7199,15 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name,
1 error
*/
-bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
+bool check_some_access(THD *thd, privilege_t want_access, TABLE_LIST *table)
{
- ulong access;
DBUG_ENTER("check_some_access");
- /* This loop will work as long as we have less than 32 privileges */
- for (access= 1; access < want_access ; access<<= 1)
+ for (ulonglong bit= 1; bit < (ulonglong) want_access ; bit<<= 1)
{
- if (access & want_access)
+ if (bit & want_access)
{
+ privilege_t access= ALL_KNOWN_ACL & bit;
if (!check_access(thd, access, table->db.str,
&table->grant.privilege,
&table->grant.m_internal,
@@ -7134,10 +7230,8 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
@param want_access Use should have any of these global rights
@warning
- One gets access right if one has ANY of the rights in want_access.
- This is useful as one in most cases only need one global right,
- but in some case we want to check if the user has SUPER or
- REPL_CLIENT_ACL rights.
+ Starting from 10.5.2 only one bit is allowed in want_access.
+ Access denied error is returned if want_access has multiple bits set.
@retval
0 ok
@@ -7145,11 +7239,11 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
1 Access denied. In this case an error is sent to the client
*/
-bool check_global_access(THD *thd, ulong want_access, bool no_errors)
+bool check_global_access(THD *thd, privilege_t want_access, bool no_errors)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
char command[128];
- if ((thd->security_ctx->master_access & want_access))
+ if (thd->security_ctx->master_access & want_access)
return 0;
if (unlikely(!no_errors))
{
@@ -7197,8 +7291,7 @@ bool check_fk_parent_table_access(THD *thd,
LEX_CSTRING db_name;
LEX_CSTRING table_name= { fk_key->ref_table.str,
fk_key->ref_table.length };
- const ulong privileges= (SELECT_ACL | INSERT_ACL | UPDATE_ACL |
- DELETE_ACL | REFERENCES_ACL);
+ const privilege_t privileges(COL_DML_ACLS | REFERENCES_ACL);
// Check if tablename is valid or not.
DBUG_ASSERT(table_name.str != NULL);
@@ -7312,8 +7405,17 @@ long max_stack_used;
corresponding exec. (Thus we only have to check in fix_fields.)
- Passing to check_stack_overrun() prevents the compiler from removing it.
*/
-bool check_stack_overrun(THD *thd, long margin,
- uchar *buf __attribute__((unused)))
+
+bool
+#if defined __GNUC__ && !defined __clang__
+/*
+ Do not optimize the function in order to preserve a stack variable creation.
+ Otherwise, the variable pointed as "buf" can be removed due to a missing
+ usage.
+ */
+__attribute__((optimize("-O0")))
+#endif
+check_stack_overrun(THD *thd, long margin, uchar *buf __attribute__((unused)))
{
long stack_used;
DBUG_ASSERT(thd == current_thd);
@@ -7355,11 +7457,11 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, size_t *yystacksize)
old_info= *yystacksize;
*yystacksize= set_zone((int)(*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
if (!(state->yacc_yyvs= (uchar*)
- my_realloc(state->yacc_yyvs,
+ my_realloc(key_memory_bison_stack, state->yacc_yyvs,
*yystacksize*sizeof(**yyvs),
MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
!(state->yacc_yyss= (uchar*)
- my_realloc(state->yacc_yyss,
+ my_realloc(key_memory_bison_stack, state->yacc_yyss,
*yystacksize*sizeof(**yyss),
MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
return 1;
@@ -7397,6 +7499,12 @@ void THD::reset_for_next_command(bool do_clear_error)
DBUG_ENTER("THD::reset_for_next_command");
DBUG_ASSERT(!spcont); /* not for substatements of routines */
DBUG_ASSERT(!in_sub_stmt);
+ /*
+ Table maps should have been reset after previous statement except in the
+ case where we have locked tables
+ */
+ DBUG_ASSERT(binlog_table_maps == 0 ||
+ locked_tables_mode == LTM_LOCK_TABLES);
if (likely(do_clear_error))
{
@@ -7456,7 +7564,7 @@ void THD::reset_for_next_command(bool do_clear_error)
if (!in_multi_stmt_transaction_mode())
{
variables.option_bits&= ~OPTION_KEEP_LOG;
- transaction.all.reset();
+ transaction->all.reset();
}
DBUG_ASSERT(security_ctx== &main_security_ctx);
thread_specific_used= FALSE;
@@ -7496,10 +7604,7 @@ void THD::reset_for_next_command(bool do_clear_error)
void
mysql_init_select(LEX *lex)
{
- SELECT_LEX *select_lex= lex->current_select;
- select_lex->init_select();
- lex->wild= 0;
- lex->exchange= 0;
+ lex->init_select();
}
@@ -7640,7 +7745,7 @@ void mysql_init_multi_delete(LEX *lex)
lex->sql_command= SQLCOM_DELETE_MULTI;
mysql_init_select(lex);
lex->first_select_lex()->select_limit= 0;
- lex->unit.select_limit_cnt= HA_POS_ERROR;
+ lex->unit.lim.set_unlimited();
lex->first_select_lex()->table_list.
save_and_clear(&lex->auxiliary_table_list);
lex->query_tables= 0;
@@ -7828,7 +7933,8 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
bool is_next_command)
{
DBUG_ENTER("mysql_parse");
- DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
+ DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on_MYSQLparse(););
+ DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on_ORAparse(););
/*
Warning.
@@ -8212,9 +8318,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
// Pure table aliases do not need to be locked:
if (ptr->db.str && !(table_options & TL_OPTION_ALIAS))
{
- ptr->mdl_request.init(MDL_key::TABLE, ptr->db.str, ptr->table_name.str,
- mdl_type,
- MDL_TRANSACTION);
+ MDL_REQUEST_INIT(&ptr->mdl_request, MDL_key::TABLE, ptr->db.str,
+ ptr->table_name.str, mdl_type, MDL_TRANSACTION);
}
DBUG_RETURN(ptr);
}
@@ -9115,11 +9220,11 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ
*/
#ifdef WITH_WSREP
- if (((thd->security_ctx->master_access & SUPER_ACL) ||
+ if (((thd->security_ctx->master_access & PRIV_KILL_OTHER_USER_PROCESS) ||
thd->security_ctx->user_matches(tmp->security_ctx)) &&
!wsrep_thd_is_BF(tmp, false) && !tmp->wsrep_applier)
#else
- if ((thd->security_ctx->master_access & SUPER_ACL) ||
+ if ((thd->security_ctx->master_access & PRIV_KILL_OTHER_USER_PROCESS) ||
thd->security_ctx->user_matches(tmp->security_ctx))
#endif /* WITH_WSREP */
{
@@ -9190,7 +9295,8 @@ static my_bool kill_threads_callback(THD *thd, kill_threads_callback_arg *arg)
!strcmp(thd->security_ctx->host_or_ip, arg->user->host.str)) &&
!strcmp(thd->security_ctx->user, arg->user->user.str))
{
- if (!(arg->thd->security_ctx->master_access & SUPER_ACL) &&
+ if (!(arg->thd->security_ctx->master_access &
+ PRIV_KILL_OTHER_USER_PROCESS) &&
!arg->thd->security_ctx->user_matches(thd->security_ctx))
return 1;
if (!arg->threads_to_kill.push_back(thd, arg->thd->mem_root))
@@ -9272,8 +9378,8 @@ void sql_kill(THD *thd, longlong id, killed_state state, killed_type type)
}
-static
-void sql_kill_user(THD *thd, LEX_USER *user, killed_state state)
+static void __attribute__ ((noinline))
+sql_kill_user(THD *thd, LEX_USER *user, killed_state state)
{
uint error;
ha_rows rows;
@@ -9434,7 +9540,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
check_grant(thd, SELECT_ACL, table, FALSE, 1, FALSE)))
DBUG_RETURN(TRUE);
- table->grant.orig_want_privilege= 0;
+ table->grant.orig_want_privilege= NO_ACL;
table->table_in_first_from_clause= 1;
}
/*
@@ -9695,9 +9801,9 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables)
Check that we have modify privileges for the first table and
select privileges for the rest
*/
- ulong privilege= (INSERT_ACL |
- (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
- (lex->value_list.elements ? UPDATE_ACL : 0));
+ privilege_t privilege= (INSERT_ACL |
+ (lex->duplicates == DUP_REPLACE ? DELETE_ACL : NO_ACL) |
+ (lex->value_list.elements ? UPDATE_ACL : NO_ACL));
if (check_one_table_access(thd, privilege, tables))
DBUG_RETURN(TRUE);
@@ -9757,7 +9863,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
{
LEX *lex= thd->lex;
SELECT_LEX *select_lex= lex->first_select_lex();
- ulong want_priv;
+ privilege_t want_priv(NO_ACL);
bool error= TRUE; // Error message is given
DBUG_ENTER("create_table_precheck");
@@ -9766,8 +9872,8 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
CREATE TABLE ... SELECT, also require INSERT.
*/
- want_priv= lex->tmp_table() ? CREATE_TMP_ACL :
- (CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0));
+ want_priv= lex->tmp_table() ? CREATE_TMP_ACL :
+ (CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : NO_ACL));
/* CREATE OR REPLACE on not temporary tables require DROP_ACL */
if (lex->create_info.or_replace() && !lex->tmp_table())
@@ -10106,10 +10212,10 @@ int path_starts_from_data_home_dir(const char *path)
if (lower_case_file_system)
{
- if (!my_strnncoll(default_charset_info, (const uchar*) path,
- mysql_unpacked_real_data_home_len,
- (const uchar*) mysql_unpacked_real_data_home,
- mysql_unpacked_real_data_home_len))
+ if (!default_charset_info->strnncoll(path,
+ mysql_unpacked_real_data_home_len,
+ mysql_unpacked_real_data_home,
+ mysql_unpacked_real_data_home_len))
{
DBUG_PRINT("error", ("Path is part of mysql_real_data_home"));
DBUG_RETURN(1);