Commit 09aa5d3f authored by Igor Babaev's avatar Igor Babaev

MDEV-17894 Assertion `(thd->lex)->current_select' failed in MYSQLparse(),

           query with VALUES()

A table value constructor can be used in all contexts where a select
can be used. In particular an ORDER BY clause or a LIMIT clause or both
of them can be attached to a table value constructor to produce a new
query. Unfortunately execution of such queries was not supported.
This patch fixes the problem.
parent 9d805004
This diff is collapsed.
......@@ -1123,3 +1123,196 @@ PREPARE stmt FROM "SELECT * FROM (VALUES(1 + 1,2,'abc')) t";
EXECUTE stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
--echo #
--echo # MDEV-17894: tvc with ORDER BY ... LIMIT
--echo #
let $q=
values (5), (7), (1), (3), (4) limit 2;
eval $q;
eval explain extended $q;
let $q=
values (5), (7), (1), (3), (4) limit 2 offset 1;
eval $q;
eval explain extended $q;
let $q=
values (5), (7), (1), (3), (4) order by 1 limit 2;
eval $q;
eval explain extended $q;
let $q=
values (5), (7), (1), (3), (4) order by 1 limit 2 offset 1;
eval $q;
eval explain extended $q;
let $q=
values (5), (7), (1), (3), (4) order by 1;
eval $q;
eval explain extended $q;
let $q=
values (5,90), (7,20), (1,70), (3,50), (4,10) order by 2;
eval $q;
eval explain extended $q;
let $q=
select 2 union (values (5), (7), (1), (3), (4) limit 2);
eval $q;
eval explain extended $q;
let $q=
select 2 union (values (5), (7), (1), (3), (4) limit 2 offset 1);
eval $q;
eval explain extended $q;
let $q=
select 2 union (values (5), (7), (1), (3), (4) order by 1 limit 2);
eval $q;
eval explain extended $q;
let $q=
select 2 union (values (5), (7), (1), (3), (4) order by 1 limit 2 offset 1);
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) limit 2) union select 2;
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) limit 2 offset 1) union select 2;
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) order by 1 limit 2) union select 2;
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) order by 1 limit 2 offset 1) union select 2;
eval $q;
eval explain extended $q;
let $q=
select 3 union all (values (5), (7), (1), (3), (4) limit 2 offset 3);
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) limit 2 offset 3) union all select 3;
eval $q;
eval explain extended $q;
let $q=
select 3 union all (values (5), (7), (1), (3), (4) order by 1 limit 2);
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) order by 1 limit 2) union all select 3;
eval $q;
eval explain extended $q;
let $q=
( values (5), (7), (1), (3), (4) limit 2 offset 1 )
union
( values (5), (7), (1), (3), (4) order by 1 limit 2 );
eval $q;
eval explain extended $q;
let $q=
( values (5), (7), (1), (3), (4) limit 2 offset 1 )
union all
( values (5), (7), (1), (3), (4) order by 1 limit 2 );
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) limit 2 offset 3) union all select 3 order by 1;
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) order by 1 limit 3 offset 1) union all select 3 order by 1;
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) order by 1 limit 3 offset 1) union all select 3
order by 1 limit 2 offset 1;
eval $q;
eval explain extended $q;
--error ER_BAD_FIELD_ERROR
values (5,90), (7,20), (1,70), (3,50), (4,10) order by 3;
prepare stmt from "
select 2 union (values (5), (7), (1), (3), (4) limit 2)
";
execute stmt;
execute stmt;
deallocate prepare stmt;
prepare stmt from "
select 2 union (values (5), (7), (1), (3), (4) order by 1 limit 2)
";
execute stmt;
execute stmt;
deallocate prepare stmt;
prepare stmt from "
select 3 union all (values (5), (7), (1), (3), (4) limit 2)
";
execute stmt;
execute stmt;
deallocate prepare stmt;
prepare stmt from "
select 3 union all (values (5), (7), (1), (3), (4) order by 1 limit 2)
";
execute stmt;
execute stmt;
deallocate prepare stmt;
prepare stmt from "
( values (5), (7), (1), (3), (4) limit 2 offset 1 )
union
( values (5), (7), (1), (3), (4) order by 1 limit 2 );
";
execute stmt;
execute stmt;
deallocate prepare stmt;
--error ER_BAD_FIELD_ERROR
prepare stmt from "
values (5,90), (7,20), (1,70), (3,50), (4,10) order by 3;
";
create view v1 as values (5), (7), (1), (3), (4) order by 1 limit 2;
show create view v1;
select * from v1;
drop view v1;
create view v1 as
( values (5), (7), (1), (3), (4) limit 2 offset 1 )
union
( values (5), (7), (1), (3), (4) order by 1 limit 2 );
show create view v1;
select * from v1;
drop view v1;
--error ER_BAD_FIELD_ERROR
create view v1 as values (5,90), (7,20), (1,70), (3,50), (4,10) order by 3;
--error ER_BAD_FIELD_ERROR
create view v1 as
( values (5), (7), (1), (3), (4) limit 2 offset 1 )
union
( values (5), (7), (1), (3), (4) order by 2 limit 2 );
......@@ -1125,3 +1125,154 @@ DROP VIEW v1;
VALUES(1 + 1,2,'abc');
SELECT * FROM (VALUES(1 + 1,2,'abc')) t;
--echo #
--echo # MDEV-17894: tvc with ORDER BY ... LIMIT
--echo #
let $q=
values (5), (7), (1), (3), (4) limit 2;
eval $q;
eval explain extended $q;
let $q=
values (5), (7), (1), (3), (4) limit 2 offset 1;
eval $q;
eval explain extended $q;
let $q=
values (5), (7), (1), (3), (4) order by 1 limit 2;
eval $q;
eval explain extended $q;
let $q=
values (5), (7), (1), (3), (4) order by 1 limit 2 offset 1;
eval $q;
eval explain extended $q;
let $q=
values (5), (7), (1), (3), (4) order by 1;
eval $q;
eval explain extended $q;
let $q=
values (5,90), (7,20), (1,70), (3,50), (4,10) order by 2;
eval $q;
eval explain extended $q;
let $q=
select 2 union (values (5), (7), (1), (3), (4) limit 2);
eval $q;
eval explain extended $q;
let $q=
select 2 union (values (5), (7), (1), (3), (4) limit 2 offset 1);
eval $q;
eval explain extended $q;
let $q=
select 2 union (values (5), (7), (1), (3), (4) order by 1 limit 2);
eval $q;
eval explain extended $q;
let $q=
select 2 union (values (5), (7), (1), (3), (4) order by 1 limit 2 offset 1);
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) limit 2) union select 2;
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) limit 2 offset 1) union select 2;
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) order by 1 limit 2) union select 2;
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) order by 1 limit 2 offset 1) union select 2;
eval $q;
eval explain extended $q;
let $q=
select 3 union all (values (5), (7), (1), (3), (4) limit 2 offset 3);
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) limit 2 offset 3) union all select 3;
eval $q;
eval explain extended $q;
let $q=
select 3 union all (values (5), (7), (1), (3), (4) order by 1 limit 2);
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) order by 1 limit 2) union all select 3;
eval $q;
eval explain extended $q;
let $q=
( values (5), (7), (1), (3), (4) limit 2 offset 1 )
union
( values (5), (7), (1), (3), (4) order by 1 limit 2 );
eval $q;
eval explain extended $q;
let $q=
( values (5), (7), (1), (3), (4) limit 2 offset 1 )
union all
( values (5), (7), (1), (3), (4) order by 1 limit 2 );
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) limit 2 offset 3) union all select 3 order by 1;
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) order by 1 limit 3 offset 1) union all select 3 order by 1;
eval $q;
eval explain extended $q;
let $q=
(values (5), (7), (1), (3), (4) order by 1 limit 3 offset 1) union all select 3
order by 1 limit 2 offset 1;
eval $q;
eval explain extended $q;
--error ER_BAD_FIELD_ERROR
values (5,90), (7,20), (1,70), (3,50), (4,10) order by 3;
create view v1 as values (5), (7), (1), (3), (4) order by 1 limit 2;
show create view v1;
select * from v1;
drop view v1;
create view v1 as
( values (5), (7), (1), (3), (4) limit 2 offset 1 )
union
( values (5), (7), (1), (3), (4) order by 1 limit 2 );
show create view v1;
select * from v1;
drop view v1;
--error ER_BAD_FIELD_ERROR
create view v1 as values (5,90), (7,20), (1,70), (3,50), (4,10) order by 3;
--error ER_BAD_FIELD_ERROR
create view v1 as
( values (5), (7), (1), (3), (4) limit 2 offset 1 )
union
( values (5), (7), (1), (3), (4) order by 2 limit 2 );
......@@ -269,7 +269,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
{
if (sl->tvc)
{
wrap_tvc_in_derived_table(thd, sl);
wrap_tvc_into_select(thd, sl);
}
}
......
......@@ -267,7 +267,7 @@ class Item_subselect :public Item_result_field,
Item* build_clone(THD *thd) { return 0; }
Item* get_copy(THD *thd) { return 0; }
bool wrap_tvc_in_derived_table(THD *thd, st_select_lex *tvc_sl);
bool wrap_tvc_into_select(THD *thd, st_select_lex *tvc_sl);
friend class select_result_interceptor;
friend class Item_in_optimizer;
......
......@@ -2292,6 +2292,7 @@ void st_select_lex_unit::init_query()
with_element= 0;
columns_are_renamed= false;
intersect_mark= NULL;
with_wrapped_tvc= false;
}
void st_select_lex::init_query()
......@@ -3428,6 +3429,19 @@ bool st_select_lex_unit::union_needs_tmp_table()
{
if (with_element && with_element->is_recursive)
return true;
if (!with_wrapped_tvc)
{
for (st_select_lex *sl= first_select(); sl; sl=sl->next_select())
{
if (sl->tvc && sl->tvc->to_be_wrapped_as_with_tail())
{
with_wrapped_tvc= true;
break;
}
}
}
if (with_wrapped_tvc)
return true;
return union_distinct != NULL ||
global_parameters()->order_list.elements != 0 ||
thd->lex->sql_command == SQLCOM_INSERT_SELECT ||
......@@ -8238,6 +8252,8 @@ bool LEX::tvc_finalize()
current_select->options))))
return true;
many_values.empty();
if (!current_select->master_unit()->fake_select_lex)
current_select->master_unit()->add_fake_select_lex(thd);
return false;
}
......
......@@ -800,6 +800,12 @@ class st_select_lex_unit: public st_select_lex_node {
table for it
*/
Item_int *intersect_mark;
/**
TRUE if the unit contained TVC at the top level that has been wrapped
into SELECT:
VALUES (v1) ... (vn) => SELECT * FROM (VALUES (v1) ... (vn)) as tvc
*/
bool with_wrapped_tvc;
/**
Pointer to 'last' select, or pointer to select where we stored
global parameters for union.
......
This diff is collapsed.
......@@ -57,6 +57,8 @@ class table_value_constr : public Sql_alloc
select_result *tmp_result,
st_select_lex_unit *unit_arg);
bool to_be_wrapped_as_with_tail();
int save_explain_data_intern(THD *thd_arg,
Explain_query *output);
bool optimize(THD *thd_arg);
......@@ -64,4 +66,7 @@ class table_value_constr : public Sql_alloc
void print(THD *thd_arg, String *str, enum_query_type query_type);
};
st_select_lex *wrap_tvc_with_tail(THD *thd, st_select_lex *tvc_sl);
#endif /* SQL_TVC_INCLUDED */
......@@ -831,7 +831,8 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
bool is_union_select;
bool have_except= FALSE, have_intersect= FALSE;
bool instantiate_tmp_table= false;
bool single_tvc= !first_sl->next_select() && first_sl->tvc;
bool single_tvc= !first_sl->next_select() && first_sl->tvc &&
!fake_select_lex;
DBUG_ENTER("st_select_lex_unit::prepare");
DBUG_ASSERT(thd == current_thd);
......@@ -986,7 +987,23 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
{
if (sl->tvc)
{
if (sl->tvc->prepare(thd, sl, tmp_result, this))
if (sl->tvc->to_be_wrapped_as_with_tail() &&
!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW))
{
st_select_lex *wrapper_sl= wrap_tvc_with_tail(thd, sl);
if (!wrapper_sl)
goto err;
if (sl == first_sl)
first_sl= wrapper_sl;
sl= wrapper_sl;
if (prepare_join(thd, sl, tmp_result, additional_options,
is_union_select))
goto err;
}
else if (sl->tvc->prepare(thd, sl, tmp_result, this))
goto err;
}
else if (prepare_join(thd, sl, tmp_result, additional_options,
......
......@@ -9192,7 +9192,7 @@ select_paren:
{
Lex->current_select->set_braces(true);
}
table_value_constructor
table_value_constructor select_part3
{
DBUG_ASSERT(Lex->current_select->braces);
}
......@@ -9212,6 +9212,12 @@ select_paren:
| '(' select_paren ')'
;
select_parent_union_query_term_proper:
SELECT_SYM select_options_and_item_list select_part3_union_query_term
opt_select_lock_type
| table_value_constructor select_part3_union_query_term
;
select_paren_union_query_term:
{
/*
......@@ -9220,14 +9226,19 @@ select_paren_union_query_term:
*/
Lex->current_select->set_braces(true);
}
SELECT_SYM select_options_and_item_list select_part3_union_query_term
opt_select_lock_type
select_parent_union_query_term_proper
{
DBUG_ASSERT(Lex->current_select->braces);
}
| '(' select_paren_union_query_term ')'
;
select_parent_view_proper:
SELECT_SYM select_options_and_item_list select_part3_view
opt_select_lock_type
| table_value_constructor select_part3_view
;
select_paren_view:
{
/*
......@@ -9236,8 +9247,7 @@ select_paren_view:
*/
Lex->current_select->set_braces(true);
}
SELECT_SYM select_options_and_item_list select_part3_view
opt_select_lock_type
select_parent_view_proper
{
DBUG_ASSERT(Lex->current_select->braces);
}
......
......@@ -9129,7 +9129,7 @@ select_paren:
{
Lex->current_select->set_braces(true);
}
table_value_constructor
table_value_constructor select_part3
{
DBUG_ASSERT(Lex->current_select->braces);
}
......@@ -9149,6 +9149,12 @@ select_paren:
| '(' select_paren ')'
;
select_parent_union_query_term_proper:
SELECT_SYM select_options_and_item_list select_part3_union_query_term
opt_select_lock_type
| table_value_constructor select_part3_union_query_term
;
select_paren_union_query_term:
{
/*
......@@ -9157,14 +9163,19 @@ select_paren_union_query_term:
*/
Lex->current_select->set_braces(true);
}
SELECT_SYM select_options_and_item_list select_part3_union_query_term
opt_select_lock_type
select_parent_union_query_term_proper
{
DBUG_ASSERT(Lex->current_select->braces);
}
| '(' select_paren_union_query_term ')'
;
select_parent_view_proper:
SELECT_SYM select_options_and_item_list select_part3_view
opt_select_lock_type
| table_value_constructor select_part3_view
;
select_paren_view:
{
/*
......@@ -9173,8 +9184,7 @@ select_paren_view:
*/
Lex->current_select->set_braces(true);
}
SELECT_SYM select_options_and_item_list select_part3_view
opt_select_lock_type
select_parent_view_proper
{
DBUG_ASSERT(Lex->current_select->braces);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment