1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

MDEV-25080 Fix crash for CREATE TABLE from pushed union

During st_select_lex_unit::prepare() the member select_unit*
st_select_lex_unit::union_result is being assigned to an instance
of one of the following classes:
 - select_unit
 - select_unit_ext
 - select_unit_recursive
 - select_union_direct
Select_union_direct used to pass the result of the query directly to
the receiving select_result without filling a temporary table. This class
wraps a select_result object and is currently used to process UNION ALL
queries. Other select_unit_* classes involve some additional result processing.
Pushed down units are processed on the engine side so the results must be
also passed directly to a select_result object. So in the case when
the unit pushdown is employed st_select_lex_unit::union_result must be
assigned to an instance of select_union_direct.
This commit is contained in:
Oleg Smirnov
2023-02-04 14:12:54 +07:00
committed by Sergei Golubchik
parent 3118132228
commit b5507c738f
4 changed files with 142 additions and 29 deletions

View File

@ -1388,6 +1388,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
bool have_except= false, have_intersect= false,
have_except_all_or_intersect_all= false;
bool instantiate_tmp_table= false;
bool use_direct_union_result= false;
bool single_tvc= !first_sl->next_select() && first_sl->tvc;
bool single_tvc_wo_order= single_tvc && !first_sl->order_list.elements;
bool distinct_key= 0;
@ -1511,23 +1512,18 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
}
}
/* Global option */
if (is_union_select || is_recursive)
{
if ((single_tvc_wo_order && !fake_select_lex) ||
(is_unit_op() && !union_needs_tmp_table() &&
!have_except && !have_intersect && !single_tvc))
!have_except && !have_intersect && !single_tvc))
{
SELECT_LEX *last= first_select();
while (last->next_select())
last= last->next_select();
if (!(tmp_result= union_result=
new (thd->mem_root) select_union_direct(thd, sel_result,
last)))
goto err; /* purecov: inspected */
if (unlikely(set_direct_union_result(sel_result)))
goto err;
tmp_result= union_result;
fake_select_lex= NULL;
instantiate_tmp_table= false;
use_direct_union_result= true;
}
else
{
@ -1763,6 +1759,24 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
goto err;
cont:
pushdown_unit= find_unit_handler(thd, this);
if (pushdown_unit)
{
if (unlikely(pushdown_unit->prepare()))
goto err;
/*
Always use select_union_direct result for pushed down units, overwrite
the previous union_result unless select_union_direct is already used
*/
if (!use_direct_union_result)
{
if (unlikely(set_direct_union_result(sel_result)))
goto err;
fake_select_lex= NULL;
instantiate_tmp_table= false;
use_direct_union_result= true;
}
}
/*
If the query is using select_union_direct, we have postponed
preparation of the underlying select_result until column types
@ -1965,13 +1979,6 @@ cont:
}
}
pushdown_unit= find_unit_handler(thd, this);
if (pushdown_unit)
{
if (unlikely(pushdown_unit->prepare()))
DBUG_RETURN(TRUE);
}
thd->lex->current_select= lex_select_save;
DBUG_RETURN(saved_error || thd->is_fatal_error);
@ -1982,6 +1989,15 @@ err:
DBUG_RETURN(TRUE);
}
bool st_select_lex_unit::set_direct_union_result(select_result *sel_result)
{
SELECT_LEX *last= first_select();
while (last->next_select())
last= last->next_select();
union_result= new (thd->mem_root) select_union_direct(thd, sel_result,
last);
return (union_result == nullptr);
}
/**
@brief