1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-27 18:02:13 +03:00

MDEV-334: Backport of UNION ALL optimization from mysql-5.7.

Although the original code of mysql-5.7 was adjusted
to the current MariaDB code the main ideas of the optimization
were preserved.
This commit is contained in:
Igor Babaev
2014-10-14 09:36:50 -07:00
parent fec5ab5a56
commit 3c4bb0e872
31 changed files with 853 additions and 327 deletions

View File

@ -3914,6 +3914,23 @@ protected:
public:
select_result();
virtual ~select_result() {};
/**
Change wrapped select_result.
Replace the wrapped result object with new_result and call
prepare() and prepare2() on new_result.
This base class implementation doesn't wrap other select_results.
@param new_result The new result object to wrap around
@retval false Success
@retval true Error
*/
virtual bool change_result(select_result *new_result)
{
return false;
}
virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
unit= u;
@ -4321,9 +4338,19 @@ public:
select_union() :write_err(0), table(0), records(0) { tmp_table_param.init(); }
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
/**
Do prepare() and prepare2() if they have been postponed until
column type information is computed (used by select_union_direct).
@param types Column types
@return false on success, true on failure
*/
virtual bool postponed_prepare(List<Item> &types)
{ return false; }
int send_data(List<Item> &items);
bool send_eof();
bool flush();
virtual bool flush();
void cleanup();
virtual bool create_result_table(THD *thd, List<Item> *column_types,
bool is_distinct, ulonglong options,
@ -4334,6 +4361,101 @@ public:
TMP_TABLE_PARAM *get_tmp_table_param() { return &tmp_table_param; }
};
/**
UNION result that is passed directly to the receiving select_result
without filling a temporary table.
Function calls are forwarded to the wrapped select_result, but some
functions are expected to be called only once for each query, so
they are only executed for the first SELECT in the union (execept
for send_eof(), which is executed only for the last SELECT).
This select_result is used when a UNION is not DISTINCT and doesn't
have a global ORDER BY clause. @see st_select_lex_unit::prepare().
*/
class select_union_direct :public select_union
{
private:
/* Result object that receives all rows */
select_result *result;
/* The last SELECT_LEX of the union */
SELECT_LEX *last_select_lex;
/* Wrapped result has received metadata */
bool done_send_result_set_metadata;
/* Wrapped result has initialized tables */
bool done_initialize_tables;
/* Accumulated limit_found_rows */
ulonglong limit_found_rows;
/* Number of rows offset */
ha_rows offset;
/* Number of rows limit + offset, @see select_union_direct::send_data() */
ha_rows limit;
public:
select_union_direct(select_result *result, SELECT_LEX *last_select_lex)
:result(result), last_select_lex(last_select_lex),
done_send_result_set_metadata(false), done_initialize_tables(false),
limit_found_rows(0)
{}
bool change_result(select_result *new_result);
uint field_count(List<Item> &fields) const
{
// Only called for top-level select_results, usually select_send
DBUG_ASSERT(false); /* purecov: inspected */
return 0; /* purecov: inspected */
}
bool postponed_prepare(List<Item> &types);
bool send_result_set_metadata(List<Item> &list, uint flags);
int send_data(List<Item> &items);
bool initialize_tables (JOIN *join= NULL);
bool send_eof();
bool flush() { return false; }
bool check_simple_select() const
{
/* Only called for top-level select_results, usually select_send */
DBUG_ASSERT(false); /* purecov: inspected */
return false; /* purecov: inspected */
}
void abort_result_set()
{
result->abort_result_set(); /* purecov: inspected */
}
void cleanup()
{
/*
Only called for top-level select_results, usually select_send,
and for the results of subquery engines
(select_<something>_subselect).
*/
DBUG_ASSERT(false); /* purecov: inspected */
}
void set_thd(THD *thd_arg)
{
/*
Only called for top-level select_results, usually select_send,
and for the results of subquery engines
(select_<something>_subselect).
*/
DBUG_ASSERT(false); /* purecov: inspected */
}
void reset_offset_limit_cnt()
{
// EXPLAIN should never output to a select_union_direct
DBUG_ASSERT(false); /* purecov: inspected */
}
void begin_dataset()
{
// Only called for sp_cursor::Select_fetch_into_spvars
DBUG_ASSERT(false); /* purecov: inspected */
}
};
/* Base subselect interface class */
class select_subselect :public select_result_interceptor
{