mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
5.5-merge
This commit is contained in:
571
sql/sql_parse.cc
571
sql/sql_parse.cc
@ -1,4 +1,5 @@
|
||||
/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
|
||||
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2011 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
|
||||
@ -11,19 +12,16 @@
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#define MYSQL_LEX 1
|
||||
#include "my_global.h"
|
||||
#include "sql_priv.h"
|
||||
#include "unireg.h" // REQUIRED: for other includes
|
||||
#include "sql_parse.h" // sql_kill, *_precheck, *_prepare
|
||||
#include "lock.h" // wait_if_global_read_lock,
|
||||
// unlock_global_read_lock,
|
||||
// try_transactional_lock,
|
||||
#include "lock.h" // try_transactional_lock,
|
||||
// check_transactional_lock,
|
||||
// set_handler_table_locks,
|
||||
// start_waiting_global_read_lock,
|
||||
// lock_global_read_lock,
|
||||
// make_global_read_lock_block_commit
|
||||
#include "sql_base.h" // find_temporary_tablesx
|
||||
@ -34,7 +32,7 @@
|
||||
#include "sql_locale.h" // my_locale_en_US
|
||||
#include "log.h" // flush_error_log
|
||||
#include "sql_view.h" // mysql_create_view, mysql_drop_view
|
||||
#include "sql_delete.h" // mysql_truncate, mysql_delete
|
||||
#include "sql_delete.h" // mysql_delete
|
||||
#include "sql_insert.h" // mysql_insert
|
||||
#include "sql_update.h" // mysql_update, mysql_multi_update
|
||||
#include "sql_partition.h" // struct partition_info
|
||||
@ -49,7 +47,6 @@
|
||||
// mysql_recreate_table,
|
||||
// mysql_backup_table,
|
||||
// mysql_restore_table
|
||||
#include "sql_truncate.h" // mysql_truncate_table
|
||||
#include "sql_reload.h" // reload_acl_and_cache
|
||||
#include "sql_admin.h" // mysql_assign_to_keycache
|
||||
#include "sql_connect.h" // check_user,
|
||||
@ -183,8 +180,7 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
|
||||
for (TABLE_LIST *table= tables; table; table= table->next_global)
|
||||
{
|
||||
DBUG_ASSERT(table->db && table->table_name);
|
||||
if (table->updating &&
|
||||
!find_temporary_table(thd, table->db, table->table_name))
|
||||
if (table->updating && !find_temporary_table(thd, table))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -268,21 +264,20 @@ void init_update_queries(void)
|
||||
the code, in particular in the Query_log_event's constructor.
|
||||
*/
|
||||
sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
|
||||
CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL |
|
||||
CF_AUTO_COMMIT_TRANS |
|
||||
CF_CAN_GENERATE_ROW_EVENTS;
|
||||
sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
|
||||
CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL;
|
||||
CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
|
||||
CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL;
|
||||
CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
|
||||
CF_PROTECT_AGAINST_GRL |
|
||||
CF_CAN_GENERATE_ROW_EVENTS;
|
||||
sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL;
|
||||
sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL;
|
||||
sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL;
|
||||
sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL;
|
||||
sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
|
||||
@ -293,26 +288,18 @@ void init_update_queries(void)
|
||||
sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_CREATE_TRIGGER]= CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_DROP_TRIGGER]= CF_AUTO_COMMIT_TRANS;
|
||||
|
||||
sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
|
||||
CF_PROTECT_AGAINST_GRL |
|
||||
CF_CAN_GENERATE_ROW_EVENTS;
|
||||
sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
|
||||
CF_PROTECT_AGAINST_GRL |
|
||||
CF_CAN_GENERATE_ROW_EVENTS;
|
||||
sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
|
||||
CF_PROTECT_AGAINST_GRL |
|
||||
CF_CAN_GENERATE_ROW_EVENTS;
|
||||
sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
|
||||
CF_PROTECT_AGAINST_GRL |
|
||||
CF_CAN_GENERATE_ROW_EVENTS;
|
||||
sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
|
||||
CF_PROTECT_AGAINST_GRL |
|
||||
CF_CAN_GENERATE_ROW_EVENTS;
|
||||
sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
|
||||
CF_PROTECT_AGAINST_GRL |
|
||||
CF_CAN_GENERATE_ROW_EVENTS;
|
||||
sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
|
||||
CF_CAN_GENERATE_ROW_EVENTS;
|
||||
@ -336,7 +323,6 @@ void init_update_queries(void)
|
||||
sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_NEW_MASTER]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_BINLOGS]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_BINLOG_EVENTS]= CF_STATUS_COMMAND;
|
||||
@ -373,20 +359,19 @@ void init_update_queries(void)
|
||||
sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND | CF_SHOW_TABLE_COMMAND | CF_REEXECUTION_FRAGILE);
|
||||
|
||||
|
||||
sql_command_flags[SQLCOM_CREATE_USER]= CF_CHANGES_DATA | CF_PROTECT_AGAINST_GRL;
|
||||
sql_command_flags[SQLCOM_RENAME_USER]= CF_CHANGES_DATA | CF_PROTECT_AGAINST_GRL;
|
||||
sql_command_flags[SQLCOM_DROP_USER]= CF_CHANGES_DATA | CF_PROTECT_AGAINST_GRL;
|
||||
sql_command_flags[SQLCOM_CREATE_USER]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_RENAME_USER]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_DROP_USER]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_GRANT]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_REVOKE]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_REVOKE_ALL]= CF_PROTECT_AGAINST_GRL;
|
||||
sql_command_flags[SQLCOM_OPTIMIZE]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_CREATE_FUNCTION]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_CREATE_PROCEDURE]= CF_CHANGES_DATA | CF_PROTECT_AGAINST_GRL | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_CREATE_SPFUNCTION]= CF_CHANGES_DATA | CF_PROTECT_AGAINST_GRL | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_DROP_PROCEDURE]= CF_CHANGES_DATA | CF_PROTECT_AGAINST_GRL | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_DROP_FUNCTION]= CF_CHANGES_DATA | CF_PROTECT_AGAINST_GRL | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_ALTER_PROCEDURE]= CF_CHANGES_DATA | CF_PROTECT_AGAINST_GRL | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_ALTER_FUNCTION]= CF_CHANGES_DATA | CF_PROTECT_AGAINST_GRL | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_CREATE_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_CREATE_SPFUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_DROP_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_DROP_FUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_ALTER_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_ALTER_FUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_INSTALL_PLUGIN]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_UNINSTALL_PLUGIN]= CF_CHANGES_DATA;
|
||||
|
||||
@ -407,6 +392,7 @@ void init_update_queries(void)
|
||||
sql_command_flags[SQLCOM_REPAIR]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_OPTIMIZE]|= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_ANALYZE]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_CHECK]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
|
||||
|
||||
sql_command_flags[SQLCOM_CREATE_USER]|= CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_DROP_USER]|= CF_AUTO_COMMIT_TRANS;
|
||||
@ -420,7 +406,6 @@ void init_update_queries(void)
|
||||
|
||||
sql_command_flags[SQLCOM_FLUSH]= CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_RESET]= CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_CHECK]= CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_CREATE_SERVER]= CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_ALTER_SERVER]= CF_AUTO_COMMIT_TRANS;
|
||||
sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS;
|
||||
@ -563,7 +548,7 @@ static void handle_bootstrap_impl(THD *thd)
|
||||
query= (char *) thd->memdup_w_gap(buff, length + 1,
|
||||
thd->db_length + 1 +
|
||||
QUERY_CACHE_FLAGS_SIZE);
|
||||
thd->set_query_and_id(query, length, next_query_id());
|
||||
thd->set_query_and_id(query, length, thd->charset(), next_query_id());
|
||||
DBUG_PRINT("query",("%-.4096s",thd->query()));
|
||||
#if defined(ENABLED_PROFILING)
|
||||
thd->profiling.start_new_query();
|
||||
@ -626,7 +611,7 @@ void do_handle_bootstrap(THD *thd)
|
||||
if (my_thread_init() || thd->store_globals())
|
||||
{
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
close_connection(thd, ER_OUT_OF_RESOURCES, 1);
|
||||
close_connection(thd, ER_OUT_OF_RESOURCES);
|
||||
#endif
|
||||
thd->fatal_error();
|
||||
goto end;
|
||||
@ -652,44 +637,6 @@ end:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Check access privs for a MERGE table and fix children lock types.
|
||||
|
||||
@param[in] thd thread handle
|
||||
@param[in] db database name
|
||||
@param[in,out] table_list list of child tables (merge_list)
|
||||
lock_type and optionally db set per table
|
||||
|
||||
@return status
|
||||
@retval 0 OK
|
||||
@retval != 0 Error
|
||||
|
||||
@detail
|
||||
This function is used for write access to MERGE tables only
|
||||
(CREATE TABLE, ALTER TABLE ... UNION=(...)). Set TL_WRITE for
|
||||
every child. Set 'db' for every child if not present.
|
||||
*/
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list)
|
||||
{
|
||||
int error= 0;
|
||||
|
||||
if (table_list)
|
||||
{
|
||||
/* Check that all tables use the current database */
|
||||
TABLE_LIST *tlist;
|
||||
|
||||
for (tlist= table_list; tlist; tlist= tlist->next_local)
|
||||
{
|
||||
if (!tlist->db || !tlist->db[0])
|
||||
tlist->db= db; /* purecov: inspected */
|
||||
}
|
||||
error= check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
|
||||
table_list, FALSE, UINT_MAX, FALSE);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This works because items are allocated with sql_alloc() */
|
||||
|
||||
@ -763,9 +710,26 @@ bool do_command(THD *thd)
|
||||
|
||||
net_new_transaction(net);
|
||||
|
||||
|
||||
/* Save for user statistics */
|
||||
thd->start_bytes_received= thd->status_var.bytes_received;
|
||||
|
||||
/*
|
||||
Synchronization point for testing of KILL_CONNECTION.
|
||||
This sync point can wait here, to simulate slow code execution
|
||||
between the last test of thd->killed and blocking in read().
|
||||
|
||||
The goal of this test is to verify that a connection does not
|
||||
hang, if it is killed at this point of execution.
|
||||
(Bug#37780 - main.kill fails randomly)
|
||||
|
||||
Note that the sync point wait itself will be terminated by a
|
||||
kill. In this case it consumes a condition broadcast, but does
|
||||
not change anything else. The consumed broadcast should not
|
||||
matter here, because the read/recv() below doesn't use it.
|
||||
*/
|
||||
DEBUG_SYNC(thd, "before_do_command_net_read");
|
||||
|
||||
if ((packet_length= my_net_read(net)) == packet_error)
|
||||
{
|
||||
DBUG_PRINT("info",("Got error %d reading command from socket %s",
|
||||
@ -928,7 +892,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
thd->profiling.start_new_query();
|
||||
#endif
|
||||
MYSQL_COMMAND_START(thd->thread_id, command,
|
||||
thd->security_ctx->priv_user,
|
||||
&thd->security_ctx->priv_user[0],
|
||||
(char *) thd->security_ctx->host_or_ip);
|
||||
|
||||
thd->command=command;
|
||||
@ -989,6 +953,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
#endif
|
||||
case COM_CHANGE_USER:
|
||||
{
|
||||
bool rc;
|
||||
status_var_increment(thd->status_var.com_other);
|
||||
|
||||
thd->change_user();
|
||||
@ -1000,7 +965,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
uint save_db_length= thd->db_length;
|
||||
char *save_db= thd->db;
|
||||
USER_CONN *save_user_connect= thd->user_connect;
|
||||
Security_context save_security_ctx= *thd->security_ctx;
|
||||
Security_context save_security_ctx= *thd->security_ctx;
|
||||
CHARSET_INFO *save_character_set_client=
|
||||
thd->variables.character_set_client;
|
||||
CHARSET_INFO *save_collation_connection=
|
||||
@ -1008,7 +973,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
CHARSET_INFO *save_character_set_results=
|
||||
thd->variables.character_set_results;
|
||||
|
||||
if (acl_authenticate(thd, 0, packet_length))
|
||||
rc= acl_authenticate(thd, 0, packet_length);
|
||||
MYSQL_AUDIT_NOTIFY_CONNECTION_CHANGE_USER(thd);
|
||||
if (rc)
|
||||
{
|
||||
my_free(thd->security_ctx->user);
|
||||
*thd->security_ctx= save_security_ctx;
|
||||
@ -1067,7 +1034,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
break; // fatal error is set
|
||||
MYSQL_QUERY_START(thd->query(), thd->thread_id,
|
||||
(char *) (thd->db ? thd->db : ""),
|
||||
thd->security_ctx->priv_user,
|
||||
&thd->security_ctx->priv_user[0],
|
||||
(char *) thd->security_ctx->host_or_ip);
|
||||
char *packet_end= thd->query() + thd->query_length();
|
||||
general_log_write(thd, command, thd->query(), thd->query_length());
|
||||
@ -1084,17 +1051,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) &&
|
||||
! thd->is_error())
|
||||
{
|
||||
char *beginning_of_next_stmt= (char*)
|
||||
parser_state.m_lip.found_semicolon;
|
||||
|
||||
/*
|
||||
Multiple queries exits, execute them individually
|
||||
*/
|
||||
close_thread_tables(thd);
|
||||
char *beginning_of_next_stmt= (char*) parser_state.m_lip.found_semicolon;
|
||||
|
||||
/* Finalize server status flags after executing a statement. */
|
||||
thd->update_server_status();
|
||||
thd->protocol->end_statement();
|
||||
query_cache_end_of_result(thd);
|
||||
|
||||
ulong length= (ulong)(packet_end - beginning_of_next_stmt);
|
||||
|
||||
log_slow_statement(thd);
|
||||
@ -1119,10 +1084,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
|
||||
MYSQL_QUERY_START(beginning_of_next_stmt, thd->thread_id,
|
||||
(char *) (thd->db ? thd->db : ""),
|
||||
thd->security_ctx->priv_user,
|
||||
&thd->security_ctx->priv_user[0],
|
||||
(char *) thd->security_ctx->host_or_ip);
|
||||
|
||||
thd->set_query_and_id(beginning_of_next_stmt, length, next_query_id());
|
||||
thd->set_query_and_id(beginning_of_next_stmt, length,
|
||||
thd->charset(), next_query_id());
|
||||
/*
|
||||
Count each statement from the client.
|
||||
*/
|
||||
@ -1152,7 +1118,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
SHOW statements should not add the used tables to the list of tables
|
||||
used in a transaction.
|
||||
*/
|
||||
MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
|
||||
MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
|
||||
|
||||
status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]);
|
||||
if (thd->copy_db_to(&db.str, &db.length))
|
||||
@ -1269,7 +1235,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
#endif
|
||||
case COM_REFRESH:
|
||||
{
|
||||
bool not_used;
|
||||
int not_used;
|
||||
status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
|
||||
ulong options= (ulong) (uchar) packet[0];
|
||||
if (trans_commit_implicit(thd))
|
||||
@ -1444,16 +1410,22 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
(thd->open_tables == NULL ||
|
||||
(thd->locked_tables_mode == LTM_LOCK_TABLES)));
|
||||
|
||||
/* 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);
|
||||
|
||||
mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_STATUS,
|
||||
thd->stmt_da->is_error() ? thd->stmt_da->sql_errno() : 0,
|
||||
command_name[command].str);
|
||||
|
||||
log_slow_statement(thd);
|
||||
|
||||
thd_proc_info(thd, "cleaning up");
|
||||
thd->set_query(NULL, 0);
|
||||
thd->reset_query();
|
||||
thd->command=COM_SLEEP;
|
||||
dec_thread_running();
|
||||
thd_proc_info(thd, 0);
|
||||
@ -1512,8 +1484,7 @@ void log_slow_statement(THD *thd)
|
||||
ulonglong end_utime_of_query= thd->current_utime();
|
||||
thd_proc_info(thd, "logging slow query");
|
||||
|
||||
if (((end_utime_of_query - thd->utime_after_lock) >
|
||||
thd->variables.long_query_time ||
|
||||
if (((thd->server_status & SERVER_QUERY_WAS_SLOW) ||
|
||||
((thd->server_status &
|
||||
(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
|
||||
opt_log_queries_not_using_indexes &&
|
||||
@ -1818,19 +1789,70 @@ bool sp_process_definer(THD *thd)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Auxiliary call that opens and locks tables for LOCK TABLES statement
|
||||
and initializes the list of locked tables.
|
||||
|
||||
@param thd Thread context.
|
||||
@param tables List of tables to be locked.
|
||||
|
||||
@return FALSE in case of success, TRUE in case of error.
|
||||
*/
|
||||
|
||||
static bool lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
|
||||
{
|
||||
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
|
||||
uint counter;
|
||||
TABLE_LIST *table;
|
||||
|
||||
thd->in_lock_tables= 1;
|
||||
|
||||
if (open_tables(thd, &tables, &counter, 0, &lock_tables_prelocking_strategy))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
We allow to change temporary tables even if they were locked for read
|
||||
by LOCK TABLES. To avoid a discrepancy between lock acquired at LOCK
|
||||
TABLES time and by the statement which is later executed under LOCK TABLES
|
||||
we ensure that for temporary tables we always request a write lock (such
|
||||
discrepancy can cause problems for the storage engine).
|
||||
We don't set TABLE_LIST::lock_type in this case as this might result in
|
||||
extra warnings from THD::decide_logging_format() even though binary logging
|
||||
is totally irrelevant for LOCK TABLES.
|
||||
*/
|
||||
for (table= tables; table; table= table->next_global)
|
||||
if (!table->placeholder() && table->table->s->tmp_table)
|
||||
table->table->reginfo.lock_type= TL_WRITE;
|
||||
|
||||
if (lock_tables(thd, tables, counter, 0) ||
|
||||
thd->locked_tables_list.init_locked_tables(thd))
|
||||
goto err;
|
||||
|
||||
thd->in_lock_tables= 0;
|
||||
|
||||
return FALSE;
|
||||
|
||||
err:
|
||||
thd->in_lock_tables= 0;
|
||||
|
||||
trans_rollback_stmt(thd);
|
||||
/*
|
||||
Need to end the current transaction, so the storage engine (InnoDB)
|
||||
can free its locks if LOCK TABLES locked some tables before finding
|
||||
that it can't lock a table in its list
|
||||
*/
|
||||
trans_commit_implicit(thd);
|
||||
/* Close tables and release metadata locks. */
|
||||
close_thread_tables(thd);
|
||||
DBUG_ASSERT(!thd->locked_tables_mode);
|
||||
thd->mdl_context.release_transactional_locks();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Execute command saved in thd and lex->sql_command.
|
||||
|
||||
Before every operation that can request a write lock for a table
|
||||
wait if a global read lock exists. However do not wait if this
|
||||
thread has locked tables already. No new locks can be requested
|
||||
until the other locks are released. The thread that requests the
|
||||
global read lock waits for write locked tables to become unlocked.
|
||||
|
||||
Note that wait_if_global_read_lock() sets a protection against a new
|
||||
global read lock when it succeeds. This needs to be released by
|
||||
start_waiting_global_read_lock() after the operation.
|
||||
|
||||
@param thd Thread handle
|
||||
|
||||
@todo
|
||||
@ -1864,7 +1886,6 @@ mysql_execute_command(THD *thd)
|
||||
/* have table map for update for multi-update statement (BUG#37051) */
|
||||
bool have_table_map_for_update= FALSE;
|
||||
#endif
|
||||
/* Saved variable value */
|
||||
DBUG_ENTER("mysql_execute_command");
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
thd->work_part_info= 0;
|
||||
@ -2056,17 +2077,6 @@ mysql_execute_command(THD *thd)
|
||||
thd->mdl_context.release_transactional_locks();
|
||||
}
|
||||
|
||||
/*
|
||||
Check if this command needs protection against the global read lock
|
||||
to avoid deadlock. See CF_PROTECT_AGAINST_GRL.
|
||||
start_waiting_global_read_lock() is called at the end of
|
||||
mysql_execute_command().
|
||||
*/
|
||||
if (((sql_command_flags[lex->sql_command] & CF_PROTECT_AGAINST_GRL) != 0) &&
|
||||
!thd->locked_tables_mode)
|
||||
if (thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE))
|
||||
goto error;
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
if (lex->sql_command != SQLCOM_SET_OPTION)
|
||||
DEBUG_SYNC(thd,"before_execute_sql_command");
|
||||
@ -2129,10 +2139,6 @@ mysql_execute_command(THD *thd)
|
||||
if (res)
|
||||
break;
|
||||
|
||||
if (!thd->locked_tables_mode && lex->protect_against_global_read_lock &&
|
||||
thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE))
|
||||
break;
|
||||
|
||||
res= execute_sqlcom_select(thd, all_tables);
|
||||
break;
|
||||
}
|
||||
@ -2226,20 +2232,7 @@ case SQLCOM_PREPARE:
|
||||
my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILES", "enable-profiling");
|
||||
goto error;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case SQLCOM_SHOW_NEW_MASTER:
|
||||
{
|
||||
if (check_global_access(thd, REPL_SLAVE_ACL))
|
||||
goto error;
|
||||
/* This query don't work now. See comment in repl_failsafe.cc */
|
||||
#ifndef WORKING_NEW_MASTER
|
||||
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
|
||||
goto error;
|
||||
#else
|
||||
res = show_new_master(thd);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
@ -2391,20 +2384,6 @@ case SQLCOM_PREPARE:
|
||||
create_info.default_table_charset= create_info.table_charset;
|
||||
create_info.table_charset= 0;
|
||||
}
|
||||
/*
|
||||
The create-select command will open and read-lock the select table
|
||||
and then create, open and write-lock the new table. If a global
|
||||
read lock steps in, we get a deadlock. The write lock waits for
|
||||
the global read lock, while the global read lock waits for the
|
||||
select table to be closed. So we wait until the global readlock is
|
||||
gone before starting both steps. Note that
|
||||
wait_if_global_read_lock() sets a protection against a new global
|
||||
read lock when it succeeds. This needs to be released by
|
||||
start_waiting_global_read_lock(). We protect the normal CREATE
|
||||
TABLE in the same way. That way we avoid that a new table is
|
||||
created during a global read lock.
|
||||
Protection against grl is covered by the CF_PROTECT_AGAINST_GRL flag.
|
||||
*/
|
||||
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
{
|
||||
@ -2850,7 +2829,11 @@ end_with_restore_list:
|
||||
{
|
||||
Incident_log_event ev(thd, incident);
|
||||
(void) mysql_bin_log.write(&ev); /* error is ignored */
|
||||
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
|
||||
if (mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE))
|
||||
{
|
||||
res= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DBUG_PRINT("debug", ("Just after generate_incident()"));
|
||||
}
|
||||
@ -2876,6 +2859,15 @@ end_with_restore_list:
|
||||
thd->first_successful_insert_id_in_cur_stmt=
|
||||
thd->first_successful_insert_id_in_prev_stmt;
|
||||
|
||||
DBUG_EXECUTE_IF("after_mysql_insert",
|
||||
{
|
||||
const char act[]=
|
||||
"now "
|
||||
"wait_for signal.continue";
|
||||
DBUG_ASSERT(opt_debug_sync_timeout > 0);
|
||||
DBUG_ASSERT(!debug_sync_set_action(current_thd,
|
||||
STRING_WITH_LEN(act)));
|
||||
};);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_REPLACE_SELECT:
|
||||
@ -3162,36 +3154,13 @@ end_with_restore_list:
|
||||
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
|
||||
FALSE, UINT_MAX, FALSE))
|
||||
goto error;
|
||||
if (lex->protect_against_global_read_lock &&
|
||||
thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE))
|
||||
goto error;
|
||||
|
||||
thd->variables.option_bits|= OPTION_TABLE_LOCK;
|
||||
thd->in_lock_tables=1;
|
||||
|
||||
{
|
||||
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
|
||||
|
||||
res= (open_and_lock_tables(thd, all_tables, FALSE, 0,
|
||||
&lock_tables_prelocking_strategy) ||
|
||||
thd->locked_tables_list.init_locked_tables(thd));
|
||||
}
|
||||
|
||||
thd->in_lock_tables= 0;
|
||||
res= lock_tables_open_and_lock_tables(thd, all_tables);
|
||||
|
||||
if (res)
|
||||
{
|
||||
trans_rollback_stmt(thd);
|
||||
/*
|
||||
Need to end the current transaction, so the storage engine (InnoDB)
|
||||
can free its locks if LOCK TABLES locked some tables before finding
|
||||
that it can't lock a table in its list
|
||||
*/
|
||||
trans_commit_implicit(thd);
|
||||
/* Close tables and release metadata locks. */
|
||||
close_thread_tables(thd);
|
||||
DBUG_ASSERT(!thd->locked_tables_mode);
|
||||
thd->mdl_context.release_transactional_locks();
|
||||
thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
|
||||
}
|
||||
else
|
||||
@ -3449,6 +3418,10 @@ end_with_restore_list:
|
||||
if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1) &&
|
||||
check_global_access(thd,CREATE_USER_ACL))
|
||||
break;
|
||||
|
||||
/* Replicate current user as grantor */
|
||||
thd->binlog_invoker();
|
||||
|
||||
/* Conditionally writes to binlog */
|
||||
if (!(res = mysql_revoke_all(thd, lex->users_list)))
|
||||
my_ok(thd);
|
||||
@ -3457,16 +3430,21 @@ end_with_restore_list:
|
||||
case SQLCOM_REVOKE:
|
||||
case SQLCOM_GRANT:
|
||||
{
|
||||
if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
|
||||
if (lex->type != TYPE_ENUM_PROXY &&
|
||||
check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
|
||||
first_table ? first_table->db : select_lex->db,
|
||||
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();
|
||||
|
||||
if (thd->security_ctx->user) // If not replication
|
||||
{
|
||||
LEX_USER *user, *tmp_user;
|
||||
bool first_user= TRUE;
|
||||
|
||||
List_iterator <LEX_USER> user_list(lex->users_list);
|
||||
while ((tmp_user= user_list++))
|
||||
@ -3477,24 +3455,26 @@ end_with_restore_list:
|
||||
hostname_requires_resolving(user->host.str))
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
ER_WARN_HOSTNAME_WONT_WORK,
|
||||
ER(ER_WARN_HOSTNAME_WONT_WORK),
|
||||
user->host.str);
|
||||
ER(ER_WARN_HOSTNAME_WONT_WORK));
|
||||
// Are we trying to change a password of another user
|
||||
DBUG_ASSERT(user->host.str != 0);
|
||||
if (strcmp(thd->security_ctx->user, user->user.str) ||
|
||||
my_strcasecmp(system_charset_info,
|
||||
user->host.str, thd->security_ctx->host_or_ip))
|
||||
|
||||
/*
|
||||
GRANT/REVOKE PROXY has the target user as a first entry in the list.
|
||||
*/
|
||||
if (lex->type == TYPE_ENUM_PROXY && first_user)
|
||||
{
|
||||
// TODO: use check_change_password()
|
||||
if (is_acl_user(user->host.str, user->user.str) &&
|
||||
user->password.str &&
|
||||
check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1))
|
||||
{
|
||||
my_message(ER_PASSWORD_NOT_ALLOWED,
|
||||
ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
|
||||
first_user= FALSE;
|
||||
if (acl_check_proxy_grant_access (thd, user->host.str, user->user.str,
|
||||
lex->grant & GRANT_ACL))
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_acl_user(user->host.str, user->user.str) &&
|
||||
user->password.str &&
|
||||
check_change_password (thd, user->host.str, user->user.str,
|
||||
user->password.str,
|
||||
user->password.length))
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (first_table)
|
||||
@ -3529,16 +3509,19 @@ end_with_restore_list:
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lex->columns.elements || lex->type)
|
||||
if (lex->columns.elements || (lex->type && lex->type != TYPE_ENUM_PROXY))
|
||||
{
|
||||
my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
|
||||
MYF(0));
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
/* Conditionally writes to binlog */
|
||||
res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
|
||||
lex->sql_command == SQLCOM_REVOKE);
|
||||
{
|
||||
/* Conditionally writes to binlog */
|
||||
res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
|
||||
lex->sql_command == SQLCOM_REVOKE,
|
||||
lex->type == TYPE_ENUM_PROXY);
|
||||
}
|
||||
if (!res)
|
||||
{
|
||||
if (lex->sql_command == SQLCOM_GRANT)
|
||||
@ -3565,8 +3548,7 @@ end_with_restore_list:
|
||||
lex->no_write_to_binlog= 1;
|
||||
case SQLCOM_FLUSH:
|
||||
{
|
||||
bool write_to_binlog;
|
||||
|
||||
int write_to_binlog;
|
||||
if (check_global_access(thd,RELOAD_ACL))
|
||||
goto error;
|
||||
|
||||
@ -3595,12 +3577,22 @@ end_with_restore_list:
|
||||
/*
|
||||
Presumably, RESET and binlog writing doesn't require synchronization
|
||||
*/
|
||||
if (!lex->no_write_to_binlog && write_to_binlog)
|
||||
|
||||
if (write_to_binlog > 0) // we should write
|
||||
{
|
||||
if (!lex->no_write_to_binlog)
|
||||
res= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
|
||||
} else if (write_to_binlog < 0)
|
||||
{
|
||||
if ((res= write_bin_log(thd, FALSE, thd->query(), thd->query_length())))
|
||||
break;
|
||||
}
|
||||
my_ok(thd);
|
||||
/*
|
||||
We should not write, but rather report error because
|
||||
reload_acl_and_cache binlog interactions failed
|
||||
*/
|
||||
res= 1;
|
||||
}
|
||||
|
||||
if (!res)
|
||||
my_ok(thd);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -3805,13 +3797,22 @@ end_with_restore_list:
|
||||
Security_context *backup= NULL;
|
||||
LEX_USER *definer= thd->lex->definer;
|
||||
/*
|
||||
We're going to issue an implicit GRANT statement.
|
||||
It takes metadata locks and updates system tables.
|
||||
Make sure that sp_create_routine() did not leave any
|
||||
locks in the MDL context, so there is no risk to
|
||||
deadlock.
|
||||
We're going to issue an implicit GRANT 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 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.
|
||||
*/
|
||||
close_mysql_tables(thd);
|
||||
DBUG_ASSERT(thd->transaction.stmt.is_empty());
|
||||
close_thread_tables(thd);
|
||||
/*
|
||||
Check if the definer exists on slave,
|
||||
then use definer privilege to insert routine privileges to mysql.procs_priv.
|
||||
@ -4059,49 +4060,48 @@ create_sp_error:
|
||||
int sp_result;
|
||||
int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
|
||||
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
|
||||
char *db= lex->spname->m_db.str;
|
||||
char *name= lex->spname->m_name.str;
|
||||
|
||||
/*
|
||||
@todo: here we break the metadata locking protocol by
|
||||
looking up the information about the routine without
|
||||
a metadata lock. Rewrite this piece to make sp_drop_routine
|
||||
return whether the routine existed or not.
|
||||
*/
|
||||
sp_result= sp_routine_exists_in_table(thd, type, lex->spname);
|
||||
thd->warning_info->opt_clear_warning_info(thd->query_id);
|
||||
if (sp_result == SP_OK)
|
||||
{
|
||||
char *db= lex->spname->m_db.str;
|
||||
char *name= lex->spname->m_name.str;
|
||||
if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
|
||||
lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
|
||||
goto error;
|
||||
|
||||
if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
|
||||
lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
|
||||
goto error;
|
||||
|
||||
/* Conditionally writes to binlog */
|
||||
sp_result= sp_drop_routine(thd, type, lex->spname);
|
||||
/* Conditionally writes to binlog */
|
||||
sp_result= sp_drop_routine(thd, type, lex->spname);
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
/*
|
||||
We're going to issue an implicit REVOKE statement.
|
||||
It takes metadata locks and updates system tables.
|
||||
Make sure that sp_create_routine() did not leave any
|
||||
locks in the MDL context, so there is no risk to
|
||||
deadlock.
|
||||
*/
|
||||
close_mysql_tables(thd);
|
||||
/*
|
||||
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.
|
||||
|
||||
if (sp_automatic_privileges && !opt_noacl &&
|
||||
sp_revoke_privileges(thd, db, name,
|
||||
lex->sql_command == SQLCOM_DROP_PROCEDURE))
|
||||
{
|
||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
ER_PROC_AUTO_REVOKE_FAIL,
|
||||
ER(ER_PROC_AUTO_REVOKE_FAIL));
|
||||
/* If this happens, an error should have been reported. */
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
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, db, name,
|
||||
lex->sql_command == SQLCOM_DROP_PROCEDURE))
|
||||
{
|
||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
ER_PROC_AUTO_REVOKE_FAIL,
|
||||
ER(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:
|
||||
@ -4378,14 +4378,6 @@ error:
|
||||
res= TRUE;
|
||||
|
||||
finish:
|
||||
if (thd->global_read_lock.has_protection())
|
||||
{
|
||||
/*
|
||||
Release the protection against the global read lock and wake
|
||||
everyone, who might want to set a global read lock.
|
||||
*/
|
||||
thd->global_read_lock.start_waiting_global_read_lock(thd);
|
||||
}
|
||||
|
||||
DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() ||
|
||||
thd->in_multi_stmt_transaction_mode());
|
||||
@ -4421,6 +4413,11 @@ finish:
|
||||
close_thread_tables(thd);
|
||||
thd_proc_info(thd, 0);
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
if (lex->sql_command != SQLCOM_SET_OPTION && ! thd->in_sub_stmt)
|
||||
DEBUG_SYNC(thd, "execute_command_after_close_tables");
|
||||
#endif
|
||||
|
||||
if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END))
|
||||
{
|
||||
/* No transaction control allowed in sub-statements. */
|
||||
@ -4446,6 +4443,10 @@ finish:
|
||||
*/
|
||||
thd->mdl_context.release_transactional_locks();
|
||||
}
|
||||
else if (! thd->in_sub_stmt)
|
||||
{
|
||||
thd->mdl_context.release_statement_locks();
|
||||
}
|
||||
|
||||
DBUG_RETURN(res || thd->is_error());
|
||||
}
|
||||
@ -4478,12 +4479,20 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
|
||||
return 1; /* purecov: inspected */
|
||||
thd->send_explain_fields(result);
|
||||
res= mysql_explain_union(thd, &thd->lex->unit, result);
|
||||
if (lex->describe & DESCRIBE_EXTENDED)
|
||||
/*
|
||||
The code which prints the extended description is not robust
|
||||
against malformed queries, so skip it if we have an error.
|
||||
*/
|
||||
if (!res && (lex->describe & DESCRIBE_EXTENDED))
|
||||
{
|
||||
char buff[1024];
|
||||
String str(buff,(uint32) sizeof(buff), system_charset_info);
|
||||
str.length(0);
|
||||
thd->lex->unit.print(&str, QT_ORDINARY);
|
||||
/*
|
||||
The warnings system requires input in utf8, @see
|
||||
mysqld_show_warnings().
|
||||
*/
|
||||
thd->lex->unit.print(&str, QT_TO_SYSTEM_CHARSET);
|
||||
str.append('\0');
|
||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_YES, str.ptr());
|
||||
@ -4802,7 +4811,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
|
||||
if (!no_errors)
|
||||
{
|
||||
status_var_increment(thd->status_var.access_denied_errors);
|
||||
my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
|
||||
my_error(access_denied_error_code(thd->password), MYF(0),
|
||||
sctx->priv_user,
|
||||
sctx->priv_host,
|
||||
(thd->password ?
|
||||
@ -5222,10 +5231,17 @@ bool check_stack_overrun(THD *thd, long margin,
|
||||
if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
|
||||
(long) (my_thread_stack_size - margin))
|
||||
{
|
||||
char ebuff[MYSQL_ERRMSG_SIZE];
|
||||
my_snprintf(ebuff, sizeof(ebuff), ER(ER_STACK_OVERRUN_NEED_MORE),
|
||||
stack_used, my_thread_stack_size, margin);
|
||||
my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR));
|
||||
/*
|
||||
Do not use stack for the message buffer to ensure correct
|
||||
behaviour in cases we have close to no stack left.
|
||||
*/
|
||||
char* ebuff= new char[MYSQL_ERRMSG_SIZE];
|
||||
if (ebuff) {
|
||||
my_snprintf(ebuff, MYSQL_ERRMSG_SIZE, ER(ER_STACK_OVERRUN_NEED_MORE),
|
||||
stack_used, my_thread_stack_size, margin);
|
||||
my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR));
|
||||
delete [] ebuff;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#ifndef DBUG_OFF
|
||||
@ -5411,17 +5427,10 @@ mysql_new_select(LEX *lex, bool move_down)
|
||||
lex->nest_level++;
|
||||
if (lex->nest_level > (int) MAX_SELECT_NESTING)
|
||||
{
|
||||
my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT,MYF(0),MAX_SELECT_NESTING);
|
||||
my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
select_lex->nest_level= lex->nest_level;
|
||||
/*
|
||||
Don't evaluate this subquery during statement prepare even if
|
||||
it's a constant one. The flag is switched off in the end of
|
||||
mysqld_stmt_prepare.
|
||||
*/
|
||||
if (thd->stmt_arena->is_stmt_prepare())
|
||||
select_lex->uncacheable|= UNCACHEABLE_PREPARE;
|
||||
if (move_down)
|
||||
{
|
||||
SELECT_LEX_UNIT *unit;
|
||||
@ -5596,7 +5605,8 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
|
||||
if (found_semicolon && (ulong) (found_semicolon - thd->query()))
|
||||
thd->set_query_inner(thd->query(),
|
||||
(uint32) (found_semicolon -
|
||||
thd->query() - 1));
|
||||
thd->query() - 1),
|
||||
thd->charset());
|
||||
/* Actually execute the query */
|
||||
if (found_semicolon)
|
||||
{
|
||||
@ -5607,7 +5617,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
|
||||
MYSQL_QUERY_EXEC_START(thd->query(),
|
||||
thd->thread_id,
|
||||
(char *) (thd->db ? thd->db : ""),
|
||||
thd->security_ctx->priv_user,
|
||||
&thd->security_ctx->priv_user[0],
|
||||
(char *) thd->security_ctx->host_or_ip,
|
||||
0);
|
||||
|
||||
@ -5992,7 +6002,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
||||
ptr->next_name_resolution_table= NULL;
|
||||
/* Link table in global list (all used tables) */
|
||||
lex->add_to_query_tables(ptr);
|
||||
ptr->mdl_request.init(MDL_key::TABLE, ptr->db, ptr->table_name, mdl_type);
|
||||
ptr->mdl_request.init(MDL_key::TABLE, ptr->db, ptr->table_name, mdl_type,
|
||||
MDL_TRANSACTION);
|
||||
DBUG_RETURN(ptr);
|
||||
}
|
||||
|
||||
@ -6990,10 +7001,16 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
|
||||
if (check_access(thd, want_priv, create_table->db,
|
||||
&create_table->grant.privilege,
|
||||
&create_table->grant.m_internal,
|
||||
0, 0) ||
|
||||
check_merge_table_access(thd, create_table->db,
|
||||
lex->create_info.merge_list.first))
|
||||
0, 0))
|
||||
goto err;
|
||||
|
||||
/* If it is a merge table, check privileges for merge children. */
|
||||
if (lex->create_info.merge_list.first &&
|
||||
check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
|
||||
lex->create_info.merge_list.first,
|
||||
FALSE, UINT_MAX, FALSE))
|
||||
goto err;
|
||||
|
||||
if (want_priv != CREATE_TMP_ACL &&
|
||||
check_grant(thd, want_priv, create_table, FALSE, 1, FALSE))
|
||||
goto err;
|
||||
@ -7342,10 +7359,20 @@ bool parse_sql(THD *thd,
|
||||
|
||||
bool mysql_parse_status= MYSQLparse(thd) != 0;
|
||||
|
||||
/* Check that if MYSQLparse() failed, thd->is_error() is set. */
|
||||
/*
|
||||
Check that if MYSQLparse() failed either thd->is_error() is set, or an
|
||||
internal error handler is set.
|
||||
|
||||
The assert will not catch a situation where parsing fails without an
|
||||
error reported if an error handler exists. The problem is that the
|
||||
error handler might have intercepted the error, so thd->is_error() is
|
||||
not set. However, there is no way to be 100% sure here (the error
|
||||
handler might be for other errors than parsing one).
|
||||
*/
|
||||
|
||||
DBUG_ASSERT(!mysql_parse_status ||
|
||||
(mysql_parse_status && thd->is_error()));
|
||||
(mysql_parse_status && thd->is_error()) ||
|
||||
(mysql_parse_status && thd->get_internal_handler()));
|
||||
|
||||
/* Reset parser state. */
|
||||
|
||||
|
Reference in New Issue
Block a user