diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sql_base.cc | 12 | ||||
-rw-r--r-- | sql/sql_class.h | 7 | ||||
-rw-r--r-- | sql/sql_lex.cc | 6 | ||||
-rw-r--r-- | sql/sql_priv.h | 1 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 44 |
5 files changed, 50 insertions, 20 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b10f09d67a5..607d03d3450 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7484,10 +7484,12 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, Item *item; List_iterator<Item> it(fields); Query_arena *arena, backup; + uint *with_wild= returning_field ? &(thd->lex->returning()->with_wild) : + &(select_lex->with_wild); DBUG_ENTER("setup_wild"); - if (!select_lex->with_wild) - DBUG_RETURN(0); + if (!(*with_wild)) + DBUG_RETURN(0); /* Don't use arena if we are not in prepared statements or stored procedures @@ -7496,7 +7498,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, arena= thd->activate_stmt_arena_if_needed(&backup); thd->lex->current_select->cur_pos_in_select_list= 0; - while (select_lex->with_wild && (item= it++)) + while (*with_wild && (item= it++)) { if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name.str == star_clex_str.str && @@ -7534,12 +7536,12 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, */ sum_func_list->elements+= fields.elements - elem; } - select_lex->with_wild--; + (*with_wild)--; } else thd->lex->current_select->cur_pos_in_select_list++; } - DBUG_ASSERT(!select_lex->with_wild); + DBUG_ASSERT(!(*with_wild)); thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS; if (arena) thd->restore_active_arena(arena, &backup); diff --git a/sql/sql_class.h b/sql/sql_class.h index 880a3bc1d09..51c1bc984da 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -7039,7 +7039,12 @@ public: inline bool add_item_to_list(THD *thd, Item *item) { - bool res= thd->lex->current_select->add_item_to_list(thd, item); + bool res; + LEX *lex= thd->lex; + if (lex->current_select->parsing_place == IN_RETURNING) + res= lex->returning()->add_item_to_list(thd, item); + else + res= lex->current_select->add_item_to_list(thd, item); return res; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 4fe097a4067..35ed1af7bc1 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -9522,7 +9522,8 @@ Item *LEX::create_item_qualified_asterisk(THD *thd, null_clex_str, *name, star_clex_str))) return NULL; - current_select->with_wild++; + current_select->parsing_place == IN_RETURNING ? + thd->lex->returning()->with_wild++ : current_select->with_wild++; return item; } @@ -9537,7 +9538,8 @@ Item *LEX::create_item_qualified_asterisk(THD *thd, if (!(item= new (thd->mem_root) Item_field(thd, current_context(), schema, *b, star_clex_str))) return NULL; - current_select->with_wild++; + current_select->parsing_place == IN_RETURNING ? + thd->lex->returning()->with_wild++ : current_select->with_wild++; return item; } diff --git a/sql/sql_priv.h b/sql/sql_priv.h index b18a80ba1f2..a304cd39df7 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -374,6 +374,7 @@ enum enum_parsing_place BEFORE_OPT_LIST, AFTER_LIST, FOR_LOOP_BOUND, + IN_RETURNING, PARSING_PLACE_SIZE /* always should be the last */ }; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index cab60b2c266..9e172646af9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9175,14 +9175,20 @@ select_item_list: | select_item | '*' { + bool is_parsing_returning= + thd->lex->current_select->parsing_place == + IN_RETURNING; + SELECT_LEX *correct_select= is_parsing_returning ? + thd->lex->returning() : + thd->lex->current_select; Item *item= new (thd->mem_root) - Item_field(thd, &thd->lex->current_select->context, + Item_field(thd, &correct_select->context, star_clex_str); if (unlikely(item == NULL)) MYSQL_YYABORT; if (unlikely(add_item_to_list(thd, item))) MYSQL_YYABORT; - (thd->lex->current_select->with_wild)++; + correct_select->with_wild++; } ; @@ -13360,19 +13366,33 @@ opt_returning: | RETURNING_SYM { DBUG_ASSERT(!Lex->has_returning()); - if (($<num>$= (Select != Lex->returning()))) - { - SELECT_LEX *sl= Lex->returning(); - sl->set_master_unit(0); - Select->attach_single(Lex->create_unit(sl)); - sl->include_global((st_select_lex_node**)&Lex->all_selects_list); - Lex->push_select(sl); - } + /* + When parsing_place is IN_RETURNING, we push select items to + item_list of builtin_select instead of current_select. + But set parsing_place of current_select to true. + + Because parsing_place for builtin_select will be IN_RETURNING, + regardless there is SELECT in RETURNING. Example, if + there is RETURNING (SELECT...), then when we parse + SELECT inside RETURNING, builtin_select->parsing_place + will still be true. So the select items of SELECT inside + RETURNING will be added to item_list of builtin_select which + is incorrect. We want to prevent this from happening. + Since for every new select, a new SELECT_LEX + object is created and pushed to select stack, current_select + will point to SELECT inside RETURNING, and also has + parsing_place not set to IN_RETURNING by default. + So items are correctly added to item_list of SELECT inside + RETURNING instead of builtin_select. + */ + + thd->lex->current_select->parsing_place= IN_RETURNING; + thd->lex->push_context(&thd->lex->returning()->context); } select_item_list { - if ($<num>2) - Lex->pop_select(); + thd->lex->pop_context(); + thd->lex->current_select->parsing_place= NO_MATTER; } ; |