summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
authorJon Olav Hauglid <jon.hauglid@oracle.com>2010-11-18 16:01:58 +0100
committerJon Olav Hauglid <jon.hauglid@oracle.com>2010-11-18 16:01:58 +0100
commit2215dc3cc1bc8858761d6366436cc4c1f697b1ed (patch)
tree7cc348d24f298fedc96ce3eef04478cb467d360f /sql/sql_parse.cc
parenta6f40e50719134a6489095b01ac9e41fc8af767d (diff)
parente0a17f56988d2c0d44a8c2107588b352f6dec07a (diff)
downloadmariadb-git-2215dc3cc1bc8858761d6366436cc4c1f697b1ed.tar.gz
Merge from mysql-5.5-runtime to mysql-5.5-bugteam
No conflicts
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc181
1 files changed, 82 insertions, 99 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 4d2c0cbb60a..40cecb75b69 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -18,12 +18,9 @@
#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
@@ -260,21 +257,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 |
@@ -285,26 +281,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;
@@ -366,20 +354,19 @@ void init_update_queries(void)
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;
@@ -712,6 +699,22 @@ bool do_command(THD *thd)
net_new_transaction(net);
+ /*
+ 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",
@@ -1031,11 +1034,13 @@ 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
*/
+ 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);
@@ -1096,7 +1101,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))
@@ -1382,6 +1387,8 @@ 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);
@@ -1436,8 +1443,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 &&
@@ -1739,16 +1745,6 @@ bool sp_process_definer(THD *thd)
/**
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
@@ -1782,7 +1778,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;
@@ -1974,17 +1969,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");
@@ -2059,10 +2043,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;
}
@@ -2321,20 +2301,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
{
@@ -3128,9 +3094,6 @@ 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;
@@ -3786,13 +3749,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.
@@ -4052,13 +4024,22 @@ create_sp_error:
#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.
+ 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.
*/
- close_mysql_tables(thd);
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
+ close_thread_tables(thd);
if (sp_result != SP_KEY_NOT_FOUND &&
sp_automatic_privileges && !opt_noacl &&
@@ -4347,14 +4328,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());
@@ -4390,6 +4363,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. */
@@ -4415,6 +4393,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());
}
@@ -5885,7 +5867,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);
}