summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Osipov <kostja@sun.com>2010-11-12 15:56:21 +0300
committerKonstantin Osipov <kostja@sun.com>2010-11-12 15:56:21 +0300
commit78fa2e4d6d89b8d0bb4b26fe648668b97c9400b9 (patch)
tree47b1a5ab7416e5cc83776aa9a0543a058f35d724
parentf11b9a88eb3e18a1da2530257a66e224473bef3c (diff)
downloadmariadb-git-78fa2e4d6d89b8d0bb4b26fe648668b97c9400b9.tar.gz
Implement a fix for Bug#57058 -- send SERVER_QUERY_WAS_SLOW over
network when a query was slow. When a query is slow, sent a special flag to the client indicating this fact. Add a test case. Implement review comments. include/mysql_com.h: Clear SERVER_QUERY_WAS_SLOW at end of each statement. Since this patch removes the technique when thd->server_status is modified briefly only to execute my_eof(), reset more server status bit that may remain in the status from execution of the previous statement. sql/protocol.cc: Always use thd->server_status to in net_* functions to send the latest status to the client. sql/sp_head.cc: Calculate if a query was slow before sending EOF packet. sql/sql_cursor.cc: Remove juggling with thd->server_status. The extra status bits are reset at start of the next statement. sql/sql_db.cc: Remove juggling with thd->server_status. The extra status bits are reset at start of the next statement. sql/sql_error.cc: Remove m_server_status member, it's not really part of the Diagnostics_area. sql/sql_error.h: Remove server_status member, it's not part of the Diagnostics_area. The associated hack is removed as well. sql/sql_parse.cc: Do not calculate if a query was slow twice. Use a status flag in thd->server_status. tests/mysql_client_test.c: Add a test case for Bug#57058. Check that the status is present at the client, when sent.
-rw-r--r--include/mysql_com.h6
-rw-r--r--sql/protocol.cc4
-rw-r--r--sql/sp_head.cc5
-rw-r--r--sql/sql_class.h14
-rw-r--r--sql/sql_cursor.cc3
-rw-r--r--sql/sql_db.cc1
-rw-r--r--sql/sql_error.cc2
-rw-r--r--sql/sql_error.h15
-rw-r--r--sql/sql_parse.cc5
-rw-r--r--tests/mysql_client_test.c42
10 files changed, 70 insertions, 27 deletions
diff --git a/include/mysql_com.h b/include/mysql_com.h
index d4223211710..bc9296a6d02 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -255,7 +255,11 @@ enum enum_server_command
#define SERVER_STATUS_CLEAR_SET (SERVER_QUERY_NO_GOOD_INDEX_USED| \
SERVER_QUERY_NO_INDEX_USED|\
SERVER_MORE_RESULTS_EXISTS|\
- SERVER_STATUS_METADATA_CHANGED)
+ SERVER_STATUS_METADATA_CHANGED |\
+ SERVER_QUERY_WAS_SLOW |\
+ SERVER_STATUS_DB_DROPPED |\
+ SERVER_STATUS_CURSOR_EXISTS|\
+ SERVER_STATUS_LAST_ROW_SENT)
#define MYSQL_ERRMSG_SIZE 512
#define NET_READ_TIMEOUT 30 /* Timeout on read */
diff --git a/sql/protocol.cc b/sql/protocol.cc
index dd3a5d92a87..03b151e4346 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -505,11 +505,11 @@ void Protocol::end_statement()
thd->stmt_da->get_sqlstate());
break;
case Diagnostics_area::DA_EOF:
- error= send_eof(thd->stmt_da->server_status(),
+ error= send_eof(thd->server_status,
thd->stmt_da->statement_warn_count());
break;
case Diagnostics_area::DA_OK:
- error= send_ok(thd->stmt_da->server_status(),
+ error= send_ok(thd->server_status,
thd->stmt_da->statement_warn_count(),
thd->stmt_da->affected_rows(),
thd->stmt_da->last_insert_id(),
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 47b698c3a2f..27238fa05d2 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -3100,7 +3100,12 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this);
if (thd->stmt_da->is_eof())
+ {
+ /* Finalize server status flags after executing a statement. */
+ thd->update_server_status();
+
thd->protocol->end_statement();
+ }
query_cache_end_of_result(thd);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 8bf72f1cdb2..cc41595e56c 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2234,6 +2234,20 @@ public:
}
void set_time_after_lock() { utime_after_lock= my_micro_time(); }
ulonglong current_utime() { return my_micro_time(); }
+ /**
+ Update server status after execution of a top level statement.
+
+ Currently only checks if a query was slow, and assigns
+ the status accordingly.
+ Evaluate the current time, and if it exceeds the long-query-time
+ setting, mark the query as slow.
+ */
+ void update_server_status()
+ {
+ ulonglong end_utime_of_query= current_utime();
+ if (end_utime_of_query > utime_after_lock + variables.long_query_time)
+ server_status|= SERVER_QUERY_WAS_SLOW;
+ }
inline ulonglong found_rows(void)
{
return limit_found_rows;
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
index 7a9834b4cde..acc591f1ea2 100644
--- a/sql/sql_cursor.cc
+++ b/sql/sql_cursor.cc
@@ -277,7 +277,6 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused)))
rc= result->send_result_set_metadata(item_list, Protocol::SEND_NUM_ROWS);
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
result->send_eof();
- thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
}
return rc;
}
@@ -318,12 +317,10 @@ void Materialized_cursor::fetch(ulong num_rows)
case 0:
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
result->send_eof();
- thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
break;
case HA_ERR_END_OF_FILE:
thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
result->send_eof();
- thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
close();
break;
default:
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 4df8748429c..1dea2f279e9 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -866,7 +866,6 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
thd->clear_error();
thd->server_status|= SERVER_STATUS_DB_DROPPED;
my_ok(thd, (ulong) deleted);
- thd->server_status&= ~SERVER_STATUS_DB_DROPPED;
}
else if (mysql_bin_log.is_open())
{
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index 8c038e10a1f..f042a7cd164 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -365,7 +365,6 @@ Diagnostics_area::set_ok_status(THD *thd, ulonglong affected_rows_arg,
if (is_error() || is_disabled())
return;
- m_server_status= thd->server_status;
m_statement_warn_count= thd->warning_info->statement_warn_count();
m_affected_rows= affected_rows_arg;
m_last_insert_id= last_insert_id_arg;
@@ -395,7 +394,6 @@ Diagnostics_area::set_eof_status(THD *thd)
if (is_error() || is_disabled())
return;
- m_server_status= thd->server_status;
/*
If inside a stored procedure, do not return the total
number of warnings, since they are not available to the client
diff --git a/sql/sql_error.h b/sql/sql_error.h
index 87e98e27673..14dc5e6d12c 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -79,12 +79,6 @@ public:
const char* get_sqlstate() const
{ DBUG_ASSERT(m_status == DA_ERROR); return m_sqlstate; }
- uint server_status() const
- {
- DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
- return m_server_status;
- }
-
ulonglong affected_rows() const
{ DBUG_ASSERT(m_status == DA_OK); return m_affected_rows; }
@@ -111,15 +105,6 @@ private:
char m_sqlstate[SQLSTATE_LENGTH+1];
/**
- Copied from thd->server_status when the diagnostics area is assigned.
- We need this member as some places in the code use the following pattern:
- thd->server_status|= ...
- my_eof(thd);
- thd->server_status&= ~...
- Assigned by OK, EOF or ERROR.
- */
- uint m_server_status;
- /**
The number of rows affected by the last statement. This is
semantically close to thd->row_count_func, but has a different
life cycle. thd->row_count_func stores the value returned by
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e95745634e8..4f4e26d1df0 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1438,8 +1438,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 &&
@@ -5505,6 +5504,8 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
thd->end_statement();
thd->cleanup_after_query();
DBUG_ASSERT(thd->change_list.is_empty());
+ /* Finalize server status flags after executing a statement. */
+ thd->update_server_status();
}
DBUG_VOID_RETURN;
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index b85a6c587e4..3d709720727 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -19061,7 +19061,7 @@ static void test_bug49972()
my_bool is_null;
DBUG_ENTER("test_bug49972");
- myheader("test_49972");
+ myheader("test_bug49972");
rc= mysql_query(mysql, "DROP FUNCTION IF EXISTS f1");
myquery(rc);
@@ -19148,6 +19148,45 @@ static void test_bug49972()
DBUG_VOID_RETURN;
}
+
+/**
+ Bug#57058 SERVER_QUERY_WAS_SLOW not wired up.
+*/
+
+static void test_bug57058()
+{
+ MYSQL_RES *res;
+ int rc;
+
+ DBUG_ENTER("test_bug57058");
+ myheader("test_bug57058");
+
+ rc= mysql_query(mysql, "set @@session.long_query_time=0.1");
+ myquery(rc);
+
+ DIE_UNLESS(!(mysql->server_status & SERVER_QUERY_WAS_SLOW));
+
+ rc= mysql_query(mysql, "select sleep(1)");
+ myquery(rc);
+
+ /*
+ Important: the flag is sent in the last EOF packet of
+ the query, the one which ends the result. Read the
+ result to see the "slow" status.
+ */
+ res= mysql_store_result(mysql);
+
+ DIE_UNLESS(mysql->server_status & SERVER_QUERY_WAS_SLOW);
+
+ mysql_free_result(res);
+
+ rc= mysql_query(mysql, "set @@session.long_query_time=default");
+ myquery(rc);
+
+ DBUG_VOID_RETURN;
+}
+
+
/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -19481,6 +19520,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug42373", test_bug42373 },
{ "test_bug54041", test_bug54041 },
{ "test_bug47485", test_bug47485 },
+ { "test_bug57058", test_bug57058 },
{ 0, 0 }
};