From a2066982f1983e2675533d2f2db28fbaf77d2c24 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Apr 2006 23:05:38 +0400 Subject: Fixed bug#14169: type of group_concat() result changed to blob if tmp_table was used In a simple queries a result of the GROUP_CONCAT() function was always of varchar type. But if length of GROUP_CONCAT() result is greater than 512 chars and temporary table is used during select then the result is converted to blob, due to policy to not to store fields longer than 512 chars in tmp table as varchar fields. In order to provide consistent behaviour, result of GROUP_CONCAT() now will always be converted to blob if it is longer than 512 chars. Item_func_group_concat::field_type() is modified accordingly. mysql-test/t/func_gconcat.test: Added test case for bug#14169: type of group_concat() result changed to blob if tmp_table was used mysql-test/r/func_gconcat.result: Added test case for bug#14169: type of group_concat() result changed to blob if tmp_table was used sql/unireg.h: Added the CONVERT_IF_BIGGER_TO_BLOB constant sql/sql_select.cc: Fixed bug#14169: type of group_concat() result changed to blob if tmp_table was used The unnamed constant 255 in the create_tmp_field() and create_tmp_field_from_item() functions now defined as the CONVERT_IF_BIGGER_TO_BLOB constant. The create_tmp_field() function now converts the Item_sum string result to a blob field based on its char length. sql/item_sum.h: Fixed bug#14169: type of group_concat() result changed to blob if tmp_table was used To the Item_func_group_concat calls added the member function field_type() which returns the BLOB or VAR_STRING type based on the items length. sql/item_func.cc: Fixed bug#14169: type of group_concat() result changed to blob if tmp_table was used In the Item_func::tmp_table_field() function the unnamed constant 255 is changed to the CONVERT_IF_BIGGER_TO_BLOB constant. The Item_func::tmp_table_field() function now measures the result length in chars rather than bytes when converting string result to a blob. --- sql/item_func.cc | 2 +- sql/item_sum.h | 7 +++++++ sql/sql_select.cc | 6 ++++-- sql/unireg.h | 1 + 4 files changed, 13 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index d0d2eca7233..174a8c55d01 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -307,7 +307,7 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) res= new Field_double(max_length, maybe_null, name, t_arg, decimals); break; case STRING_RESULT: - if (max_length > 255) + if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) res= new Field_blob(max_length, maybe_null, name, t_arg, collation.collation); else res= new Field_string(max_length, maybe_null, name, t_arg, collation.collation); diff --git a/sql/item_sum.h b/sql/item_sum.h index c972240fcba..0cc2a20faa3 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -729,6 +729,13 @@ class Item_func_group_concat : public Item_sum enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;} const char *func_name() const { return "group_concat"; } virtual Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const + { + if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) + return FIELD_TYPE_BLOB; + else + return MYSQL_TYPE_VAR_STRING; + } void clear(); bool add(); void reset_field(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d7aa617cffd..91fc808058f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4925,7 +4925,8 @@ static Field* create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, if ((type= item->field_type()) == MYSQL_TYPE_DATETIME || type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE) new_field= item->tmp_table_field_from_field_type(table); - else if (item->max_length/item->collation.collation->mbmaxlen > 255) + else if (item->max_length/item->collation.collation->mbmaxlen > + CONVERT_IF_BIGGER_TO_BLOB) { if (convert_blob_length) new_field= new Field_varstring(convert_blob_length, maybe_null, @@ -5028,7 +5029,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, return new Field_longlong(item_sum->max_length,maybe_null, item->name,table,item->unsigned_flag); case STRING_RESULT: - if (item_sum->max_length > 255) + if (item_sum->max_length/item_sum->collation.collation->mbmaxlen > + CONVERT_IF_BIGGER_TO_BLOB) { if (convert_blob_length) return new Field_varstring(convert_blob_length, maybe_null, diff --git a/sql/unireg.h b/sql/unireg.h index 70df9a89c8f..3fb30315c81 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -60,6 +60,7 @@ #define MAX_MBWIDTH 3 /* Max multibyte sequence */ #define MAX_FIELD_CHARLENGTH 255 +#define CONVERT_IF_BIGGER_TO_BLOB 255 /* Max column width +1 */ #define MAX_FIELD_WIDTH (MAX_FIELD_CHARLENGTH*MAX_MBWIDTH+1) -- cgit v1.2.1 From c0887e546140ce8989dd8b06a87d3944956bb1cf Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Apr 2006 22:54:25 +0500 Subject: Bug#18544 - LOCK TABLES timeout causes MyISAM table corruption After a locking error the open table(s) were not fully cleaned up for reuse. But they were put into the open table cache even before the lock was tried. The next statement reused the table(s) with a wrong lock type set up. This tricked MyISAM into believing that it don't need to update the table statistics. Hence CHECK TABLE reported a mismatch of record count and table size. Fortunately nothing worse has been detected yet. The effect of the test case was that the insert worked on a read locked table. (!) I added a new function that clears the lock type from all tables that were prepared for a lock. I call this function when a lock failes. No test case. One test would add 50 seconds to the test suite. Another test requires file mode modifications. I added a test script to the bug report. It contains three cases for failing locks. All could reproduce a table corruption. All are fixed by this patch. This bug was not lock timeout specific. sql/lock.cc: Bug#18544 - LOCK TABLES timeout causes MyISAM table corruption Resetting the lock type in the open table(s) lock data after a locking error. --- sql/lock.cc | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/lock.cc b/sql/lock.cc index fe59039dde3..ab4a81034ba 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -78,6 +78,7 @@ extern HASH open_cache; static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count, uint flags, TABLE **write_locked); +static void reset_lock_data(MYSQL_LOCK *sql_lock); static int lock_external(THD *thd, TABLE **table,uint count); static int unlock_external(THD *thd, TABLE **table,uint count); static void print_lock_error(int error); @@ -120,12 +121,16 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) */ if (wait_if_global_read_lock(thd, 1, 1)) { + /* Clear the lock type of all lock data to avoid reusage. */ + reset_lock_data(sql_lock); my_free((gptr) sql_lock,MYF(0)); sql_lock=0; break; - } + } if (thd->version != refresh_version) { + /* Clear the lock type of all lock data to avoid reusage. */ + reset_lock_data(sql_lock); my_free((gptr) sql_lock,MYF(0)); goto retry; } @@ -134,6 +139,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) thd->proc_info="System lock"; if (lock_external(thd, tables, count)) { + /* Clear the lock type of all lock data to avoid reusage. */ + reset_lock_data(sql_lock); my_free((gptr) sql_lock,MYF(0)); sql_lock=0; thd->proc_info=0; @@ -639,6 +646,9 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, if (table->db_stat & HA_READ_ONLY) { my_error(ER_OPEN_AS_READONLY,MYF(0),table->table_name); + /* Clear the lock type of the lock data that are stored already. */ + sql_lock->lock_count= locks - sql_lock->locks; + reset_lock_data(sql_lock); my_free((gptr) sql_lock,MYF(0)); DBUG_RETURN(0); } @@ -663,6 +673,48 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, } +/* + Reset lock type in lock data. + + SYNOPSIS + reset_lock_data() + sql_lock The MySQL lock. + + DESCRIPTION + + After a locking error we want to quit the locking of the table(s). + The test case in the bug report for Bug #18544 has the following + cases: 1. Locking error in lock_external() due to InnoDB timeout. + 2. Locking error in get_lock_data() due to missing write permission. + 3. Locking error in wait_if_global_read_lock() due to lock conflict. + + In all these cases we have already set the lock type into the lock + data of the open table(s). If the table(s) are in the open table + cache, they could be reused with the non-zero lock type set. This + could lead to ignoring a different lock type with the next lock. + + Clear the lock type of all lock data. This ensures that the next + lock request will set its lock type properly. + + RETURN + void +*/ + +static void reset_lock_data(MYSQL_LOCK *sql_lock) +{ + THR_LOCK_DATA **ldata; + THR_LOCK_DATA **ldata_end; + + for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count; + ldata < ldata_end; + ldata++) + { + /* Reset lock type. */ + (*ldata)->type= TL_UNLOCK; + } +} + + /***************************************************************************** Lock table based on the name. This is used when we need total access to a closed, not open table -- cgit v1.2.1 From b30d80e826cfe4925e381ab79e7342e0a5486e94 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 20 Apr 2006 00:42:12 -0700 Subject: Post merge fix --- sql/item_func.cc | 5 +---- sql/item_sum.cc | 4 ++-- sql/item_sum.h | 4 ++-- sql/sql_select.cc | 19 ++++++------------- 4 files changed, 11 insertions(+), 21 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 56409a329f1..4bdb62c6e7a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -380,10 +380,7 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) res= new Field_double(max_length, maybe_null, name, t_arg, decimals); break; case STRING_RESULT: - if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) - res= new Field_blob(max_length, maybe_null, name, t_arg, collation.collation); - else - res= new Field_string(max_length, maybe_null, name, t_arg, collation.collation); + res= make_string_field(t_arg); break; case DECIMAL_RESULT: res= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(), diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 8826144266e..962454e237e 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -377,12 +377,12 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, case INT_RESULT: return new Field_longlong(max_length,maybe_null,name,table,unsigned_flag); case STRING_RESULT: - if (max_length > 255 && convert_blob_length) + if (max_length/collation.collation->mbmaxlen > 255 && convert_blob_length) return new Field_varstring(convert_blob_length, maybe_null, name, table, collation.collation); return make_string_field(table); - case DECIMAL_RESULT: +case DECIMAL_RESULT: return new Field_new_decimal(max_length, maybe_null, name, table, decimals, unsigned_flag); case ROW_RESULT: diff --git a/sql/item_sum.h b/sql/item_sum.h index 77b6ac57e79..f4ff257aa4e 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1121,10 +1121,10 @@ public: virtual Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { - if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) + if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB ) return FIELD_TYPE_BLOB; else - return MYSQL_TYPE_VAR_STRING; + return MYSQL_TYPE_VARCHAR; } void clear(); bool add(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5b796aeb4c1..0211539e784 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8245,20 +8245,13 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, if ((type= item->field_type()) == MYSQL_TYPE_DATETIME || type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE) new_field= item->tmp_table_field_from_field_type(table); - else if (item->max_length/item->collation.collation->mbmaxlen > - CONVERT_IF_BIGGER_TO_BLOB) - { - if (convert_blob_length) - new_field= new Field_varstring(convert_blob_length, maybe_null, - item->name, table, - item->collation.collation); - else - new_field= new Field_blob(item->max_length, maybe_null, item->name, - table, item->collation.collation); - } + else if (item->max_length/item->collation.collation->mbmaxlen > 255 && + convert_blob_length) + new_field= new Field_varstring(convert_blob_length, maybe_null, + item->name, table, + item->collation.collation); else - new_field= new Field_string(item->max_length, maybe_null, item->name, - table, item->collation.collation); + new_field= item->make_string_field(table); break; case DECIMAL_RESULT: new_field= new Field_new_decimal(item->max_length, maybe_null, item->name, -- cgit v1.2.1 From 9225a51c58def1fe505d0b46473b5294862309a7 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 20 Apr 2006 22:15:38 -0700 Subject: 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. --- 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 +++++++++++++++--- 5 files changed, 81 insertions(+), 22 deletions(-) (limited to 'sql') 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: -- cgit v1.2.1 From b93dd4327b159caf6a684a1d1463373f7e57b661 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Apr 2006 08:19:38 -0700 Subject: Post merge fixes --- sql/sql_parse.cc | 5 +++-- sql/sql_union.cc | 2 +- sql/sql_yacc.yy | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3752fc62d02..c58628cd856 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6355,17 +6355,18 @@ 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->parent_lex= thd->lex; /* Used in init_query. */ fake_select_lex->make_empty_select(); fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE; fake_select_lex->select_limit= 0; - fake_select_lex->context.outer_context= first_sl->context.outer_context; + fake_select_lex->context.outer_context=first_sl->context.outer_context; /* allow item list resolving in fake select for ORDER BY */ fake_select_lex->context.resolve_in_select_list= TRUE; fake_select_lex->context.select_lex= fake_select_lex; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 68036f76e96..c5af81ae55a 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -202,7 +202,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, thd_arg->lex->current_select= sl= first_sl; found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS; - is_union= test(first_select->next_select() || fake_select_lex); + is_union= first_sl->next_select() || fake_select_lex; /* Global option */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a911ad41cd7..f3f0990c917 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5719,7 +5719,7 @@ order_clause: SELECT_LEX *first_sl= unit->first_select(); if (!first_sl->next_select() && (first_sl->order_list.elements || - first_sl->select_limit != HA_POS_ERROR) && + first_sl->select_limit) && unit->add_fake_select_lex(lex->thd)) YYABORT; } -- cgit v1.2.1