summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_base.cc12
-rw-r--r--sql/sql_class.h7
-rw-r--r--sql/sql_lex.cc6
-rw-r--r--sql/sql_priv.h1
-rw-r--r--sql/sql_yacc.yy44
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;
}
;