[MDEV-25086] Stored Procedure Crashes Server Created: 2021-03-08 Updated: 2022-04-13 Resolved: 2022-01-11 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Stored routines |
| Affects Version/s: | 10.5.9, 10.2, 10.3, 10.4, 10.5, 10.6 |
| Fix Version/s: | 10.2.42, 10.3.33, 10.4.23, 10.5.14, 10.6.6, 10.7.2 |
| Type: | Bug | Priority: | Critical |
| Reporter: | Maria M Pflaum | Assignee: | Igor Babaev |
| Resolution: | Fixed | Votes: | 0 |
| Labels: | None | ||
| Environment: |
Red Hat 8 |
||
| Description |
|
The following procedure crashes the server if it is called twice, even with no data, it succeeds if you add a limit:
It succeeds if you replace:
|
| Comments |
| Comment by Elena Stepanova [ 2021-03-08 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Reproducible as described.
Fails the same way on debug, ASAN and release builds, 10.2-10.6. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Oleksandr Byelkin [ 2021-09-15 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
It crashes group_concat Item has ref_by NULL. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Oleksandr Byelkin [ 2021-09-15 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Item_sum::register_sum_func called on first call and assign the ref_by, but not second time. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Oleksandr Byelkin [ 2021-09-15 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
ref_by reset by fix_fields to NULL. On first execution of Item_sum::check_sum_func nest_level is 1 and max_arg_level 0 and it go to register_sum_func and assign ref_by. on the second execution both (nest_level and max_arg_level) are 1 and so no register_sum_func call. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2021-12-30 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The following test case brings us to the same crash in THD::change_item_tree() as the reported test case:
As for the reported test we have a crash at the second execution of the prepared statement for a query that uses a subquery with set function whose argument refers to a field of a mergeable derived table from the FROM clause of the main query. Executing EXPLAIN EXTENDED for the query shows that the merge of the derived table is done correctly:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2021-12-30 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Manual merge of the derived table does not cause any problem:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2021-12-30 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
In MySQL 8.0.18 I do not see such problem. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2021-12-31 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Interesting that if we use the view v1
instead of the derived table dt
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2021-12-31 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
When at the second execution of the prepared statement for the query
the reference to the field b from the expression sum(b) is resolved in Item_field::fix_fields() the function find_field_in_tables() is called and it sees that the field cached_table points to the table dt and that this table is a merged derived table. That why the function find_field_in_table_ref() is called. This function calls the function find_field_in_view() as a field translation is defined for dt. The function find_field_in_view() creates the field translation item for b and this is t2.b. Item_field::fix_fields() is called for t2.b. Here find_field_in_tables() is called for t2.b that first looks for a t2.b in in the table t2. It successfully finds it and comes to the code
where lex_s is the LEX structure for the whole query, select is select for dt, lex_s->in_sun_func points to the item for sum(b). As select->nest_level == 1 and lex_s->in_sum_func->nest_level == 1 the value of lex_s->in_sum_func->max_arg_level is set to 1 and this is incorrect. When the prepared statement for the query using the view v1 is executed for the second time the resolution of b from sum(b) goes through the same sequence of calls and comes to the above code. However here lex_s is the LEX structure for the view instance, not for the whole query and lex_s->in_sum_func == NULL. So thd->lex->in_sum_func->max_arg_level is not updated here remaining equal to (-1). This value is updated when we return after the call of find_field_in_tables() within the invocation of Item_field::fix_fields() for b . | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-01-01 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The above code was added in the commit:
If we replace the above code with the code
all tests from the main test suite pass (without and with --ps-protocol).
Also after this change we have no problems with the second call of the following stored procedure that causes a crash with the current code:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-01-01 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
If we return to 10.2 tree just before the commit 3690c549c6e72646ba74f6b4c83813ee4ac3aea4 (see above)
as for the second execution of the prepared statement for the query
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-01-05 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The change in Item_field::fix_fields() suggested above fixes both bugs
Note that if in the above query we use the derived table dt1 specified exactly as v3 we have no problems with the execution of the query:
We also have no problems if we use CTE cte instead of dt1:
Yet we immediately have the same kind of crash if we use cte twice like in the query:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-01-06 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Analysis of the bug
'select' above is the select for the specification of v3. Each view specification is parsed separately with its own LEX and the top select has level 0. Meanwhile the set function sum() is used in the main query and in a select whose nest level is 1. Comparing nest levels of selects belonging to different LEX structures does not make sense. Besides we know that an argument of any set function cannot belong to a view specification.
Thus instead of the above code we should use the code:
Similar changes should applied to all other pieces of code where thd->lex->in_sum_func->max_arg_level is updated. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Oleksandr Byelkin [ 2022-01-10 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
OK to push (with other 2 commits) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-01-11 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
A fix for this bug was pushed into 10.2. It should be merged upstream as it is. |