1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Crash in INSERT...SELECT..RETURNING with subquery

Underlying causes of all bugs mentioned below are same. This patch fixes
all of them:
1) MDEV-25028: ASAN use-after-poison in
base_list_iterator::next or Assertion `sl->join == 0' upon
INSERT .. RETURNING via PS
2) MDEV-25187: Assertion `inited == NONE || table->open_by_handler'
failed or Direct leak in init_dynamic_array2 upon INSERT .. RETURNING
and memory leak in init_dynamic_array2
3) MDEV-28740: crash in INSERT RETURNING subquery in prepared statements
4) MDEV-27165: crash in base_list_iterator::next
5) MDEV-29686: Assertion `slave == 0' failed in
st_select_lex_node::attach_single

Analysis:
consider this statement:
INSERT(1)...SELECT(2)...(SELECT(3)...) RETURNING (SELECT(4)...)

When RETURNING is encountered, add_slave() changes how selects are linked.
It makes the builtin_select(1) slave of SELECT(2). This causes
losing of already existing slave(3) (which is nested select of SELECT of
INSERT...SELECT). When really, builtin_select (1) shouldn't be slave to
SELECT(2) because it is not nested within it. Also, push_select() to use
correct context also changed how select are linked.
During reinit_stmt_before_use(), we expect the selects to
be cleaned-up and have join=0. Since these selects are not linked correctly,
clean-up doesn't happen correctly so join is not NULL. Hence the crash.

Fix:
IF we are parsing RETURNING, make is_parsing_returning= true for
current select. get rid of add_slave(). In place of push_select(), used
push_context() to have correct context (the context of builtin_select)
to resolve items in item_list. And add these items to item_list of
builtin_select.
This commit is contained in:
Rucha Deodhar
2022-09-26 13:29:10 +05:30
parent 3a2116241b
commit 7865c8c9a2
7 changed files with 181 additions and 23 deletions

View File

@ -7484,10 +7484,12 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
Item *item;
List_iterator<Item> it(fields);
Query_arena *arena, backup;
uint *with_wild= returning_field ? &(thd->lex->returning()->with_wild) :
&(select_lex->with_wild);
DBUG_ENTER("setup_wild");
if (!select_lex->with_wild)
DBUG_RETURN(0);
if (!(*with_wild))
DBUG_RETURN(0);
/*
Don't use arena if we are not in prepared statements or stored procedures
@ -7496,7 +7498,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
arena= thd->activate_stmt_arena_if_needed(&backup);
thd->lex->current_select->cur_pos_in_select_list= 0;
while (select_lex->with_wild && (item= it++))
while (*with_wild && (item= it++))
{
if (item->type() == Item::FIELD_ITEM &&
((Item_field*) item)->field_name.str == star_clex_str.str &&
@ -7534,12 +7536,12 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
*/
sum_func_list->elements+= fields.elements - elem;
}
select_lex->with_wild--;
(*with_wild)--;
}
else
thd->lex->current_select->cur_pos_in_select_list++;
}
DBUG_ASSERT(!select_lex->with_wild);
DBUG_ASSERT(!(*with_wild));
thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
if (arena)
thd->restore_active_arena(arena, &backup);