From 046f82e3a52e212cb50f3d32497030fe317d9b25 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 23 Nov 2005 16:49:07 -0800 Subject: [PATCH 1/3] Fix possible corruption of results from SUBSTRING_INDEX(). (Bug #14676) mysql-test/r/func_str.result: Add new results mysql-test/t/func_str.test: Add new test sql/item_strfunc.cc: Mark tmp_value in Item_func_substr_index as const so that we don't overwrite the contents of another String when getting the delimiter. Fix typo in variable names (delimeter -> delimiter). --- mysql-test/r/func_str.result | 7 +++++++ mysql-test/t/func_str.test | 8 ++++++++ sql/item_strfunc.cc | 38 +++++++++++++++++++++--------------- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index a305bf20bff..911d6eea033 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1023,3 +1023,10 @@ select format(d, 2) from t1; format(d, 2) NULL drop table t1; +create table t1 (c varchar(40)); +insert into t1 values ('y,abc'),('y,abc'); +select c, substring_index(lcase(c), @q:=',', -1) as res from t1; +c res +y,abc abc +y,abc abc +drop table t1; diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index ac2bf820257..ef20d766bce 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -676,4 +676,12 @@ insert into t1 values (null); select format(d, 2) from t1; drop table t1; +# +# Bug #14676: substring_index() returns incorrect results +# +create table t1 (c varchar(40)); +insert into t1 values ('y,abc'),('y,abc'); +select c, substring_index(lcase(c), @q:=',', -1) as res from t1; +drop table t1; + # End of 5.0 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 1e8fe2e695f..9f17e978b39 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1094,9 +1094,9 @@ void Item_func_substr_index::fix_length_and_dec() String *Item_func_substr_index::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res =args[0]->val_str(str); - String *delimeter =args[1]->val_str(&tmp_value); - int32 count = (int32) args[2]->val_int(); + String *res= args[0]->val_str(str); + String *delimiter= args[1]->val_str(&tmp_value); + int32 count= (int32) args[2]->val_int(); uint offset; if (args[0]->null_value || args[1]->null_value || args[2]->null_value) @@ -1105,8 +1105,8 @@ String *Item_func_substr_index::val_str(String *str) return 0; } null_value=0; - uint delimeter_length=delimeter->length(); - if (!res->length() || !delimeter_length || !count) + uint delimiter_length= delimiter->length(); + if (!res->length() || !delimiter_length || !count) return &my_empty_string; // Wrong parameters res->set_charset(collation.collation); @@ -1114,11 +1114,11 @@ String *Item_func_substr_index::val_str(String *str) #ifdef USE_MB if (use_mb(res->charset())) { - const char *ptr=res->ptr(); - const char *strend = ptr+res->length(); - const char *end=strend-delimeter_length+1; - const char *search=delimeter->ptr(); - const char *search_end=search+delimeter_length; + const char *ptr= res->ptr(); + const char *strend= ptr+res->length(); + const char *end= strend-delimiter_length+1; + const char *search= delimiter->ptr(); + const char *search_end= search+delimiter_length; int32 n=0,c=count,pass; register uint32 l; for (pass=(count>0);pass<2;++pass) @@ -1133,7 +1133,7 @@ String *Item_func_substr_index::val_str(String *str) if (*i++ != *j++) goto skip; if (pass==0) ++n; else if (!--c) break; - ptr+=delimeter_length; + ptr+= delimiter_length; continue; } skip: @@ -1155,7 +1155,7 @@ String *Item_func_substr_index::val_str(String *str) } else /* return right part */ { - ptr+=delimeter_length; + ptr+= delimiter_length; tmp_value.set(*res,(ulong) (ptr-res->ptr()), (ulong) (strend-ptr)); } } @@ -1166,9 +1166,9 @@ String *Item_func_substr_index::val_str(String *str) { if (count > 0) { // start counting from the beginning - for (offset=0 ;; offset+=delimeter_length) + for (offset=0; ; offset+= delimiter_length) { - if ((int) (offset=res->strstr(*delimeter,offset)) < 0) + if ((int) (offset= res->strstr(*delimiter, offset)) < 0) return res; // Didn't find, return org string if (!--count) { @@ -1189,7 +1189,7 @@ String *Item_func_substr_index::val_str(String *str) address space less than where the found substring is located in res */ - if ((int) (offset=res->strrstr(*delimeter,offset)) < 0) + if ((int) (offset= res->strrstr(*delimiter, offset)) < 0) return res; // Didn't find, return org string /* At this point, we've searched for the substring @@ -1197,13 +1197,19 @@ String *Item_func_substr_index::val_str(String *str) */ if (!++count) { - offset+=delimeter_length; + offset+= delimiter_length; tmp_value.set(*res,offset,res->length()- offset); break; } } } } + /* + We always mark tmp_value as const so that if val_str() is called again + on this object, we don't disrupt the contents of tmp_value when it was + derived from another String. + */ + tmp_value.mark_as_const(); return (&tmp_value); } From de0c65dd4e925105b2670e2f86a041cd76820e0d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Feb 2006 19:45:06 +0300 Subject: [PATCH 2/3] Fix bug #15706 find_field_in_tables() returns field from outer select If item->cached_table is set, find_field_in_tables() returns found field even if it doesn't belong to current select. Because Item_field::fix_fields doesn't expect such behaviour, reported bug occurs. Item_field::fix_fields() was modifed to detect when find_field_in_tables() can return field from outer select and process such fields accordingly. In order to ease this code which was searching and processing outed fields was moved into separate function called Item_field::fix_outer_field(). sql/item_subselect.h: Fixed bug #15706: find_field_in_tables() returns field from outer select Item_field::fix_outer_field() was marked as friend to Item_subselect class. sql/item.h: Fixed bug #15706: find_field_in_tables() returns field from outer select fix_outer_field() function is added to the Item_field class. sql/item.cc: Fixed bug #15706: find_field_in_tables() returns field from outer select Item_ref::fix_fields() and Item_field::fix_fields() were modifed to detect when find_field_in_tables() can return field from outer select and process such fields accordingly. In order to ease this, code Item_field::fix_fields() which was searching and processing outer fields was moved into separate function called Item_field::fix_outer_field(). To the Item_field::fix_field() added a loop for finding context for found field. mysql-test/t/disabled.def: Fixed bug #15706: find_field_in_tables() returns field from outer select Enable subselect test --- mysql-test/t/disabled.def | 1 - sql/item.cc | 477 ++++++++++++++++++++++---------------- sql/item.h | 1 + sql/item_subselect.h | 1 + 4 files changed, 285 insertions(+), 195 deletions(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 4722fac435c..4f5e11e7fbd 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -12,4 +12,3 @@ sp-goto : GOTO is currently is disabled - will be fixed in the future kill : Unstable test case, bug#9712 -subselect : Bug#15706 diff --git a/sql/item.cc b/sql/item.cc index 659970f2a91..793cbc70998 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3210,6 +3210,252 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) } +/* + Resolve the name of an outer select column reference. + + SYNOPSIS + Item_field::fix_outer_field() + thd [in] current thread + from_field [in/out] found field reference or (Field*)not_found_field + reference [in/out] view column if this item was resolved to a view column + + DESCRIPTION + The method resolves the column reference represented by 'this' as a column + present in outer selects that contain current select. + + NOTES + This is the inner loop of Item_field::fix_fields: + + for each outer query Q_k beginning from the inner-most one + { + search for a column or derived column named col_ref_i + [in table T_j] in the FROM clause of Q_k; + + if such a column is not found + Search for a column or derived column named col_ref_i + [in table T_j] in the SELECT and GROUP clauses of Q_k. + } + + IMPLEMENTATION + In prepared statements, because of cache, find_field_in_tables() + can resolve fields even if they don't belong to current context. + In this case this method only finds appropriate context and marks + current select as dependent. The found reference of field should be + provided in 'from_field'. + + RETURN + 1 - column succefully resolved and fix_fields() should continue. + 0 - column fully fixed and fix_fields() should return FALSE + -1 - error occured +*/ +int +Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) +{ + enum_parsing_place place= NO_MATTER; + bool field_found= (*from_field != not_found_field); + bool upward_lookup= FALSE; + + /* + If there are outer contexts (outer selects, but current select is + not derived table or view) try to resolve this reference in the + outer contexts. + + We treat each subselect as a separate namespace, so that different + subselects may contain columns with the same names. The subselects + are searched starting from the innermost. + */ + Name_resolution_context *last_checked_context= context; + Item **ref= (Item **) not_found_item; + Name_resolution_context *outer_context= context->outer_context; + for (; + outer_context; + outer_context= outer_context->outer_context) + { + SELECT_LEX *select= outer_context->select_lex; + Item_subselect *prev_subselect_item= + last_checked_context->select_lex->master_unit()->item; + last_checked_context= outer_context; + upward_lookup= TRUE; + + place= prev_subselect_item->parsing_place; + /* + If outer_field is set, field was already found by first call + to find_field_in_tables(). Only need to find appropriate context. + */ + if (field_found && outer_context->select_lex != + cached_table->select_lex) + continue; + /* + In case of a view, find_field_in_tables() writes the pointer to + the found view field into '*reference', in other words, it + substitutes this Item_field with the found expression. + */ + if (field_found || (*from_field= find_field_in_tables(thd, this, + outer_context-> + first_name_resolution_table, + outer_context-> + last_name_resolution_table, + reference, + IGNORE_EXCEPT_NON_UNIQUE, + TRUE, TRUE)) != + not_found_field) + { + if (*from_field) + { + if (*from_field != view_ref_found) + { + prev_subselect_item->used_tables_cache|= (*from_field)->table->map; + prev_subselect_item->const_item_cache= 0; + if (thd->lex->in_sum_func && + thd->lex->in_sum_func->nest_level == + thd->lex->current_select->nest_level) + { + Item::Type type= (*reference)->type(); + set_if_bigger(thd->lex->in_sum_func->max_arg_level, + select->nest_level); + set_field(*from_field); + fixed= 1; + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, + ((type == REF_ITEM || type == FIELD_ITEM) ? + (Item_ident*) (*reference) : 0)); + return 0; + } + } + else + { + Item::Type type= (*reference)->type(); + prev_subselect_item->used_tables_cache|= + (*reference)->used_tables(); + prev_subselect_item->const_item_cache&= + (*reference)->const_item(); + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, + ((type == REF_ITEM || type == FIELD_ITEM) ? + (Item_ident*) (*reference) : + 0)); + /* + A reference to a view field had been found and we + substituted it instead of this Item (find_field_in_tables + does it by assigning the new value to *reference), so now + we can return from this function. + */ + return 0; + } + } + break; + } + + /* Search in SELECT and GROUP lists of the outer select. */ + if (outer_context->resolve_in_select_list) + { + if (!(ref= resolve_ref_in_select_and_group(thd, this, select))) + return -1; /* Some error occurred (e.g. ambiguous names). */ + if (ref != not_found_item) + { + DBUG_ASSERT(*ref && (*ref)->fixed); + prev_subselect_item->used_tables_cache|= (*ref)->used_tables(); + prev_subselect_item->const_item_cache&= (*ref)->const_item(); + break; + } + } + + /* + Reference is not found in this select => this subquery depend on + outer select (or we just trying to find wrong identifier, in this + case it does not matter which used tables bits we set) + */ + prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; + prev_subselect_item->const_item_cache= 0; + } + + DBUG_ASSERT(ref != 0); + if (!*from_field) + return -1; + if (ref == not_found_item && *from_field == not_found_field) + { + if (upward_lookup) + { + // We can't say exactly what absent table or field + my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where); + } + else + { + /* Call find_field_in_tables only to report the error */ + find_field_in_tables(thd, this, + context->first_name_resolution_table, + context->last_name_resolution_table, + reference, REPORT_ALL_ERRORS, + !any_privileges && + TRUE, TRUE); + } + return -1; + } + else if (ref != not_found_item) + { + Item *save; + Item_ref *rf; + + /* Should have been checked in resolve_ref_in_select_and_group(). */ + DBUG_ASSERT(*ref && (*ref)->fixed); + /* + Here, a subset of actions performed by Item_ref::set_properties + is not enough. So we pass ptr to NULL into Item_[direct]_ref + constructor, so no initialization is performed, and call + fix_fields() below. + */ + save= *ref; + *ref= NULL; // Don't call set_properties() + rf= (place == IN_HAVING ? + new Item_ref(context, ref, (char*) table_name, + (char*) field_name) : + new Item_direct_ref(context, ref, (char*) table_name, + (char*) field_name)); + *ref= save; + if (!rf) + return -1; + thd->change_item_tree(reference, rf); + /* + rf is Item_ref => never substitute other items (in this case) + during fix_fields() => we can use rf after fix_fields() + */ + DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() + if (rf->fix_fields(thd, reference) || rf->check_cols(1)) + return -1; + + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, + rf); + return 0; + } + else + { + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, + this, this); + if (last_checked_context->select_lex->having_fix_field) + { + Item_ref *rf; + rf= new Item_ref(context, + (cached_table->db[0] ? cached_table->db : 0), + (char*) cached_table->alias, (char*) field_name); + if (!rf) + return -1; + thd->change_item_tree(reference, rf); + /* + rf is Item_ref => never substitute other items (in this case) + during fix_fields() => we can use rf after fix_fields() + */ + DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() + if (rf->fix_fields(thd, reference) || rf->check_cols(1)) + return -1; + return 0; + } + } + return 1; +} + + /* Resolve the name of a column reference. @@ -3257,12 +3503,11 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) bool Item_field::fix_fields(THD *thd, Item **reference) { - enum_parsing_place place= NO_MATTER; DBUG_ASSERT(fixed == 0); if (!field) // If field is not checked { - bool upward_lookup= FALSE; Field *from_field= (Field *)not_found_field; + bool outer_fixed= false; /* In case of view, find_field_in_tables() write pointer to view field expression to 'reference', i.e. it substitute that expression instead @@ -3277,7 +3522,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) TRUE)) == not_found_field) { - + int ret; /* Look up in current select's item_list to find aliased fields */ if (thd->lex->current_select->is_item_list_lookup) { @@ -3292,197 +3537,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference) return 0; } } - - /* - If there are outer contexts (outer selects, but current select is - not derived table or view) try to resolve this reference in the - outer contexts. - - We treat each subselect as a separate namespace, so that different - subselects may contain columns with the same names. The subselects - are searched starting from the innermost. - */ - Name_resolution_context *last_checked_context= context; - Item **ref= (Item **) not_found_item; - Name_resolution_context *outer_context= context->outer_context; - for (; - outer_context; - outer_context= outer_context->outer_context) - { - SELECT_LEX *select= outer_context->select_lex; - Item_subselect *prev_subselect_item= - last_checked_context->select_lex->master_unit()->item; - last_checked_context= outer_context; - upward_lookup= TRUE; - - place= prev_subselect_item->parsing_place; - /* - In case of a view, find_field_in_tables() writes the pointer to - the found view field into '*reference', in other words, it - substitutes this Item_field with the found expression. - */ - if ((from_field= find_field_in_tables(thd, this, - outer_context-> - first_name_resolution_table, - outer_context-> - last_name_resolution_table, - reference, - IGNORE_EXCEPT_NON_UNIQUE, - TRUE, TRUE)) != - not_found_field) - { - if (from_field) - { - if (from_field != view_ref_found) - { - prev_subselect_item->used_tables_cache|= from_field->table->map; - prev_subselect_item->const_item_cache= 0; - if (thd->lex->in_sum_func && - thd->lex->in_sum_func->nest_level == - thd->lex->current_select->nest_level) - { - Item::Type type= (*reference)->type(); - set_if_bigger(thd->lex->in_sum_func->max_arg_level, - select->nest_level); - set_field(from_field); - fixed= 1; - mark_as_dependent(thd, last_checked_context->select_lex, - context->select_lex, this, - ((type == REF_ITEM || type == FIELD_ITEM) ? - (Item_ident*) (*reference) : 0)); - return FALSE; - } - } - else - { - Item::Type type= (*reference)->type(); - prev_subselect_item->used_tables_cache|= - (*reference)->used_tables(); - prev_subselect_item->const_item_cache&= - (*reference)->const_item(); - mark_as_dependent(thd, last_checked_context->select_lex, - context->select_lex, this, - ((type == REF_ITEM || type == FIELD_ITEM) ? - (Item_ident*) (*reference) : - 0)); - /* - A reference to a view field had been found and we - substituted it instead of this Item (find_field_in_tables - does it by assigning the new value to *reference), so now - we can return from this function. - */ - return FALSE; - } - } - break; - } - - /* Search in SELECT and GROUP lists of the outer select. */ - if (outer_context->resolve_in_select_list) - { - if (!(ref= resolve_ref_in_select_and_group(thd, this, select))) - goto error; /* Some error occurred (e.g. ambiguous names). */ - if (ref != not_found_item) - { - DBUG_ASSERT(*ref && (*ref)->fixed); - prev_subselect_item->used_tables_cache|= (*ref)->used_tables(); - prev_subselect_item->const_item_cache&= (*ref)->const_item(); - break; - } - } - - /* - Reference is not found in this select => this subquery depend on - outer select (or we just trying to find wrong identifier, in this - case it does not matter which used tables bits we set) - */ - prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; - prev_subselect_item->const_item_cache= 0; - } - - DBUG_ASSERT(ref != 0); - if (!from_field) - goto error; - if (ref == not_found_item && from_field == not_found_field) - { - if (upward_lookup) - { - // We can't say exactly what absent table or field - my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where); - } - else - { - /* Call find_field_in_tables only to report the error */ - find_field_in_tables(thd, this, - context->first_name_resolution_table, - context->last_name_resolution_table, - reference, REPORT_ALL_ERRORS, - !any_privileges && - TRUE, TRUE); - } - goto error; - } - else if (ref != not_found_item) - { - Item *save; - Item_ref *rf; - - /* Should have been checked in resolve_ref_in_select_and_group(). */ - DBUG_ASSERT(*ref && (*ref)->fixed); - /* - Here, a subset of actions performed by Item_ref::set_properties - is not enough. So we pass ptr to NULL into Item_[direct]_ref - constructor, so no initialization is performed, and call - fix_fields() below. - */ - save= *ref; - *ref= NULL; // Don't call set_properties() - rf= (place == IN_HAVING ? - new Item_ref(context, ref, (char*) table_name, - (char*) field_name) : - new Item_direct_ref(context, ref, (char*) table_name, - (char*) field_name)); - *ref= save; - if (!rf) - goto error; - thd->change_item_tree(reference, rf); - /* - rf is Item_ref => never substitute other items (in this case) - during fix_fields() => we can use rf after fix_fields() - */ - DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() - if (rf->fix_fields(thd, reference) || rf->check_cols(1)) - goto error; - - mark_as_dependent(thd, last_checked_context->select_lex, - context->select_lex, this, - rf); - return FALSE; - } - else - { - mark_as_dependent(thd, last_checked_context->select_lex, - context->select_lex, - this, this); - if (last_checked_context->select_lex->having_fix_field) - { - Item_ref *rf; - rf= new Item_ref(context, - (cached_table->db[0] ? cached_table->db : 0), - (char*) cached_table->alias, (char*) field_name); - if (!rf) - goto error; - thd->change_item_tree(reference, rf); - /* - rf is Item_ref => never substitute other items (in this case) - during fix_fields() => we can use rf after fix_fields() - */ - DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() - if (rf->fix_fields(thd, reference) || rf->check_cols(1)) - goto error; - return FALSE; - } - } + if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) + goto error; + else if (!ret) + return FALSE; + outer_fixed= TRUE; } else if (!from_field) goto error; @@ -3502,6 +3561,17 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (from_field == view_ref_found) return FALSE; + if (!outer_fixed && cached_table && cached_table->select_lex && + context->select_lex && + cached_table->select_lex != context->select_lex) + { + int ret; + if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) + goto error; + else if (!ret) + return FALSE; + } + set_field(from_field); if (thd->lex->in_sum_func && thd->lex->in_sum_func->nest_level == @@ -4620,6 +4690,25 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) } if (from_field != not_found_field) { + if (cached_table && cached_table->select_lex && + outer_context->select_lex && + cached_table->select_lex != outer_context->select_lex) + { + /* + Due to cache, find_field_in_tables() can return field which + doesn't belong to provided outer_context. In this case we have + to find proper field context in order to fix field correcly. + */ + do + { + outer_context= outer_context->outer_context; + select= outer_context->select_lex; + prev_subselect_item= + last_checked_context->select_lex->master_unit()->item; + last_checked_context= outer_context; + } while (outer_context && outer_context->select_lex && + cached_table->select_lex != outer_context->select_lex); + } prev_subselect_item->used_tables_cache|= from_field->table->map; prev_subselect_item->const_item_cache= 0; break; diff --git a/sql/item.h b/sql/item.h index 4b49ff907d3..1a5e64c585b 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1161,6 +1161,7 @@ public: inline uint32 max_disp_length() { return field->max_length(); } Item_field *filed_for_view_update() { return this; } Item *safe_charset_converter(CHARSET_INFO *tocs); + int fix_outer_field(THD *thd, Field **field, Item **reference); friend class Item_default_value; friend class Item_insert_value; friend class st_select_lex_unit; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index f1c99f74498..a4dac5bda87 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -125,6 +125,7 @@ public: friend class select_subselect; friend class Item_in_optimizer; friend bool Item_field::fix_fields(THD *, Item **); + friend int Item_field::fix_outer_field(THD *, Field **, Item **); friend bool Item_ref::fix_fields(THD *, Item **); friend void mark_select_range_as_dependent(THD*, st_select_lex*, st_select_lex*, From eae6679fd4a55a1798f2c20385507f869c85e7a6 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 17 Feb 2006 10:02:59 -0800 Subject: [PATCH 3/3] Fix subselect results (there was a bad merge when subselect test was disabled) BitKeeper/etc/ignore: Added scripts/mysql_upgrade to the ignore list mysql-test/r/subselect.result: Update results --- .bzrignore | 1 + mysql-test/r/subselect.result | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.bzrignore b/.bzrignore index a210762d46a..a16ed70a812 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1273,3 +1273,4 @@ vio/viotest-sslconnect.cpp vio/viotest.cpp zlib/*.ds? zlib/*.vcproj +scripts/mysql_upgrade diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 85976c211c5..6094d23b0d0 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -215,9 +215,9 @@ select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from a select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; b (select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) -8 7.5 -8 4.5 -9 7.5 +8 7.5000 +8 4.5000 +9 7.5000 explain extended select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t4 ALL NULL NULL NULL NULL 3