Commit e3abcb6b authored by konstantin@mysql.com's avatar konstantin@mysql.com

A fix and test case for Bug#6088 "FOUND_ROWS returns wrong values for

prepared statements when LIMIT is used" and post-review comments.
The fix changes the approach we calculate the need for ORDER BY 
in UNION: the previous was not PS friendly, as it damaged SELECT_LEX 
options in case of single select.
parent 016d5ade
...@@ -410,3 +410,27 @@ a a ...@@ -410,3 +410,27 @@ a a
1.1 1.2 1.1 1.2
2.1 2.2 2.1 2.2
deallocate prepare stmt; deallocate prepare stmt;
create table t1 (a int);
insert into t1 (a) values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
prepare stmt from "select sql_calc_found_rows * from t1 limit 2";
execute stmt;
a
1
2
select found_rows();
found_rows()
10
execute stmt;
a
1
2
select found_rows();
found_rows()
10
execute stmt;
a
1
2
select found_rows();
found_rows()
10
...@@ -176,17 +176,17 @@ a b ...@@ -176,17 +176,17 @@ a b
a b a b
1 7 1 7
2 7 2 7
3 8
4 8 4 8
3 8
explain extended (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); explain extended (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 Using filesort 2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 Using filesort
3 UNION t4 ALL NULL NULL NULL NULL 3 Using where; Using filesort 3 UNION t4 ALL NULL NULL NULL NULL 3 Using where
4 SUBQUERY t2 ALL NULL NULL NULL NULL 2 4 SUBQUERY t2 ALL NULL NULL NULL NULL 2
NULL UNION RESULT <union1,3> ALL NULL NULL NULL NULL NULL NULL UNION RESULT <union1,3> ALL NULL NULL NULL NULL NULL
Warnings: Warnings:
Note 1003 (select test.t2.a AS `a`,test.t2.b AS `b` from test.t2 where (test.t2.b = (select test.t3.a AS `a` from test.t3 order by test.t3.a desc limit 1))) union (select test.t4.a AS `a`,test.t4.b AS `b` from test.t4 where (test.t4.b = (select (max(test.t2.a) * 4) AS `max(t2.a)*4` from test.t2)) order by test.t4.a) Note 1003 (select test.t2.a AS `a`,test.t2.b AS `b` from test.t2 where (test.t2.b = (select test.t3.a AS `a` from test.t3 order by test.t3.a desc limit 1))) union (select test.t4.a AS `a`,test.t4.b AS `b` from test.t4 where (test.t4.b = (select (max(test.t2.a) * 4) AS `max(t2.a)*4` from test.t2)) order by a)
select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2; select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2;
(select a from t3 where a<t2.a*4 order by 1 desc limit 1) a (select a from t3 where a<t2.a*4 order by 1 desc limit 1) a
3 1 3 1
......
...@@ -415,3 +415,17 @@ execute stmt; ...@@ -415,3 +415,17 @@ execute stmt;
execute stmt; execute stmt;
execute stmt; execute stmt;
deallocate prepare stmt; deallocate prepare stmt;
#
# Bug#6088 "FOUND_ROWS returns wrong values for prepared statements when
# LIMIT is used"
#
create table t1 (a int);
insert into t1 (a) values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
prepare stmt from "select sql_calc_found_rows * from t1 limit 2";
execute stmt;
select found_rows();
execute stmt;
select found_rows();
execute stmt;
select found_rows();
...@@ -147,6 +147,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ...@@ -147,6 +147,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
SELECT_LEX *lex_select_save= thd_arg->lex->current_select; SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
SELECT_LEX *sl, *first_select; SELECT_LEX *sl, *first_select;
select_result *tmp_result; select_result *tmp_result;
bool is_union;
DBUG_ENTER("st_select_lex_unit::prepare"); DBUG_ENTER("st_select_lex_unit::prepare");
describe= test(additional_options & SELECT_DESCRIBE); describe= test(additional_options & SELECT_DESCRIBE);
...@@ -183,10 +184,11 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ...@@ -183,10 +184,11 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= sl= first_select= first_select_in_union(); thd_arg->lex->current_select= sl= first_select= first_select_in_union();
found_rows_for_union= first_select->options & OPTION_FOUND_ROWS; found_rows_for_union= first_select->options & OPTION_FOUND_ROWS;
is_union= test(first_select->next_select());
/* Global option */ /* Global option */
if (first_select->next_select()) if (is_union)
{ {
if (!(tmp_result= union_result= new select_union(0))) if (!(tmp_result= union_result= new select_union(0)))
goto err; goto err;
...@@ -195,14 +197,11 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ...@@ -195,14 +197,11 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
tmp_result= sel_result; tmp_result= sel_result;
} }
else else
{
tmp_result= sel_result; tmp_result= sel_result;
// single select should be processed like select in p[arantses
first_select->braces= 1;
}
for (;sl; sl= sl->next_select()) for (;sl; sl= sl->next_select())
{ {
bool can_skip_order_by;
sl->options|= SELECT_NO_UNLOCK; sl->options|= SELECT_NO_UNLOCK;
JOIN *join= new JOIN(thd_arg, sl->item_list, JOIN *join= new JOIN(thd_arg, sl->item_list,
sl->options | thd_arg->options | additional_options, sl->options | thd_arg->options | additional_options,
...@@ -218,13 +217,16 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ...@@ -218,13 +217,16 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (select_limit_cnt == HA_POS_ERROR || sl->braces) if (select_limit_cnt == HA_POS_ERROR || sl->braces)
sl->options&= ~OPTION_FOUND_ROWS; sl->options&= ~OPTION_FOUND_ROWS;
can_skip_order_by= is_union &&
(!sl->braces || select_limit_cnt == HA_POS_ERROR);
res= join->prepare(&sl->ref_pointer_array, res= join->prepare(&sl->ref_pointer_array,
(TABLE_LIST*) sl->table_list.first, sl->with_wild, (TABLE_LIST*) sl->table_list.first, sl->with_wild,
sl->where, sl->where,
((sl->braces) ? sl->order_list.elements : 0) + (can_skip_order_by ? 0 : sl->order_list.elements) +
sl->group_list.elements, sl->group_list.elements,
(sl->braces) ? can_skip_order_by ?
(ORDER *)sl->order_list.first : (ORDER *) 0, (ORDER*) 0 : (ORDER *)sl->order_list.first,
(ORDER*) sl->group_list.first, (ORDER*) sl->group_list.first,
sl->having, sl->having,
(ORDER*) NULL, (ORDER*) NULL,
...@@ -264,10 +266,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ...@@ -264,10 +266,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
} }
} }
if (first_select->next_select()) if (is_union)
{ {
/* This is not a single select */
/* /*
Check that it was possible to aggregate Check that it was possible to aggregate
all collations together for UNION. all collations together for UNION.
...@@ -364,8 +364,6 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ...@@ -364,8 +364,6 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
} }
} }
} }
else
first_select->braces= 0; // remove our changes
thd_arg->lex->current_select= lex_select_save; thd_arg->lex->current_select= lex_select_save;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment