From fffe7c4d1e6be607a449cfe26016e31fe708ab9b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 20 Apr 2006 12:35:33 +0400 Subject: [PATCH 1/2] func_gconcat.test: Clean up test case for bug#14169 mysql-test/t/func_gconcat.test: Clean up test case for bug#14169 --- mysql-test/t/func_gconcat.test | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index ed35c7534f6..8f50690dd8b 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -398,7 +398,6 @@ create table t1 (f1 int unsigned, f2 varchar(255)); insert into t1 values (1,repeat('a',255)),(2,repeat('b',255)); --enable_metadata select f2,group_concat(f1) from t1 group by f2; -# select f2,group_concat(f1) from t1 group by f2 order by 2; --disable_metadata drop table t1; From 9225a51c58def1fe505d0b46473b5294862309a7 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 20 Apr 2006 22:15:38 -0700 Subject: [PATCH 2/2] Fixed bug #18767. The bug caused wrong result sets for union constructs of the form (SELECT ... ORDER BY order_list1 [LIMIT n]) ORDER BY order_list2. For such queries order lists were concatenated and limit clause was completely neglected. mysql-test/r/order_by.result: Added a test case for bug #18767. mysql-test/t/order_by.test: Added a test case for bug #18767. sql/sql_lex.h: Fixed bug #18767. Placed the code the created a fake SELECT_LEX into a separate function. sql/sql_parse.cc: Fixed bug #18767. Placed the code the created a fake SELECT_LEX into a separate function. sql/sql_select.cc: Fixed bug #18767. Changed the condition on which a SELECT is treated as part of a UNION. The SELECT in (SELECT ... ORDER BY order_list1 [LIMIT n]) ORDER BY order_list2 now is handled in the same way as the first SELECT in a UNION sequence. sql/sql_union.cc: Fixed bug #18767. Changed the condition at which a SELECT is treated as part of a UNION. The SELECT in (SELECT ... ORDER BY order_list1 [LIMIT n]) ORDER BY order_list2 now is handled in the same way as the first SELECT in a UNION sequence. sql/sql_yacc.yy: Fixed bug #18767. Changed the condition at which a SELECT is treated as part of a UNION. The SELECT in (SELECT ... ORDER BY order_list1 [LIMIT n]) ORDER BY order_list2 now is handled in the same way as the first SELECT in a UNION sequence. In the same way is handled the SELECT in (SELECT ... LIMIT n) ORDER BY order list. Yet if there is neither ORDER BY nor LIMIT in the single-select union construct (SELECT ...) ORDER BY order_list then it is still handled as simple select with an order clause. --- mysql-test/r/order_by.result | 32 ++++++++++++++++ mysql-test/t/order_by.test | 14 +++++++ sql/sql_lex.h | 1 + sql/sql_parse.cc | 74 +++++++++++++++++++++++++++--------- sql/sql_select.cc | 2 +- sql/sql_union.cc | 2 +- sql/sql_yacc.yy | 24 ++++++++++-- 7 files changed, 127 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index ee8ca5f0328..8126e223f55 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -788,3 +788,35 @@ a 2 2 DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,30), (2,20), (1,10), (2,30), (1,20), (2,10); +(SELECT b,a FROM t1 ORDER BY a,b) ORDER BY b,a; +b a +10 1 +10 2 +20 1 +20 2 +30 1 +30 2 +(SELECT b FROM t1 ORDER BY b DESC) ORDER BY b ASC; +b +10 +10 +20 +20 +30 +30 +(SELECT b,a FROM t1 ORDER BY b,a) ORDER BY a,b; +b a +10 1 +20 1 +30 1 +10 2 +20 2 +30 2 +(SELECT b,a FROM t1 ORDER by b,a LIMIT 3) ORDER by a,b; +b a +10 1 +20 1 +10 2 +DROP TABLE t1; diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 4b7ec84dc54..1664afc70f9 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -545,4 +545,18 @@ SELECT a FROM t1 ORDER BY a; (SELECT a FROM t1) ORDER BY a; DROP TABLE t1; +# +# Bug #18767: global ORDER BY applied to a SELECT with ORDER BY either was +# ignored or 'concatened' to the latter. + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,30), (2,20), (1,10), (2,30), (1,20), (2,10); + +(SELECT b,a FROM t1 ORDER BY a,b) ORDER BY b,a; +(SELECT b FROM t1 ORDER BY b DESC) ORDER BY b ASC; +(SELECT b,a FROM t1 ORDER BY b,a) ORDER BY a,b; +(SELECT b,a FROM t1 ORDER by b,a LIMIT 3) ORDER by a,b; + +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 47908ba8685..bd79a194122 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -400,6 +400,7 @@ public: bool check_updateable(char *db, char *table); void print(String *str); + bool add_fake_select_lex(THD *thd); ulong init_prepare_fake_select_lex(THD *thd); int change_result(select_subselect *result, select_subselect *old_result); inline bool is_prepared() { return prepared; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 21a335637b9..e25a428aaa7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4189,23 +4189,9 @@ mysql_new_select(LEX *lex, bool move_down) else { select_lex->include_neighbour(lex->current_select); - SELECT_LEX_UNIT *unit= select_lex->master_unit(); - SELECT_LEX *fake= unit->fake_select_lex; - if (!fake) - { - /* - as far as we included SELECT_LEX for UNION unit should have - fake SELECT_LEX for UNION processing - */ - if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX())) - return 1; - fake->include_standalone(unit, - (SELECT_LEX_NODE**)&unit->fake_select_lex); - fake->select_number= INT_MAX; - fake->make_empty_select(); - fake->linkage= GLOBAL_OPTIONS_TYPE; - fake->select_limit= HA_POS_ERROR; - } + if (!select_lex->master_unit()->fake_select_lex && + select_lex->master_unit()->add_fake_select_lex(lex->thd)) + return 1; } select_lex->master_unit()->global_parameters= select_lex; @@ -4975,6 +4961,60 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type) } +/* + Create a fake SELECT_LEX for a unit + + SYNOPSIS: + add_fake_select_lex() + thd thread handle + + DESCRIPTION + The method create a fake SELECT_LEX object for a unit. + This object is created for any union construct containing a union + operation and also for any single select union construct of the form + (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ... + or of the form + (SELECT ... ORDER BY LIMIT n) ORDER BY ... + + NOTES + The object is used to retrieve rows from the temporary table + where the result on the union is obtained. + + RETURN VALUES + 1 on failure to create the object + 0 on success +*/ + +bool st_select_lex_unit::add_fake_select_lex(THD *thd) +{ + SELECT_LEX *first_sl= first_select(); + DBUG_ENTER("add_fake_select_lex"); + DBUG_ASSERT(!fake_select_lex); + + if (!(fake_select_lex= new (thd->mem_root) SELECT_LEX())) + DBUG_RETURN(1); + fake_select_lex->include_standalone(this, + (SELECT_LEX_NODE**)&fake_select_lex); + fake_select_lex->select_number= INT_MAX; + fake_select_lex->make_empty_select(); + fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE; + fake_select_lex->select_limit= HA_POS_ERROR; + + if (!first_sl->next_select()) + { + /* + This works only for + (SELECT ... ORDER BY list [LIMIT n]) ORDER BY order_list [LIMIT m], + (SELECT ... LIMIT n) ORDER BY order_list [LIMIT m] + just before the parser starts processing order_list + */ + global_parameters= fake_select_lex; + fake_select_lex->no_table_names_allowed= 1; + thd->lex->current_select= fake_select_lex; + } + DBUG_RETURN(0); +} + void add_join_on(TABLE_LIST *b,Item *expr) { if (expr) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 91fc808058f..46dba61cfc5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -171,7 +171,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result) register SELECT_LEX *select_lex = &lex->select_lex; DBUG_ENTER("handle_select"); - if (select_lex->next_select()) + if (select_lex->next_select() || select_lex->master_unit()->fake_select_lex) res=mysql_union(thd, lex, result, &lex->unit); else res= mysql_select(thd, &select_lex->ref_pointer_array, diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 8bb53f7b573..0948602bbb4 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -184,7 +184,7 @@ 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(); found_rows_for_union= first_select->options & OPTION_FOUND_ROWS; - is_union= test(first_select->next_select()); + is_union= test(first_select->next_select() || fake_select_lex); /* Global option */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 05d95b57abb..162b4183c84 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3790,15 +3790,33 @@ order_clause: ORDER_SYM BY { LEX *lex=Lex; - if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE && - lex->current_select->olap != - UNSPECIFIED_OLAP_TYPE) + SELECT_LEX *sel= lex->current_select; + SELECT_LEX_UNIT *unit= sel-> master_unit(); + if (sel->linkage != GLOBAL_OPTIONS_TYPE && + sel->olap != UNSPECIFIED_OLAP_TYPE) { net_printf(lex->thd, ER_WRONG_USAGE, "CUBE/ROLLUP", "ORDER BY"); YYABORT; } + if (lex->sql_command != SQLCOM_ALTER_TABLE && !unit->fake_select_lex) + { + /* + A query of the of the form (SELECT ...) ORDER BY order_list is + executed in the same way as the query + SELECT ... ORDER BY order_list + unless the SELECT construct contains ORDER BY or LIMIT clauses. + Otherwise we create a fake SELECT_LEX if it has not been created + yet. + */ + SELECT_LEX *first_sl= unit->first_select(); + if (!first_sl->next_select() && + (first_sl->order_list.elements || + first_sl->select_limit != HA_POS_ERROR) && + unit->add_fake_select_lex(lex->thd)) + YYABORT; + } } order_list; order_list: