summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2013-12-12 13:55:33 -0800
committerIgor Babaev <igor@askmonty.org>2013-12-12 13:55:33 -0800
commit3ec4296ec413e866c3efabc8dfa94172ad5f7c04 (patch)
treec34f3306a1671c4f672732bdc6a42133e080d5d3
parentfde2777b2722a2b81f995c74e74cc3e47c0f8788 (diff)
downloadmariadb-git-3ec4296ec413e866c3efabc8dfa94172ad5f7c04.tar.gz
Fixed bug mdev-5410.
The fix for bug #27937 was incomplete: it did not handle correctly the queries containing UNION with global ORDER BY in subselects.
-rw-r--r--mysql-test/r/ps.result23
-rw-r--r--mysql-test/t/ps.test22
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_union.cc17
4 files changed, 59 insertions, 5 deletions
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 75aef40b529..e5411b2a210 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -3284,4 +3284,27 @@ Handler_read_rnd_deleted 0
Handler_read_rnd_next 0
deallocate prepare st;
drop table t1;
+#
+# Bug mdev-5410: crash at the execution of PS with subselect
+# formed by UNION with global ORDER BY
+#
+CREATE TABLE t1 (a int DEFAULT NULL);
+INSERT INTO t1 VALUES (2), (4);
+CREATE TABLE t2 (b int DEFAULT NULL);
+INSERT INTO t2 VALUES (1), (3);
+PREPARE stmt FROM "
+SELECT c1 FROM (SELECT (SELECT a FROM t1 WHERE t1.a <= t2.b
+ UNION ALL
+ SELECT a FROM t1 WHERE t1.a+3<= t2.b
+ ORDER BY a DESC) AS c1 FROM t2) t3;
+";
+EXECUTE stmt;
+c1
+NULL
+2
+EXECUTE stmt;
+c1
+NULL
+2
+DROP TABLE t1,t2;
# End of 5.3 tests
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index f1941337874..4d7c6848da7 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -3308,4 +3308,26 @@ show status like '%Handler_read%';
deallocate prepare st;
drop table t1;
+--echo #
+--echo # Bug mdev-5410: crash at the execution of PS with subselect
+--echo # formed by UNION with global ORDER BY
+--echo #
+
+CREATE TABLE t1 (a int DEFAULT NULL);
+INSERT INTO t1 VALUES (2), (4);
+CREATE TABLE t2 (b int DEFAULT NULL);
+INSERT INTO t2 VALUES (1), (3);
+
+PREPARE stmt FROM "
+SELECT c1 FROM (SELECT (SELECT a FROM t1 WHERE t1.a <= t2.b
+ UNION ALL
+ SELECT a FROM t1 WHERE t1.a+3<= t2.b
+ ORDER BY a DESC) AS c1 FROM t2) t3;
+";
+
+EXECUTE stmt;
+EXECUTE stmt;
+
+DROP TABLE t1,t2;
+
--echo # End of 5.3 tests
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 4b4496a7df8..d5639724d5f 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -584,7 +584,7 @@ public:
void print(String *str, enum_query_type query_type);
bool add_fake_select_lex(THD *thd);
- void init_prepare_fake_select_lex(THD *thd);
+ void init_prepare_fake_select_lex(THD *thd, bool first_execution);
inline bool is_prepared() { return prepared; }
bool change_result(select_result_interceptor *result,
select_result_interceptor *old_result);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index f82657a837c..5ca4af8eb0d 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -184,13 +184,15 @@ void select_union::cleanup()
SYNOPSIS
st_select_lex_unit::init_prepare_fake_select_lex()
thd - thread handler
+ first_execution - TRUE at the first execution of the union
RETURN
options of SELECT
*/
void
-st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg)
+st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg,
+ bool first_execution)
{
thd_arg->lex->current_select= fake_select_lex;
fake_select_lex->table_list.link_in_list(&result_table_list,
@@ -198,7 +200,13 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg)
fake_select_lex->context.table_list=
fake_select_lex->context.first_name_resolution_table=
fake_select_lex->get_table_list();
- if (!fake_select_lex->first_execution)
+ /*
+ The flag fake_select_lex->first_execution indicates whether this is
+ called at the first execution of the statement, while first_execution
+ shows whether this is called at the first execution of the union that
+ may form just a subselect.
+ */
+ if (!fake_select_lex->first_execution && first_execution)
{
for (ORDER *order= global_parameters->order_list.first;
order;
@@ -472,7 +480,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
{
/* Validate the global parameters of this union */
- init_prepare_fake_select_lex(thd);
+ init_prepare_fake_select_lex(thd, TRUE);
/* Should be done only once (the only item_list per statement) */
DBUG_ASSERT(fake_select_lex->join == 0);
if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
@@ -612,6 +620,7 @@ bool st_select_lex_unit::exec()
SELECT_LEX *select_cursor=first_select();
ulonglong add_rows=0;
ha_rows examined_rows= 0;
+ bool first_execution= !executed;
DBUG_ENTER("st_select_lex_unit::exec");
if (executed && !uncacheable && !describe)
@@ -714,7 +723,7 @@ bool st_select_lex_unit::exec()
if (!thd->is_fatal_error) // Check if EOM
{
set_limit(global_parameters);
- init_prepare_fake_select_lex(thd);
+ init_prepare_fake_select_lex(thd, first_execution);
JOIN *join= fake_select_lex->join;
if (!join)
{