Skip to content

Commit a347f7a

Browse files
LIMIT ROWS EXAMINED prematurely triggers during optimization
1. LIMIT ROWS EXAMINED clause allows to abort a query if a certain limit of rows involved in processing is exceeded. This limitation should be only enforced during the execution phase and not the optimization. 2. Unions are often executed using so-called "fake_select_lex" which collects the final result from union parts. During that finalization LIMIT ROWS EXAMINED must be ignored to avoid producing a potentially incomplete result. There is a workaround at `st_select_lex_unit::exec()` which deactivates the limit before fake_select_lex processing, and re-activates it when the processing is finished. However, this re-activation does not take into account whether the limit was active before the start of fake_select_lex processing. 3. `st_select_lex_unit::exec()` can be invoked during the optimization phase for evaluation of constant conditions with unions. At that time the limit trigger is not activated. Given that the re-activation mentioned above does not respect the previous state of the limit trigger, a premature activation of the limit may happen. This commit fixes that behavior by storing the state of the trigger before its deactivation at `st_select_lex_unit::exec()` and re-activating it only if the limit was active before. 4. This commit also removes the call to `thd->lex->set_rows_examined()` from `st_select_lex_unit::exec_recursive()` which was probably copied from `st_select_lex_unit::exec()`. But in the context of `exec_recursive()` the call does not make sense as there is no previous deactivation of the limit as at `exec()`. Reviewed by: Dave Gosselin, Sergei Petrunia
1 parent f64e3fe commit a347f7a

File tree

4 files changed

+33
-8
lines changed

4 files changed

+33
-8
lines changed

mysql-test/main/limit_rows_examined.result

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,3 +938,14 @@ Warnings:
938938
Warning 1931 Query execution was interrupted. The query exceeded LIMIT ROWS EXAMINED 100. The query result may be incomplete
939939
DROP TABLE t1, t2;
940940
# End of 10.5 tests
941+
#
942+
# MDEV-22241: Assertion `0' failed in Protocol::end_statement after query with LIMIT ROWS EXAMINED
943+
#
944+
CREATE TABLE t1 (a int);
945+
INSERT INTO t1 VALUES (1);
946+
SELECT 1 FROM t1
947+
WHERE (1 IN (SELECT 8 UNION SELECT 5)) OR t1.a = 2
948+
LIMIT ROWS EXAMINED 1;
949+
1
950+
DROP TABLE t1;
951+
# End of 10.11 tests

mysql-test/main/limit_rows_examined.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,3 +658,18 @@ SELECT COUNT(*) FROM t1 JOIN t2 ON (b = a) UNION DISTINCT SELECT COUNT(*) FROM t
658658
DROP TABLE t1, t2;
659659

660660
--echo # End of 10.5 tests
661+
662+
--echo #
663+
--echo # MDEV-22241: Assertion `0' failed in Protocol::end_statement after query with LIMIT ROWS EXAMINED
664+
--echo #
665+
666+
CREATE TABLE t1 (a int);
667+
INSERT INTO t1 VALUES (1);
668+
669+
SELECT 1 FROM t1
670+
WHERE (1 IN (SELECT 8 UNION SELECT 5)) OR t1.a = 2
671+
LIMIT ROWS EXAMINED 1;
672+
673+
DROP TABLE t1;
674+
675+
--echo # End of 10.11 tests

sql/sql_lex.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3604,8 +3604,6 @@ struct LEX: public Query_tables_list
36043604
{
36053605
if (limit_rows_examined)
36063606
limit_rows_examined_cnt= limit_rows_examined->val_uint();
3607-
else
3608-
limit_rows_examined_cnt= ULONGLONG_MAX; // Unreachable value
36093607
}
36103608

36113609
/**
@@ -3617,7 +3615,7 @@ struct LEX: public Query_tables_list
36173615
*/
36183616
bool deactivate_limit_rows_examined()
36193617
{
3620-
bool was_activated= (limit_rows_examined_cnt == ULONGLONG_MAX);
3618+
bool was_activated= (limit_rows_examined_cnt != ULONGLONG_MAX);
36213619
limit_rows_examined_cnt= ULONGLONG_MAX; // Unreachable value
36223620
return was_activated;
36233621
}

sql/sql_union.cc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2340,14 +2340,15 @@ bool st_select_lex_unit::exec()
23402340

23412341
DBUG_EXECUTE_IF("show_explain_probe_union_read",
23422342
dbug_serve_apcs(thd, 1););
2343+
bool limit_rows_was_activated;
23432344
{
23442345
List<Item_func_match> empty_list;
23452346
empty_list.empty();
23462347
/*
2347-
Deactivate LIMIT ROWS EXAMINED in order to produce the possibly incomplete
2348-
result of the UNION without interruption due to exceeding the limit.
2348+
Deactivate LIMIT ROWS EXAMINED to avoid producing potentially incomplete
2349+
result of the UNION due to exceeding of the limit.
23492350
*/
2350-
thd->lex->deactivate_limit_rows_examined();
2351+
limit_rows_was_activated= thd->lex->deactivate_limit_rows_examined();
23512352

23522353
// Check if EOM
23532354
if (fake_select_lex != NULL && likely(!thd->is_fatal_error))
@@ -2447,7 +2448,8 @@ bool st_select_lex_unit::exec()
24472448
}
24482449
thd->lex->current_select= lex_select_save;
24492450
err:
2450-
thd->lex->activate_limit_rows_examined();
2451+
if (limit_rows_was_activated)
2452+
thd->lex->activate_limit_rows_examined();
24512453
if (likely(!saved_error))
24522454
thd->inc_examined_row_count(examined_rows);
24532455
DBUG_RETURN(saved_error);
@@ -2588,7 +2590,6 @@ bool st_select_lex_unit::exec_recursive()
25882590

25892591
thd->lex->current_select= lex_select_save;
25902592
err:
2591-
thd->lex->activate_limit_rows_examined();
25922593
DBUG_RETURN(saved_error);
25932594
}
25942595

0 commit comments

Comments
 (0)