Commit 0de565a5 authored by Igor Babaev's avatar Igor Babaev

Fixed mdev-14852 Fails to reopen temp table within standard CTE

If the specification of a CTE contains a reference to a temporary table
then THD::open_temporary_table() must be called for this reference for
any occurrence of the CTE in the query. By mistake this was done only
for the first occurrences of CTEs.
The patch fixes this problem in With_element::clone_parsed_spec().
It also moves there the call of check_dependencies_in_with_clauses()
to its proper place before the call of check_table_access().
Additionally the patch optimizes the number of calls of the
function check_dependencies_in_with_clauses().
parent 287d1053
......@@ -1265,3 +1265,33 @@ a
4
deallocate prepare stmt;
drop table t1;
#
# MDEV-14852: CTE using temporary table in query
# with two references to the CTE
#
create temporary table t1 (i int);
insert into t1 values (5),(4),(1),(2),(3);
with
c1 as (select i from t1),
c2 as (select i from c1 where c1.i=2)
select i from c1 where i > 3 union select i from c2;
i
5
4
2
drop table t1;
create table t1 (term char(10));
create temporary table t2 (term char(10));
insert into t1 values ('TERM01'),('TERM02'),('TERM03');
insert into t2 values ('TERM02'),('TERM03'),('TERM04');
with c1 as (select * from t1), c2 as (select * from t2)
(select * from c1 left outer join c2 on c1.term = c2.term)
union all
(select * from c1 right outer join c2 on c1.term = c2.term
where c1.term is null);
term term
TERM02 TERM02
TERM03 TERM03
TERM01 NULL
NULL TERM04
drop table t1,t2;
......@@ -853,3 +853,32 @@ execute stmt;
deallocate prepare stmt;
drop table t1;
--echo #
--echo # MDEV-14852: CTE using temporary table in query
--echo # with two references to the CTE
--echo #
create temporary table t1 (i int);
insert into t1 values (5),(4),(1),(2),(3);
with
c1 as (select i from t1),
c2 as (select i from c1 where c1.i=2)
select i from c1 where i > 3 union select i from c2;
drop table t1;
create table t1 (term char(10));
create temporary table t2 (term char(10));
insert into t1 values ('TERM01'),('TERM02'),('TERM03');
insert into t2 values ('TERM02'),('TERM03'),('TERM04');
with c1 as (select * from t1), c2 as (select * from t2)
(select * from c1 left outer join c2 on c1.term = c2.term)
union all
(select * from c1 right outer join c2 on c1.term = c2.term
where c1.term is null);
drop table t1,t2;
......@@ -817,12 +817,19 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
parse_status= parse_sql(thd, &parser_state, 0);
if (parse_status)
goto err;
if (check_dependencies_in_with_clauses(lex->with_clauses_list))
goto err;
spec_tables= lex->query_tables;
spec_tables_tail= 0;
for (TABLE_LIST *tbl= spec_tables;
tbl;
tbl= tbl->next_global)
{
if (!tbl->derived && !tbl->schema_table &&
thd->open_temporary_table(tbl))
goto err;
spec_tables_tail= tbl;
}
if (check_table_access(thd, SELECT_ACL, spec_tables, FALSE, UINT_MAX, FALSE))
......
......@@ -2990,6 +2990,9 @@ mysql_execute_command(THD *thd)
thd->get_stmt_da()->opt_clear_warning_info(thd->query_id);
}
if (check_dependencies_in_with_clauses(thd->lex->with_clauses_list))
DBUG_RETURN(1);
#ifdef HAVE_REPLICATION
if (unlikely(thd->slave_thread))
{
......@@ -3446,14 +3449,6 @@ mysql_execute_command(THD *thd)
ulong privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL :
SELECT_ACL;
/*
The same function must be called for DML commands
when CTEs are supported in DML statements
*/
res= check_dependencies_in_with_clauses(thd->lex->with_clauses_list);
if (res)
break;
if (all_tables)
res= check_table_access(thd,
privileges_requested,
......@@ -3879,8 +3874,7 @@ mysql_execute_command(THD *thd)
/* Copy temporarily the statement flags to thd for lock_table_names() */
uint save_thd_create_info_options= thd->lex->create_info.options;
thd->lex->create_info.options|= create_info.options;
if (!(res= check_dependencies_in_with_clauses(lex->with_clauses_list)))
res= open_and_lock_tables(thd, create_info, lex->query_tables, TRUE, 0);
res= open_and_lock_tables(thd, create_info, lex->query_tables, TRUE, 0);
thd->lex->create_info.options= save_thd_create_info_options;
if (res)
{
......@@ -4493,8 +4487,7 @@ mysql_execute_command(THD *thd)
unit->set_limit(select_lex);
if (!(res= check_dependencies_in_with_clauses(lex->with_clauses_list)) &&
!(res=open_and_lock_tables(thd, all_tables, TRUE, 0)))
if (!(res=open_and_lock_tables(thd, all_tables, TRUE, 0)))
{
MYSQL_INSERT_SELECT_START(thd->query());
/*
......@@ -4821,9 +4814,6 @@ mysql_execute_command(THD *thd)
{
List<set_var_base> *lex_var_list= &lex->var_list;
if (check_dependencies_in_with_clauses(thd->lex->with_clauses_list))
goto error;
if ((check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)
|| open_and_lock_tables(thd, all_tables, TRUE, 0)))
goto error;
......@@ -6376,8 +6366,6 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
new (thd->mem_root) Item_int(thd,
(ulonglong) thd->variables.select_limit);
}
if (check_dependencies_in_with_clauses(lex->with_clauses_list))
return 1;
if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0)))
{
......
......@@ -1573,8 +1573,6 @@ static int mysql_test_select(Prepared_statement *stmt,
lex->select_lex.context.resolve_in_select_list= TRUE;
ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
if (check_dependencies_in_with_clauses(lex->with_clauses_list))
goto error;
if (tables)
{
if (check_table_access(thd, privilege, tables, FALSE, UINT_MAX, FALSE))
......@@ -1841,9 +1839,6 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
if (create_table_precheck(thd, tables, create_table))
DBUG_RETURN(TRUE);
if (check_dependencies_in_with_clauses(lex->with_clauses_list))
DBUG_RETURN(TRUE);
if (select_lex->item_list.elements)
{
/* Base table and temporary table are not in the same name space. */
......@@ -2234,9 +2229,6 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
if (insert_precheck(stmt->thd, tables))
return 1;
if (check_dependencies_in_with_clauses(lex->with_clauses_list))
return 1;
/* store it, because mysql_insert_select_prepare_tester change it */
first_local_table= lex->select_lex.table_list.first;
DBUG_ASSERT(first_local_table != 0);
......@@ -2339,6 +2331,9 @@ static bool check_prepared_statement(Prepared_statement *stmt)
if (tables)
thd->get_stmt_da()->opt_clear_warning_info(thd->query_id);
if (check_dependencies_in_with_clauses(thd->lex->with_clauses_list))
goto error;
if (sql_command_flags[sql_command] & CF_HA_CLOSE)
mysql_ha_rm_tables(thd, tables);
......
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