mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-31721: Cursor protocol increases the counter of "Empty_queries" for select
Problem: Empty queries are incremented if no rows are sent to the client in the EXECUTE phase of select query. With cursor protocol, rows are not sent during EXECUTE phase; they are sent later in FETCH phase. Hence, queries executed with cursor protocol are always falsely treated as empty in EXECUTE phase. Fix: For cursor protocol, empty queries are now counted during the FETCH phase. This ensures counter correctly reflects whether any rows were actually sent to the client. Tests included in `mysql-test/main/show.test`.
This commit is contained in:
committed by
Raghunandan Bhat
parent
7ab205b009
commit
2c7cea28da
@@ -65,3 +65,37 @@ drop table t1;
|
|||||||
#
|
#
|
||||||
# End of 10.3 tests
|
# End of 10.3 tests
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
# MDEV-31721: Cursor protocol increases the counter of "Empty_queries" for select
|
||||||
|
#
|
||||||
|
FLUSH STATUS;
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
SELECT COUNT(*) FROM t1;
|
||||||
|
COUNT(*)
|
||||||
|
1
|
||||||
|
SELECT * FROM t1;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
SELECT * FROM t1 LIMIT 0;
|
||||||
|
a
|
||||||
|
SHOW STATUS LIKE "Empty_queries";
|
||||||
|
Variable_name Value
|
||||||
|
Empty_queries 1
|
||||||
|
DROP TABLE t1;
|
||||||
|
#------------------------------
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
CREATE TABLE t2 (b INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
|
SELECT * FROM t1 UNION SELECT * FROM t2;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
2
|
||||||
|
SELECT * FROM t1 UNION SELECT * FROM t2 LIMIT 0;
|
||||||
|
a
|
||||||
|
SHOW STATUS LIKE "Empty_queries";
|
||||||
|
Variable_name Value
|
||||||
|
Empty_queries 2
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
# End of 10.11 tests
|
||||||
|
@@ -56,3 +56,40 @@ drop table t1;
|
|||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.3 tests
|
--echo # End of 10.3 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-31721: Cursor protocol increases the counter of "Empty_queries" for select
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
FLUSH STATUS;
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
|
||||||
|
--disable_ps2_protocol
|
||||||
|
SELECT COUNT(*) FROM t1;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
SELECT * FROM t1 LIMIT 0;
|
||||||
|
--enable_ps2_protocol
|
||||||
|
|
||||||
|
SHOW STATUS LIKE "Empty_queries";
|
||||||
|
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #------------------------------
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
CREATE TABLE t2 (b INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
|
|
||||||
|
--disable_ps2_protocol
|
||||||
|
SELECT * FROM t1 UNION SELECT * FROM t2;
|
||||||
|
SELECT * FROM t1 UNION SELECT * FROM t2 LIMIT 0;
|
||||||
|
--enable_ps2_protocol
|
||||||
|
|
||||||
|
SHOW STATUS LIKE "Empty_queries";
|
||||||
|
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
|
||||||
|
--echo # End of 10.11 tests
|
||||||
|
@@ -65,6 +65,7 @@
|
|||||||
#include "lock.h"
|
#include "lock.h"
|
||||||
#include "wsrep_mysqld.h"
|
#include "wsrep_mysqld.h"
|
||||||
#include "sql_connect.h"
|
#include "sql_connect.h"
|
||||||
|
#include "sql_cursor.h" //Select_materialize
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
#include "wsrep_thd.h"
|
#include "wsrep_thd.h"
|
||||||
#include "wsrep_trans_observer.h"
|
#include "wsrep_trans_observer.h"
|
||||||
@@ -8737,3 +8738,9 @@ void Charset_loader_server::raise_not_applicable_error(const char *cs,
|
|||||||
{
|
{
|
||||||
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), cl, cs);
|
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), cl, cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool THD::is_cursor_execution() const
|
||||||
|
{
|
||||||
|
return dynamic_cast<Select_materialize*>(this->lex->result);
|
||||||
|
}
|
||||||
|
@@ -5850,6 +5850,17 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
return !is_set_timestamp_forbidden(this);
|
return !is_set_timestamp_forbidden(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief
|
||||||
|
Return true if current statement uses cursor protocol for execution.
|
||||||
|
|
||||||
|
@details
|
||||||
|
Cursor protocol execution is determined by checking if lex->result is a
|
||||||
|
Select_materialize object, which is exclusively used by the server for
|
||||||
|
cursor result set materialization.
|
||||||
|
*/
|
||||||
|
bool is_cursor_execution() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -24,72 +24,6 @@
|
|||||||
#include "probes_mysql.h"
|
#include "probes_mysql.h"
|
||||||
#include "sql_parse.h" // mysql_execute_command
|
#include "sql_parse.h" // mysql_execute_command
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
Declarations.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
Materialized_cursor -- an insensitive materialized server-side
|
|
||||||
cursor. The result set of this cursor is saved in a temporary
|
|
||||||
table at open. The cursor itself is simply an interface for the
|
|
||||||
handler of the temporary table.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Materialized_cursor: public Server_side_cursor
|
|
||||||
{
|
|
||||||
MEM_ROOT main_mem_root;
|
|
||||||
/* A fake unit to supply to select_send when fetching */
|
|
||||||
SELECT_LEX_UNIT fake_unit;
|
|
||||||
TABLE *table;
|
|
||||||
List<Item> item_list;
|
|
||||||
ulong fetch_limit;
|
|
||||||
ulong fetch_count;
|
|
||||||
bool is_rnd_inited;
|
|
||||||
public:
|
|
||||||
Materialized_cursor(select_result *result, TABLE *table);
|
|
||||||
|
|
||||||
int send_result_set_metadata(THD *thd, List<Item> &send_result_set_metadata);
|
|
||||||
bool is_open() const override { return table != 0; }
|
|
||||||
int open(JOIN *join __attribute__((unused))) override;
|
|
||||||
void fetch(ulong num_rows) override;
|
|
||||||
void close() override;
|
|
||||||
bool export_structure(THD *thd, Row_definition_list *defs) override
|
|
||||||
{
|
|
||||||
return table->export_structure(thd, defs);
|
|
||||||
}
|
|
||||||
~Materialized_cursor() override;
|
|
||||||
|
|
||||||
void on_table_fill_finished();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Select_materialize -- a mediator between a cursor query and the
|
|
||||||
protocol. In case we were not able to open a non-materialzed
|
|
||||||
cursor, it creates an internal temporary HEAP table, and insert
|
|
||||||
all rows into it. When the table reaches max_heap_table_size,
|
|
||||||
it's converted to a MyISAM table. Later this table is used to
|
|
||||||
create a Materialized_cursor.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Select_materialize: public select_unit
|
|
||||||
{
|
|
||||||
select_result *result; /**< the result object of the caller (PS or SP) */
|
|
||||||
public:
|
|
||||||
Materialized_cursor *materialized_cursor;
|
|
||||||
Select_materialize(THD *thd_arg, select_result *result_arg):
|
|
||||||
select_unit(thd_arg), result(result_arg), materialized_cursor(0) {}
|
|
||||||
bool send_result_set_metadata(List<Item> &list, uint flags) override;
|
|
||||||
bool send_eof() override { return false; }
|
|
||||||
bool view_structure_only() const override
|
|
||||||
{
|
|
||||||
return result->view_structure_only();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Attempt to open a materialized cursor.
|
Attempt to open a materialized cursor.
|
||||||
|
|
||||||
|
@@ -68,6 +68,66 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Materialized_cursor -- an insensitive materialized server-side
|
||||||
|
cursor. The result set of this cursor is saved in a temporary
|
||||||
|
table at open. The cursor itself is simply an interface for the
|
||||||
|
handler of the temporary table.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Materialized_cursor: public Server_side_cursor
|
||||||
|
{
|
||||||
|
MEM_ROOT main_mem_root;
|
||||||
|
/* A fake unit to supply to select_send when fetching */
|
||||||
|
SELECT_LEX_UNIT fake_unit;
|
||||||
|
TABLE *table;
|
||||||
|
List<Item> item_list;
|
||||||
|
ulong fetch_limit;
|
||||||
|
ulong fetch_count;
|
||||||
|
bool is_rnd_inited;
|
||||||
|
public:
|
||||||
|
Materialized_cursor(select_result *result, TABLE *table);
|
||||||
|
|
||||||
|
int send_result_set_metadata(THD *thd, List<Item> &send_result_set_metadata);
|
||||||
|
bool is_open() const override { return table != 0; }
|
||||||
|
int open(JOIN *join __attribute__((unused))) override;
|
||||||
|
void fetch(ulong num_rows) override;
|
||||||
|
void close() override;
|
||||||
|
bool export_structure(THD *thd, Row_definition_list *defs) override
|
||||||
|
{
|
||||||
|
return table->export_structure(thd, defs);
|
||||||
|
}
|
||||||
|
~Materialized_cursor() override;
|
||||||
|
|
||||||
|
void on_table_fill_finished();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Select_materialize -- a mediator between a cursor query and the
|
||||||
|
protocol. In case we were not able to open a non-materialzed
|
||||||
|
cursor, it creates an internal temporary HEAP table, and insert
|
||||||
|
all rows into it. When the table reaches max_heap_table_size,
|
||||||
|
it's converted to a MyISAM table. Later this table is used to
|
||||||
|
create a Materialized_cursor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Select_materialize: public select_unit
|
||||||
|
{
|
||||||
|
select_result *result; /**< the result object of the caller (PS or SP) */
|
||||||
|
public:
|
||||||
|
Materialized_cursor *materialized_cursor;
|
||||||
|
Select_materialize(THD *thd_arg, select_result *result_arg):
|
||||||
|
select_unit(thd_arg), result(result_arg), materialized_cursor(0) {}
|
||||||
|
bool send_result_set_metadata(List<Item> &list, uint flags) override;
|
||||||
|
bool send_eof() override { return false; }
|
||||||
|
bool view_structure_only() const override
|
||||||
|
{
|
||||||
|
return result->view_structure_only();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
int mysql_open_cursor(THD *thd, select_result *result,
|
int mysql_open_cursor(THD *thd, select_result *result,
|
||||||
Server_side_cursor **res);
|
Server_side_cursor **res);
|
||||||
|
|
||||||
|
@@ -56,6 +56,7 @@
|
|||||||
#include "sql_test.h" // mysql_print_status
|
#include "sql_test.h" // mysql_print_status
|
||||||
#include "sql_select.h" // handle_select, mysql_select,
|
#include "sql_select.h" // handle_select, mysql_select,
|
||||||
// mysql_explain_union
|
// mysql_explain_union
|
||||||
|
#include "sql_cursor.h" // Select_materialzie
|
||||||
#include "sql_load.h" // mysql_load
|
#include "sql_load.h" // mysql_load
|
||||||
#include "sql_servers.h" // create_servers, alter_servers,
|
#include "sql_servers.h" // create_servers, alter_servers,
|
||||||
// drop_servers, servers_reload
|
// drop_servers, servers_reload
|
||||||
@@ -6443,7 +6444,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Count number of empty select queries */
|
/* Count number of empty select queries */
|
||||||
if (!thd->get_sent_row_count() && !res)
|
if (!thd->is_cursor_execution() && !thd->get_sent_row_count() && !res)
|
||||||
status_var_increment(thd->status_var.empty_queries);
|
status_var_increment(thd->status_var.empty_queries);
|
||||||
else
|
else
|
||||||
status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count());
|
status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count());
|
||||||
|
@@ -3767,6 +3767,9 @@ void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length)
|
|||||||
|
|
||||||
cursor->fetch(num_rows);
|
cursor->fetch(num_rows);
|
||||||
|
|
||||||
|
if (!thd->get_sent_row_count())
|
||||||
|
status_var_increment(thd->status_var.empty_queries);
|
||||||
|
|
||||||
if (!cursor->is_open())
|
if (!cursor->is_open())
|
||||||
{
|
{
|
||||||
stmt->close_cursor();
|
stmt->close_cursor();
|
||||||
|
Reference in New Issue
Block a user