summaryrefslogtreecommitdiff
path: root/sql/sql_lex.cc
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2019-09-20 09:03:38 -0700
committerIgor Babaev <igor@askmonty.org>2019-09-23 09:57:37 -0700
commitb44171428ab2ea25db82f7cd27349e67812e4921 (patch)
tree15508ccee1f052305f1fe8b421e9dbf69f8df6e8 /sql/sql_lex.cc
parente3da362c037af95a85d3054243a4c9a039ceb4b4 (diff)
downloadmariadb-git-b44171428ab2ea25db82f7cd27349e67812e4921.tar.gz
MDEV-19956 Queries with subqueries containing UNION are not parsed
Shift-Reduce conflicts prevented parsing some queries with subqueries that used set operations when the subqueries occurred in expressions or in IN predicands. The grammar rules for query expression were transformed in order to avoid these conflicts. New grammar rules employ an idea taken from MySQL 8.0.
Diffstat (limited to 'sql/sql_lex.cc')
-rw-r--r--sql/sql_lex.cc295
1 files changed, 111 insertions, 184 deletions
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 7952b2a267e..826e7a6def0 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1444,7 +1444,7 @@ int Lex_input_stream::lex_token(YYSTYPE *yylval, THD *thd)
return LEFT_PAREN_LIKE;
if (token == WITH)
return LEFT_PAREN_WITH;
- if (token != left_paren && token != SELECT_SYM)
+ if (token != left_paren && token != SELECT_SYM && token != VALUES)
return LEFT_PAREN_ALT;
else
return left_paren;
@@ -5339,10 +5339,9 @@ LEX::create_unit(SELECT_LEX *first_sel)
SELECT_LEX_UNIT *unit;
DBUG_ENTER("LEX::create_unit");
- if (first_sel->master_unit())
- DBUG_RETURN(first_sel->master_unit());
+ unit = first_sel->master_unit();
- if (!(unit= alloc_unit()))
+ if (!unit && !(unit= alloc_unit()))
DBUG_RETURN(NULL);
unit->register_select_chain(first_sel);
@@ -9001,7 +9000,8 @@ bool LEX::insert_select_hack(SELECT_LEX *sel)
builtin_select.link_prev= NULL; // indicator of removal
}
- set_main_unit(sel->master_unit());
+ if (set_main_unit(sel->master_unit()))
+ return true;
DBUG_ASSERT(builtin_select.table_list.elements == 1);
TABLE_LIST *insert_table= builtin_select.table_list.first;
@@ -9045,9 +9045,10 @@ bool LEX::insert_select_hack(SELECT_LEX *sel)
}
-/*
+/**
Create an Item_singlerow_subselect for a query expression.
*/
+
Item *LEX::create_item_query_expression(THD *thd,
st_select_lex_unit *unit)
{
@@ -9062,118 +9063,17 @@ Item *LEX::create_item_query_expression(THD *thd,
SELECT_LEX *curr_sel= select_stack_head();
DBUG_ASSERT(current_select == curr_sel);
if (!curr_sel)
+ {
curr_sel= &builtin_select;
- curr_sel->register_unit(unit, &curr_sel->context);
- curr_sel->add_statistics(unit);
+ curr_sel->register_unit(unit, &curr_sel->context);
+ curr_sel->add_statistics(unit);
+ }
return new (thd->mem_root)
Item_singlerow_subselect(thd, unit->first_select());
}
-/**
- Process unit parsed in brackets
-*/
-
-bool LEX::parsed_unit_in_brackets(SELECT_LEX_UNIT *unit)
-{
- SELECT_LEX *first_in_nest= unit->pre_last_parse->next_select()->first_nested;
- if (first_in_nest->first_nested != first_in_nest)
- {
- /* There is a priority jump starting from first_in_nest */
- if (create_priority_nest(first_in_nest) == NULL)
- return true;
- unit->fix_distinct();
- }
- push_select(unit->fake_select_lex);
- return false;
-}
-
-
-
-/**
- Process tail of unit parsed in brackets
-*/
-SELECT_LEX *LEX::parsed_unit_in_brackets_tail(SELECT_LEX_UNIT *unit,
- Lex_order_limit_lock * l)
-{
- pop_select();
- if (l)
- {
- (l)->set_to(unit->fake_select_lex);
- }
- return unit->first_select();
-}
-
-
-/**
- Process select parsed in brackets
-*/
-
-SELECT_LEX *LEX::parsed_select(SELECT_LEX *sel, Lex_order_limit_lock * l)
-{
- pop_select();
- if (l)
- {
- if (sel->next_select())
- {
- SELECT_LEX_UNIT *unit= sel->master_unit();
- if (!unit)
- unit= create_unit(sel);
- if (!unit)
- return NULL;
- if (!unit->fake_select_lex->is_set_query_expr_tail)
- l->set_to(unit->fake_select_lex);
- else
- {
- if (!l->order_list && !unit->fake_select_lex->explicit_limit)
- {
- sel= unit->fake_select_lex;
- l->order_list= &sel->order_list;
- }
- else
- sel= wrap_unit_into_derived(unit);
- if (!sel)
- return NULL;
- l->set_to(sel);
- }
- }
- else if (!sel->is_set_query_expr_tail)
- {
- l->set_to(sel);
- }
- else
- {
- if (!l->order_list && !sel->explicit_limit)
- l->order_list= &sel->order_list;
- else
- {
- SELECT_LEX_UNIT *unit= create_unit(sel);
- if (!unit)
- return NULL;
- sel= wrap_unit_into_derived(unit);
- }
- if (!sel)
- return NULL;
- l->set_to(sel);
- }
- }
- return sel;
-}
-
-
-/**
- Process select parsed in brackets
-*/
-
-SELECT_LEX *LEX::parsed_select_in_brackets(SELECT_LEX *sel,
- Lex_order_limit_lock * l)
-{
- sel->braces= TRUE;
- return parsed_select(sel, l);
-}
-
-
SELECT_LEX_UNIT *LEX::parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2,
enum sub_select_type unit_type,
bool distinct)
@@ -9204,6 +9104,7 @@ SELECT_LEX_UNIT *LEX::parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2,
if (res == NULL)
return NULL;
res->pre_last_parse= sel1;
+ push_select(res->fake_select_lex);
return res;
}
@@ -9216,12 +9117,6 @@ SELECT_LEX_UNIT *LEX::parsed_select_expr_cont(SELECT_LEX_UNIT *unit,
SELECT_LEX *sel1;
if (!s2->next_select())
sel1= s2;
- else
- {
- sel1= wrap_unit_into_derived(s2->master_unit());
- if (!sel1)
- return NULL;
- }
SELECT_LEX *last= unit->pre_last_parse->next_select();
int cmp= oracle? 0 : cmp_unit_op(unit_type, last->get_linkage());
@@ -9253,41 +9148,73 @@ SELECT_LEX_UNIT *LEX::parsed_select_expr_cont(SELECT_LEX_UNIT *unit,
return unit;
}
+
/**
- Process parsed select in body
+ Add primary expression as the next term in a given query expression body
+ pruducing a new query expression body
*/
-SELECT_LEX_UNIT *LEX::parsed_body_select(SELECT_LEX *sel,
- Lex_order_limit_lock * l)
+SELECT_LEX_UNIT *
+LEX::add_primary_to_query_expression_body(SELECT_LEX_UNIT *unit,
+ SELECT_LEX *sel,
+ enum sub_select_type unit_type,
+ bool distinct,
+ bool oracle)
{
- if (sel->braces && l && l->lock.defined_lock)
+ SELECT_LEX *sel2= sel;
+ if (sel->master_unit() && sel->master_unit()->first_select()->next_select())
{
- my_error(ER_WRONG_USAGE, MYF(0), "lock options",
- "SELECT in brackets");
- return NULL;
+ sel2= wrap_unit_into_derived(sel->master_unit());
+ if (!sel2)
+ return NULL;
}
- if (!(sel= parsed_select(sel, l)))
- return NULL;
+ SELECT_LEX *sel1= unit->first_select();
+ if (!sel1->next_select())
+ unit= parsed_select_expr_start(sel1, sel2, unit_type, distinct);
+ else
+ unit= parsed_select_expr_cont(unit, sel2, unit_type, distinct, oracle);
+ return unit;
+}
- SELECT_LEX_UNIT *res= create_unit(sel);
- if (res && sel->tvc && sel->order_list.elements)
+
+/**
+ Add query primary to a parenthesized query primary
+ pruducing a new query expression body
+*/
+
+SELECT_LEX_UNIT *
+LEX::add_primary_to_query_expression_body_ext_parens(
+ SELECT_LEX_UNIT *unit,
+ SELECT_LEX *sel,
+ enum sub_select_type unit_type,
+ bool distinct)
+{
+ SELECT_LEX *sel1= unit->first_select();
+ if (unit->first_select()->next_select())
{
- if (res->add_fake_select_lex(thd))
+ sel1= wrap_unit_into_derived(unit);
+ if (!sel1)
+ return NULL;
+ if (!create_unit(sel1))
return NULL;
- SELECT_LEX *fake= res->fake_select_lex;
- fake->order_list= sel->order_list;
- fake->explicit_limit= sel->explicit_limit;
- fake->select_limit= sel->select_limit;
- fake->offset_limit= sel->offset_limit;
}
- return res;
+ SELECT_LEX *sel2= sel;
+ if (sel->master_unit() && sel->master_unit()->first_select()->next_select())
+ {
+ sel2= wrap_unit_into_derived(sel->master_unit());
+ if (!sel2)
+ return NULL;
+ }
+ unit= parsed_select_expr_start(sel1, sel2, unit_type, distinct);
+ return unit;
}
+
/**
- Process parsed unit in body
+ Process multi-operand query expression body
*/
-bool LEX::parsed_body_unit(SELECT_LEX_UNIT *unit)
+bool LEX::parsed_multi_operand_query_expression_body(SELECT_LEX_UNIT *unit)
{
SELECT_LEX *first_in_nest=
unit->pre_last_parse->next_select()->first_nested;
@@ -9298,27 +9225,60 @@ bool LEX::parsed_body_unit(SELECT_LEX_UNIT *unit)
return true;
unit->fix_distinct();
}
- push_select(unit->fake_select_lex);
return false;
}
+
/**
- Process parsed tail of unit in body
+ Add non-empty tail to a query expression body
+*/
- TODO: make processing for double tail case
+SELECT_LEX_UNIT *LEX::add_tail_to_query_expression_body(SELECT_LEX_UNIT *unit,
+ Lex_order_limit_lock *l)
+{
+ DBUG_ASSERT(l != NULL);
+ pop_select();
+ SELECT_LEX *sel= unit->first_select()->next_select() ? unit->fake_select_lex :
+ unit->first_select();
+ l->set_to(sel);
+ return unit;
+}
+
+
+/**
+ Add non-empty tail to a parenthesized query primary
*/
-SELECT_LEX_UNIT *LEX::parsed_body_unit_tail(SELECT_LEX_UNIT *unit,
- Lex_order_limit_lock * l)
+SELECT_LEX_UNIT *
+LEX::add_tail_to_query_expression_body_ext_parens(SELECT_LEX_UNIT *unit,
+ Lex_order_limit_lock *l)
{
+ SELECT_LEX *sel= unit->first_select()->next_select() ? unit->fake_select_lex :
+ unit->first_select();
+
+ DBUG_ASSERT(l != NULL);
+
pop_select();
- if (l)
+ if (sel->is_set_query_expr_tail)
{
- (l)->set_to(unit->fake_select_lex);
+ if (!l->order_list && !sel->explicit_limit)
+ l->order_list= &sel->order_list;
+ else
+ {
+ if (!unit)
+ return NULL;
+ sel= wrap_unit_into_derived(unit);
+ if (!sel)
+ return NULL;
+ if (!create_unit(sel))
+ return NULL;
+ }
}
- return unit;
+ l->set_to(sel);
+ return sel->master_unit();
}
+
/**
Process subselect parsing
*/
@@ -9345,7 +9305,6 @@ SELECT_LEX *LEX::parsed_subselect(SELECT_LEX_UNIT *unit)
}
-
/**
Process INSERT-like select
*/
@@ -9400,40 +9359,8 @@ SELECT_LEX *LEX::parsed_TVC_end()
}
-TABLE_LIST *LEX::parsed_derived_select(SELECT_LEX *sel, int for_system_time,
- LEX_CSTRING *alias)
-{
- TABLE_LIST *res;
- derived_tables|= DERIVED_SUBQUERY;
- sel->set_linkage(DERIVED_TABLE_TYPE);
- sel->braces= FALSE;
- // Add the subtree of subquery to the current SELECT_LEX
- SELECT_LEX *curr_sel= select_stack_head();
- DBUG_ASSERT(current_select == curr_sel);
- SELECT_LEX_UNIT *unit= sel->master_unit();
- if (!unit)
- {
- unit= create_unit(sel);
- if (!unit)
- return NULL;
- }
- curr_sel->register_unit(unit, &curr_sel->context);
- curr_sel->add_statistics(unit);
-
- Table_ident *ti= new (thd->mem_root) Table_ident(unit);
- if (ti == NULL)
- return NULL;
- if (!(res= curr_sel->add_table_to_list(thd, ti, alias, 0,
- TL_READ, MDL_SHARED_READ)))
- return NULL;
- if (for_system_time)
- {
- res->vers_conditions= vers_conditions;
- }
- return res;
-}
-TABLE_LIST *LEX::parsed_derived_unit(SELECT_LEX_UNIT *unit,
+TABLE_LIST *LEX::parsed_derived_table(SELECT_LEX_UNIT *unit,
int for_system_time,
LEX_CSTRING *alias)
{
@@ -9444,8 +9371,6 @@ TABLE_LIST *LEX::parsed_derived_unit(SELECT_LEX_UNIT *unit,
// Add the subtree of subquery to the current SELECT_LEX
SELECT_LEX *curr_sel= select_stack_head();
DBUG_ASSERT(current_select == curr_sel);
- curr_sel->register_unit(unit, &curr_sel->context);
- curr_sel->add_statistics(unit);
Table_ident *ti= new (thd->mem_root) Table_ident(unit);
if (ti == NULL)
@@ -9463,7 +9388,8 @@ TABLE_LIST *LEX::parsed_derived_unit(SELECT_LEX_UNIT *unit,
bool LEX::parsed_create_view(SELECT_LEX_UNIT *unit, int check)
{
SQL_I_List<TABLE_LIST> *save= &first_select_lex()->table_list;
- set_main_unit(unit);
+ if (set_main_unit(unit))
+ return true;
if (check_main_unit_semantics())
return true;
first_select_lex()->table_list.push_front(save);
@@ -9486,7 +9412,8 @@ bool LEX::select_finalize(st_select_lex_unit *expr)
sql_command= SQLCOM_SELECT;
selects_allow_into= TRUE;
selects_allow_procedure= TRUE;
- set_main_unit(expr);
+ if (set_main_unit(expr))
+ return true;
return check_main_unit_semantics();
}
@@ -9497,6 +9424,7 @@ bool LEX::select_finalize(st_select_lex_unit *expr, Lex_select_lock l)
select_finalize(expr);
}
+
/*
"IN" and "EXISTS" subselect can appear in two statement types:
@@ -9529,7 +9457,6 @@ void LEX::relink_hack(st_select_lex *select_lex)
}
-
bool SELECT_LEX_UNIT::set_lock_to_the_last_select(Lex_select_lock l)
{
if (l.defined_lock)