[MDEV-27212] Crash in Item_equal::sort on second execution of stored procedure Created: 2021-12-09 Updated: 2022-07-01 Resolved: 2022-04-25 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Stored routines |
| Affects Version/s: | 10.2.41, 10.5.13, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7 |
| Fix Version/s: | 10.2.44, 10.3.35, 10.4.25, 10.5.16, 10.6.8, 10.7.4 |
| Type: | Bug | Priority: | Critical |
| Reporter: | Valerii Kravchuk | Assignee: | Igor Babaev |
| Resolution: | Fixed | Votes: | 0 |
| Labels: | None | ||
| Issue Links: |
|
||||||||
| Description |
|
The following crash happens on a second call to the stored procedure:
|
| Comments |
| Comment by Sergei Golubchik [ 2022-01-17 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
valerii, is there any way we can reproduce the bug? unfortunately, a stack trace alone isn't enough to understand what's wrong and fix it. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Alice Sherepa [ 2022-01-18 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
I repeated on 10.2-10.7
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-03-30 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The problem can be reproduced with a simpler SP
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-03-30 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The problem can be reproduced with the following prepared statement when it is executed for the second time:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-03-30 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The problem can be reproduced when using views v2, v instead of derived tables dt2, dt and stored procedure sp2() using these views:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-03-30 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The problem can be reproduced with MyISAM tables if we fill them with rows:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-04-18 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Let's look at the query:
Both derived tables of this query dt2 and dt are mergeable. First dt2 is merged into dt and then dt is merged into the main query. The merges are performed at the first execution of the query in the function JOIN::optimize.
where subquery#3 looks like this:
Note that we have two references to the field u.x1: one in the subquery (t2.x1 = u.x1), the other in in the main query (t1.`id` = u.x1). For the first reference we have
For the second reference we have:
We see that both references ultimately refer to the same Item_field and this is correct because the field belongs to the same instance of dt. We also see that the first reference has one Item_direct_view_ref wrapper whose depend_from field is not NULL, while the second reference has two Item_direct_view_ref wrappers and for both of them depend_from is NULL. It is important to know how Item_direct_view_ref wrappers appear in the query tree and in what memory they are allocated.
Note that field translations are allocated in the statement memory.
JOIN::prepare() for dt calls setup_fields() that resolves field references in the select list. It starts from name resolution for
The function fix_fields is called for this reference. This is a reference to a column of the derived table dt2. The pair with column name 'x1' is found in the field translator for dt2 and the corresponding expression is taken from this pair:
create_view_field() is called for u.x1. Here we have:
thd->lex->current_select->no_wrap_view_item is set to TRUE.
JOIN::prepare() is called for this subquery whose specification looks like this
setup_conds() is called for the where condition "t2.x1 = dt2.x1".
Here we have:
fix_fields() is not called for dt2.x1 as this item is already fixed. As save_wrapper == false the item is wrapped into a Item_direct_view_ref wrapper. The wrapper is allocated in the statement memory.
The function sets dependency of mark_item from the select
TABLE_LIST::create_field_translation() is called for the derived table dt. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-04-19 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Let's come to the second execution of the query
When JOIN::prepare() starts for the query it looks like:
At the moment there are no Item_direct_ref_wrappers in the tree representation for this query except those reflected in field translations. They were removed at the end of the previous execution. JOIN::prepare is supposed to restore them. It is supposed to be done by calling the function create_view_field() when references to the fields of the query is resolved.
Then the code
is executed. The code actually sets thd->lex->select_lex.no_wrap_view_item to TRUE.
and we come to JOIN::prepare() for
Name resolution for dt2.x1 brings us to the call of find_field_in_view() that invokes indirectly create_view_field() for this field. Here we have
After thd->lex->current_select->no_wrap_view_item is set to TRUE fix_fields() is called for the item
The call returns the item
as the out parameter.
Also note that thd->lex->select_lex.no_wrap_view_item remains true.
Yet in the the call of create_view_field() for dt2.m it is reset to false.
.
As mark_item->can_be_depended was set to false at the very end of the first execution the item is not marked as dependent.
we have
This is of course not correct as the select has only one table. This brings us to the reported crash. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-04-21 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The problem appears because the Item_direct_view_ref wrapper is missing for the outer reference dt2.x1 at the second execution. It happens due to the following mistake in the legacy code of the function create_view_field()
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Oleksandr Byelkin [ 2022-04-22 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
OK to push | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2022-04-25 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
A fix for this bug was pushed into 10.2. It has to be merged upstream as it is. |