Skip to content

Commit b57ee59

Browse files
committed
Fix rownum in HAVING clause or subquery
Description ========== When rownum used in HAVING without GROUP BY, accepted_rows should be incremented even if the having cond's value is 0. When rownum used in subquery 1. Forbid subquery transformed to semi join. 2. New conditions must be added into having clause when doing in2exists.
1 parent 6ef1303 commit b57ee59

File tree

5 files changed

+95
-18
lines changed

5 files changed

+95
-18
lines changed

mysql-test/main/rownum.result

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,5 +1015,45 @@ ERROR HY000: The target table v of the UPDATE is not updatable
10151015
DROP VIEW v;
10161016
DROP TABLE t;
10171017
#
1018+
# rownum in having without group by
1019+
#
1020+
create table t1 (a int primary key, b int);
1021+
insert into t1 values (1, 1), (2, 1), (3, 1), (4, 2), (5, 2), (6, 2);
1022+
select * from (select * from t1 order by a, b) dt having rownum() = 4;
1023+
a b
1024+
4 2
1025+
drop table t1;
1026+
#
1027+
# rownum in subquery
1028+
#
1029+
create table t1 (a int primary key, b int);
1030+
insert into t1 values (1, 1), (2, 1), (3, 1), (4, 2), (5, 2), (6, 2);
1031+
explain select * from t1 where a in (select rownum() from t1);
1032+
id select_type table type possible_keys key key_len ref rows Extra
1033+
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 6
1034+
1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 <subquery2>.rownum() 1 Using index condition
1035+
2 MATERIALIZED t1 index NULL PRIMARY 4 NULL 6 Using index
1036+
select * from t1 where a in (select rownum() from t1);
1037+
a b
1038+
1 1
1039+
2 1
1040+
3 1
1041+
4 2
1042+
5 2
1043+
6 2
1044+
set optimizer_switch='materialization=off';
1045+
explain select * from t1 where a + 1 in (select rownum() from t1);
1046+
id select_type table type possible_keys key key_len ref rows Extra
1047+
1 PRIMARY t1 ALL NULL NULL NULL NULL 6 Using where
1048+
2 DEPENDENT SUBQUERY t1 index NULL PRIMARY 4 NULL 6 Using index
1049+
select * from t1 where a + 1 in (select rownum() from t1);
1050+
a b
1051+
1 1
1052+
2 1
1053+
3 1
1054+
4 2
1055+
5 2
1056+
drop table t1;
1057+
#
10181058
# End of 10.6 tests
10191059
#

mysql-test/main/rownum.test

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,34 @@ UPDATE v SET f = 10 WHERE e > 42 LIMIT 1;
617617
DROP VIEW v;
618618
DROP TABLE t;
619619

620+
--echo #
621+
--echo # rownum in having without group by
622+
--echo #
623+
624+
create table t1 (a int primary key, b int);
625+
insert into t1 values (1, 1), (2, 1), (3, 1), (4, 2), (5, 2), (6, 2);
626+
select * from (select * from t1 order by a, b) dt having rownum() = 4;
627+
628+
drop table t1;
629+
630+
--echo #
631+
--echo # rownum in subquery
632+
--echo #
633+
634+
create table t1 (a int primary key, b int);
635+
insert into t1 values (1, 1), (2, 1), (3, 1), (4, 2), (5, 2), (6, 2);
636+
637+
# When rownum used in subquery, the subquery shouldn't be transformed to semijoin
638+
explain select * from t1 where a in (select rownum() from t1);
639+
select * from t1 where a in (select rownum() from t1);
640+
641+
set optimizer_switch='materialization=off';
642+
# When rownum used in IN-subquery and the subquery is transformed to EXISTS, the new condition should be added to HAVING clause.
643+
explain select * from t1 where a + 1 in (select rownum() from t1);
644+
select * from t1 where a + 1 in (select rownum() from t1);
645+
646+
drop table t1;
647+
620648
--echo #
621649
--echo # End of 10.6 tests
622650
--echo #

sql/item_subselect.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,7 +2369,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
23692369
*having_item= NULL;
23702370

23712371
if (join_having || select_lex->with_sum_func ||
2372-
select_lex->group_list.elements)
2372+
select_lex->group_list.elements || select_lex->with_rownum)
23732373
{
23742374
LEX_CSTRING field_name= this->full_name_cstring();
23752375
Item *item= func->create(thd, expr,
@@ -2616,9 +2616,10 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
26162616
during JOIN::optimize: this->tmp_having= this->having; this->having= 0;
26172617
*/
26182618
Item* join_having= join->having ? join->having : join->tmp_having;
2619-
bool is_having_used= (join_having || select_lex->with_sum_func ||
2620-
select_lex->group_list.first ||
2621-
!select_lex->table_list.elements);
2619+
bool is_having_used=
2620+
(join_having || select_lex->with_sum_func ||
2621+
select_lex->group_list.first || !select_lex->table_list.elements ||
2622+
select_lex->with_rownum);
26222623
LEX_CSTRING list_ref= { STRING_WITH_LEN("<list ref>")};
26232624
DBUG_ENTER("Item_in_subselect::create_row_in_to_exists_cond");
26242625
DBUG_ASSERT(thd == join->thd);

sql/opt_subselect.cc

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -737,25 +737,26 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
737737
11. It is first optimisation (the subquery could be moved from ON
738738
clause during first optimisation and then be considered for SJ
739739
on the second when it is too late)
740+
12. Subquery does not have ROWNUM
740741
741742
There are also other requirements which cannot be checked at this phase,
742743
yet. They are checked later in convert_join_subqueries_to_semijoins(),
743744
look for calls to block_conversion_to_sj().
744745
*/
745-
if (select_lex->semijoin_enabled(thd) &&
746-
in_subs && // 1
747-
!select_lex->is_part_of_union() && // 2
748-
!select_lex->group_list.elements && !join->order && // 3
749-
!join->having && !select_lex->with_sum_func && // 4
750-
in_subs->emb_on_expr_nest && // 5
751-
!select_lex->is_sj_conversion_prohibited(thd) && // 6
752-
parent_unit->first_select()->leaf_tables.elements && // 7
753-
!in_subs->has_strategy() && // 8
754-
select_lex->outer_select()->table_list.first && // 9
755-
!((join->select_options | // 10
756-
select_lex->outer_select()->join->select_options) // 10
757-
& SELECT_STRAIGHT_JOIN) && // 10
758-
select_lex->first_cond_optimization) // 11
746+
if (select_lex->semijoin_enabled(thd) && in_subs && // 1
747+
!select_lex->is_part_of_union() && // 2
748+
!select_lex->group_list.elements && !join->order && // 3
749+
!join->having && !select_lex->with_sum_func && // 4
750+
in_subs->emb_on_expr_nest && // 5
751+
!select_lex->is_sj_conversion_prohibited(thd) && // 6
752+
parent_unit->first_select()->leaf_tables.elements && // 7
753+
!in_subs->has_strategy() && // 8
754+
select_lex->outer_select()->table_list.first && // 9
755+
!((join->select_options | // 10
756+
select_lex->outer_select()->join->select_options) // 10
757+
& SELECT_STRAIGHT_JOIN) && // 10
758+
select_lex->first_cond_optimization && // 11
759+
!select_lex->with_rownum) // 12
759760
{
760761
DBUG_PRINT("info", ("Subquery is semi-join conversion candidate"));
761762

sql/sql_select.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25768,7 +25768,14 @@ end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
2576825768
copy_fields(&join->tmp_table_param);
2576925769
}
2577025770
if (join->having && join->having->val_bool() == 0)
25771+
{
25772+
/*
25773+
If we have HAVING clause and it is not satisfied, we don't send
25774+
the row to the client, but rownum should be incremented.
25775+
*/
25776+
join->accepted_rows++;
2577125777
DBUG_RETURN(NESTED_LOOP_OK); // Didn't match having
25778+
}
2577225779
if (join->procedure)
2577325780
{
2577425781
if (join->procedure->send_row(join->procedure_fields_list))

0 commit comments

Comments
 (0)