[MDEV-31279] Crash when lateral derived is guaranteed to return no rows Created: 2023-05-15 Updated: 2024-01-09 Resolved: 2023-12-13 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Optimizer |
| Affects Version/s: | 10.3, 10.4, 10.5, 10.6, 10.8, 10.9, 10.10, 10.11, 11.0, 11.1, 11.2, 11.3, 11.4 |
| Fix Version/s: | 10.4.33, 10.5.24, 10.6.17, 10.11.7, 11.0.5, 11.1.4, 11.2.3, 11.3.2, 11.4.1 |
| Type: | Bug | Priority: | Major |
| Reporter: | Elena Stepanova | Assignee: | Rex Johnston |
| Resolution: | Fixed | Votes: | 1 |
| Labels: | None | ||
| Description |
|
I only found MDEV-26835 as possibly related, but it's still too different and there is no tentative patch to check if it fixes both. If it turns out to be the same issue, feel free to close this one as a duplicate.
Reproducible with MyISAM and Aria, but not with InnoDB (possibly because of DISABLE/ENABLE KEYS which is somehow important there). Plan:
|
| Comments |
| Comment by Rex Johnston [ 2023-09-18 ] | |||||||||||||||||||||||||||||||||||||||
|
The problem query
can (and under normal circumstances, is) rewritten to
This is a candidate for lateral derived optimization (for the materialized derived table sq).
Note that if rows in the subquery are estimated to be <= thd->variables.expensive_subquery_limit (100), then this subquery is deemed not 'expensive' and directly materialized. The select_lex for the subquery sq is now
During the first evaluation of this table in mysql_derived_fill() / mysql_select() / JOIN::exec / JOIN::exec_inner,the exec_const_cond (set it JOIN::choose_tableless_subquery_plan() during query optimization)
It is noted that exec_const_cond->val_int(), which represents the expression
is zero, setting zero_result_cause for this join to "Impossible WHERE noticed after reading const tables". This bypasses the rest of JOIN::exec_inner(), which would normally open the handler in sending result sets to the relevant handler
Thus initializing the heap table->file for the derived table isn't done. Being a lateral derived table, mysql_derived_fill() is called for the next result group, and as part of this operation, results from the previous result set are cleared out.
all is OK until ha_delete_all_rows() is called on the join for the derived table sq attempting to tidy up that which was never materialized in the first place. We could either test for the handler actually being opened, via table->file->is_open() or checking the string/flag zero_result_cause, which caused this chain of events. | |||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2023-12-13 ] | |||||||||||||||||||||||||||||||||||||||
|
Ok to push the latest commit into 10.4 | |||||||||||||||||||||||||||||||||||||||
| Comment by Rex Johnston [ 2023-12-13 ] | |||||||||||||||||||||||||||||||||||||||
|
Thank you Igor. | |||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2024-01-08 ] | |||||||||||||||||||||||||||||||||||||||
|
Note for the changelog: A query with derived table which A) has a GROUP BY clause and B) produces no rows can cause a crash if the optimizer uses Lateral Derived Optimization for it. | |||||||||||||||||||||||||||||||||||||||
| Comment by Igor Babaev [ 2024-01-08 ] | |||||||||||||||||||||||||||||||||||||||
|
Note for the changelog: A query with derived table which A) has a GROUP BY clause and B) produces no rows can cause a crash if the optimizer uses the default setting optimizer_switch='split_materialized=on'. |