mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
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. mysql-test/r/ps.result: Test results fixed: the test case for Bug#6088 mysql-test/r/subselect.result: Test results fixed: now we don't perform ORDER BY for parts of UNION if there is no LIMIT clause. mysql-test/t/ps.test: A test case for Bug#6088 "FOUND_ROWS returns wrong values for prepared statements when LIMIT is used". sql/sql_union.cc: The actual fix for Bug#6088: - don't modify SELECT_LEX'es - use boolean variable can_skip_order_by to check if we can skip ORDER BY in UNION
This commit is contained in:
@@ -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
|
|||||||
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;
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
||||||
@@ -217,14 +216,17 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
|||||||
select_limit_cnt= HA_POS_ERROR; // no limit
|
select_limit_cnt= HA_POS_ERROR; // no limit
|
||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
first_select->braces= 0; // remove our changes
|
|
||||||
|
|
||||||
thd_arg->lex->current_select= lex_select_save;
|
thd_arg->lex->current_select= lex_select_save;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user