Loading mysql-test/t/disabled.def +0 −1 Original line number Diff line number Diff line Loading @@ -11,5 +11,4 @@ ############################################################################## sp-goto : GOTO is currently is disabled - will be fixed in the future subselect : Bug#15706 ndb_load : Bug#17233 sql/item.cc +283 −194 Original line number Diff line number Diff line Loading @@ -3211,30 +3211,21 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) /* Resolve the name of a column reference. Resolve the name of an outer select column reference. SYNOPSIS Item_field::fix_fields() 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 one of: FROM clause, SELECT clause, GROUP BY clause of a query Q, or in outer queries that contain Q. present in outer selects that contain current select. NOTES The name resolution algorithm used is (where [T_j] is an optional table name that qualifies the column name): This is the inner loop of Item_field::fix_fields: resolve_column_reference([T_j].col_ref_i) { search for a column or derived column named col_ref_i [in table T_j] in the FROM clause of Q; if such a column is NOT found AND // Lookup in outer queries. there are outer queries { for each outer query Q_k beginning from the inner-most one { search for a column or derived column named col_ref_i Loading @@ -3244,54 +3235,25 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) Search for a column or derived column named col_ref_i [in table T_j] in the SELECT and GROUP clauses of Q_k. } } } Notice that compared to Item_ref::fix_fields, here we first search the FROM clause, and then we search the SELECT and GROUP BY clauses. 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 TRUE if error FALSE on success 1 - column succefully resolved and fix_fields() should continue. 0 - column fully fixed and fix_fields() should return FALSE -1 - error occured */ bool Item_field::fix_fields(THD *thd, Item **reference) int Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) { enum_parsing_place place= NO_MATTER; DBUG_ASSERT(fixed == 0); if (!field) // If field is not checked { bool field_found= (*from_field != not_found_field); bool upward_lookup= FALSE; Field *from_field= (Field *)not_found_field; /* In case of view, find_field_in_tables() write pointer to view field expression to 'reference', i.e. it substitute that expression instead of this Item_field */ if ((from_field= find_field_in_tables(thd, this, context->first_name_resolution_table, context->last_name_resolution_table, reference, IGNORE_EXCEPT_NON_UNIQUE, !any_privileges, TRUE)) == not_found_field) { /* Look up in current select's item_list to find aliased fields */ if (thd->lex->current_select->is_item_list_lookup) { uint counter; bool not_used; Item** res= find_item_in_list(this, thd->lex->current_select->item_list, &counter, REPORT_EXCEPT_NOT_FOUND, ¬_used); if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM) { set_field((*((Item_field**)res))->field); return 0; } } /* If there are outer contexts (outer selects, but current select is Loading @@ -3316,12 +3278,19 @@ bool Item_field::fix_fields(THD *thd, Item **reference) 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 ((from_field= find_field_in_tables(thd, this, if (field_found || (*from_field= find_field_in_tables(thd, this, outer_context-> first_name_resolution_table, outer_context-> Loading @@ -3331,11 +3300,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference) TRUE, TRUE)) != not_found_field) { if (from_field) if (*from_field) { if (from_field != view_ref_found) if (*from_field != view_ref_found) { prev_subselect_item->used_tables_cache|= from_field->table->map; 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 == Loading @@ -3344,13 +3313,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference) Item::Type type= (*reference)->type(); set_if_bigger(thd->lex->in_sum_func->max_arg_level, select->nest_level); set_field(from_field); 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; return 0; } } else Loading @@ -3371,7 +3340,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) does it by assigning the new value to *reference), so now we can return from this function. */ return FALSE; return 0; } } break; Loading @@ -3381,7 +3350,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) 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). */ return -1; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { DBUG_ASSERT(*ref && (*ref)->fixed); Loading @@ -3401,9 +3370,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) } DBUG_ASSERT(ref != 0); if (!from_field) goto error; if (ref == not_found_item && from_field == not_found_field) if (!*from_field) return -1; if (ref == not_found_item && *from_field == not_found_field) { if (upward_lookup) { Loading @@ -3420,7 +3389,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) !any_privileges && TRUE, TRUE); } goto error; return -1; } else if (ref != not_found_item) { Loading @@ -3444,7 +3413,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) (char*) field_name)); *ref= save; if (!rf) goto error; return -1; thd->change_item_tree(reference, rf); /* rf is Item_ref => never substitute other items (in this case) Loading @@ -3452,12 +3421,12 @@ bool Item_field::fix_fields(THD *thd, Item **reference) */ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() if (rf->fix_fields(thd, reference) || rf->check_cols(1)) goto error; return -1; mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, rf); return FALSE; return 0; } else { Loading @@ -3471,7 +3440,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) (cached_table->db[0] ? cached_table->db : 0), (char*) cached_table->alias, (char*) field_name); if (!rf) goto error; return -1; thd->change_item_tree(reference, rf); /* rf is Item_ref => never substitute other items (in this case) Loading @@ -3479,10 +3448,100 @@ bool Item_field::fix_fields(THD *thd, Item **reference) */ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() if (rf->fix_fields(thd, reference) || rf->check_cols(1)) goto error; return FALSE; return -1; return 0; } } return 1; } /* Resolve the name of a column reference. SYNOPSIS Item_field::fix_fields() thd [in] current thread 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 one of: FROM clause, SELECT clause, GROUP BY clause of a query Q, or in outer queries that contain Q. NOTES The name resolution algorithm used is (where [T_j] is an optional table name that qualifies the column name): resolve_column_reference([T_j].col_ref_i) { search for a column or derived column named col_ref_i [in table T_j] in the FROM clause of Q; if such a column is NOT found AND // Lookup in outer queries. there are outer queries { 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. } } } Notice that compared to Item_ref::fix_fields, here we first search the FROM clause, and then we search the SELECT and GROUP BY clauses. RETURN TRUE if error FALSE on success */ bool Item_field::fix_fields(THD *thd, Item **reference) { DBUG_ASSERT(fixed == 0); if (!field) // If field is not checked { 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 of this Item_field */ if ((from_field= find_field_in_tables(thd, this, context->first_name_resolution_table, context->last_name_resolution_table, reference, IGNORE_EXCEPT_NON_UNIQUE, !any_privileges, 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) { uint counter; bool not_used; Item** res= find_item_in_list(this, thd->lex->current_select->item_list, &counter, REPORT_EXCEPT_NOT_FOUND, ¬_used); if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM) { set_field((*((Item_field**)res))->field); return 0; } } 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; Loading @@ -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 == Loading Loading @@ -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; Loading sql/item.h +1 −0 Original line number Diff line number Diff line Loading @@ -1161,6 +1161,7 @@ class Item_field :public Item_ident 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; Loading sql/item_subselect.h +1 −0 Original line number Diff line number Diff line Loading @@ -125,6 +125,7 @@ class Item_subselect :public Item_result_field 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*, Loading Loading
mysql-test/t/disabled.def +0 −1 Original line number Diff line number Diff line Loading @@ -11,5 +11,4 @@ ############################################################################## sp-goto : GOTO is currently is disabled - will be fixed in the future subselect : Bug#15706 ndb_load : Bug#17233
sql/item.cc +283 −194 Original line number Diff line number Diff line Loading @@ -3211,30 +3211,21 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) /* Resolve the name of a column reference. Resolve the name of an outer select column reference. SYNOPSIS Item_field::fix_fields() 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 one of: FROM clause, SELECT clause, GROUP BY clause of a query Q, or in outer queries that contain Q. present in outer selects that contain current select. NOTES The name resolution algorithm used is (where [T_j] is an optional table name that qualifies the column name): This is the inner loop of Item_field::fix_fields: resolve_column_reference([T_j].col_ref_i) { search for a column or derived column named col_ref_i [in table T_j] in the FROM clause of Q; if such a column is NOT found AND // Lookup in outer queries. there are outer queries { for each outer query Q_k beginning from the inner-most one { search for a column or derived column named col_ref_i Loading @@ -3244,54 +3235,25 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) Search for a column or derived column named col_ref_i [in table T_j] in the SELECT and GROUP clauses of Q_k. } } } Notice that compared to Item_ref::fix_fields, here we first search the FROM clause, and then we search the SELECT and GROUP BY clauses. 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 TRUE if error FALSE on success 1 - column succefully resolved and fix_fields() should continue. 0 - column fully fixed and fix_fields() should return FALSE -1 - error occured */ bool Item_field::fix_fields(THD *thd, Item **reference) int Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) { enum_parsing_place place= NO_MATTER; DBUG_ASSERT(fixed == 0); if (!field) // If field is not checked { bool field_found= (*from_field != not_found_field); bool upward_lookup= FALSE; Field *from_field= (Field *)not_found_field; /* In case of view, find_field_in_tables() write pointer to view field expression to 'reference', i.e. it substitute that expression instead of this Item_field */ if ((from_field= find_field_in_tables(thd, this, context->first_name_resolution_table, context->last_name_resolution_table, reference, IGNORE_EXCEPT_NON_UNIQUE, !any_privileges, TRUE)) == not_found_field) { /* Look up in current select's item_list to find aliased fields */ if (thd->lex->current_select->is_item_list_lookup) { uint counter; bool not_used; Item** res= find_item_in_list(this, thd->lex->current_select->item_list, &counter, REPORT_EXCEPT_NOT_FOUND, ¬_used); if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM) { set_field((*((Item_field**)res))->field); return 0; } } /* If there are outer contexts (outer selects, but current select is Loading @@ -3316,12 +3278,19 @@ bool Item_field::fix_fields(THD *thd, Item **reference) 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 ((from_field= find_field_in_tables(thd, this, if (field_found || (*from_field= find_field_in_tables(thd, this, outer_context-> first_name_resolution_table, outer_context-> Loading @@ -3331,11 +3300,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference) TRUE, TRUE)) != not_found_field) { if (from_field) if (*from_field) { if (from_field != view_ref_found) if (*from_field != view_ref_found) { prev_subselect_item->used_tables_cache|= from_field->table->map; 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 == Loading @@ -3344,13 +3313,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference) Item::Type type= (*reference)->type(); set_if_bigger(thd->lex->in_sum_func->max_arg_level, select->nest_level); set_field(from_field); 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; return 0; } } else Loading @@ -3371,7 +3340,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) does it by assigning the new value to *reference), so now we can return from this function. */ return FALSE; return 0; } } break; Loading @@ -3381,7 +3350,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) 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). */ return -1; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { DBUG_ASSERT(*ref && (*ref)->fixed); Loading @@ -3401,9 +3370,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) } DBUG_ASSERT(ref != 0); if (!from_field) goto error; if (ref == not_found_item && from_field == not_found_field) if (!*from_field) return -1; if (ref == not_found_item && *from_field == not_found_field) { if (upward_lookup) { Loading @@ -3420,7 +3389,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) !any_privileges && TRUE, TRUE); } goto error; return -1; } else if (ref != not_found_item) { Loading @@ -3444,7 +3413,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) (char*) field_name)); *ref= save; if (!rf) goto error; return -1; thd->change_item_tree(reference, rf); /* rf is Item_ref => never substitute other items (in this case) Loading @@ -3452,12 +3421,12 @@ bool Item_field::fix_fields(THD *thd, Item **reference) */ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() if (rf->fix_fields(thd, reference) || rf->check_cols(1)) goto error; return -1; mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, rf); return FALSE; return 0; } else { Loading @@ -3471,7 +3440,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) (cached_table->db[0] ? cached_table->db : 0), (char*) cached_table->alias, (char*) field_name); if (!rf) goto error; return -1; thd->change_item_tree(reference, rf); /* rf is Item_ref => never substitute other items (in this case) Loading @@ -3479,10 +3448,100 @@ bool Item_field::fix_fields(THD *thd, Item **reference) */ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() if (rf->fix_fields(thd, reference) || rf->check_cols(1)) goto error; return FALSE; return -1; return 0; } } return 1; } /* Resolve the name of a column reference. SYNOPSIS Item_field::fix_fields() thd [in] current thread 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 one of: FROM clause, SELECT clause, GROUP BY clause of a query Q, or in outer queries that contain Q. NOTES The name resolution algorithm used is (where [T_j] is an optional table name that qualifies the column name): resolve_column_reference([T_j].col_ref_i) { search for a column or derived column named col_ref_i [in table T_j] in the FROM clause of Q; if such a column is NOT found AND // Lookup in outer queries. there are outer queries { 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. } } } Notice that compared to Item_ref::fix_fields, here we first search the FROM clause, and then we search the SELECT and GROUP BY clauses. RETURN TRUE if error FALSE on success */ bool Item_field::fix_fields(THD *thd, Item **reference) { DBUG_ASSERT(fixed == 0); if (!field) // If field is not checked { 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 of this Item_field */ if ((from_field= find_field_in_tables(thd, this, context->first_name_resolution_table, context->last_name_resolution_table, reference, IGNORE_EXCEPT_NON_UNIQUE, !any_privileges, 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) { uint counter; bool not_used; Item** res= find_item_in_list(this, thd->lex->current_select->item_list, &counter, REPORT_EXCEPT_NOT_FOUND, ¬_used); if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM) { set_field((*((Item_field**)res))->field); return 0; } } 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; Loading @@ -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 == Loading Loading @@ -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; Loading
sql/item.h +1 −0 Original line number Diff line number Diff line Loading @@ -1161,6 +1161,7 @@ class Item_field :public Item_ident 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; Loading
sql/item_subselect.h +1 −0 Original line number Diff line number Diff line Loading @@ -125,6 +125,7 @@ class Item_subselect :public Item_result_field 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*, Loading