From a287bfa09ac45dba3241b8236abffda5ba48cadc Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 25 Apr 2017 19:34:39 -0700 Subject: [PATCH] Fixed the bug mdev-12558. In the current code temporary tables we identified and opened before other tables. CTE tables are identified in the same procedure as regular tables. When a temporary table and a CTE table have the same name T any reference to T that is in the scope of the CTE declaration must be associated with this CTE. Yet it was not done properly. When a reference to T was found in the scope of the declaration of CTE T a pointer to this CTE was set in the reference. No check that the reference had been already associated with a temporary table was done. As a result, if the temporary table T had been created then the reference to T was considered simultaneously as reference to the CTE named T and as a reference to the temporary table named T. This confused the code that were executed later and caused a crash of the server. Now when a table reference is associated with a CTE any previous association with a temporary table is dropped. This problem could be easily avoided if the temporary tables were not identified prematurely. as reference to CTE named T and --- mysql-test/r/cte_nonrecursive.result | 18 +++++++++++++++++- mysql-test/t/cte_nonrecursive.test | 19 +++++++++++++++++-- sql/sql_cte.cc | 11 +++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/cte_nonrecursive.result b/mysql-test/r/cte_nonrecursive.result index 207df07f083..50f99ec4bde 100644 --- a/mysql-test/r/cte_nonrecursive.result +++ b/mysql-test/r/cte_nonrecursive.result @@ -962,7 +962,7 @@ View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS with alias1 as (select 1 AS `one`), alias2 as (select 2 AS `two`)select `alias1`.`one` AS `one`,`alias2`.`two` AS `two` from (`alias1` join `alias2`) latin1 latin1_swedish_ci drop view v1; # -# MDEV-12440: the same CTE table is used in twice +# MDEV-12440: the same CTE table is used twice # create table t1 (a int, b varchar(32)); insert into t1 values @@ -984,3 +984,19 @@ select * from cte3; a b 4 dd drop table t1; +# +# MDEV-12558: CTE with the same name as temporary table +# +CREATE TABLE t ENGINE=MyISAM AS SELECT 1 AS i; +CREATE TEMPORARY TABLE cte ENGINE=MyISAM AS SELECT 2 AS f; +WITH cte AS ( SELECT i FROM t ) SELECT * FROM cte; +i +1 +WITH cte AS ( SELECT i FROM t GROUP BY i) SELECT * FROM cte; +i +1 +SELECT * FROM cte; +f +2 +DROP TABLE cte; +DROP TABLE t; diff --git a/mysql-test/t/cte_nonrecursive.test b/mysql-test/t/cte_nonrecursive.test index bcdc06afbad..0cc63104fa5 100644 --- a/mysql-test/t/cte_nonrecursive.test +++ b/mysql-test/t/cte_nonrecursive.test @@ -644,7 +644,7 @@ show create view v1; drop view v1; --echo # ---echo # MDEV-12440: the same CTE table is used in twice +--echo # MDEV-12440: the same CTE table is used twice --echo # create table t1 (a int, b varchar(32)); @@ -665,4 +665,19 @@ cte2 as (select * from cte1 where b > 'c'), cte3 as (select * from cte2 where a > 1 union select * from cte2 where a > 1) select * from cte3; -drop table t1; \ No newline at end of file +drop table t1; + +--echo # +--echo # MDEV-12558: CTE with the same name as temporary table +--echo # + +CREATE TABLE t ENGINE=MyISAM AS SELECT 1 AS i; +CREATE TEMPORARY TABLE cte ENGINE=MyISAM AS SELECT 2 AS f; + +WITH cte AS ( SELECT i FROM t ) SELECT * FROM cte; +WITH cte AS ( SELECT i FROM t GROUP BY i) SELECT * FROM cte; + +SELECT * FROM cte; + +DROP TABLE cte; +DROP TABLE t; diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index c9976baeabd..62b27d05e9b 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -968,6 +968,17 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem) { + if (table) + { + /* + This table was prematurely identified as a temporary table. + We correct it here, but it's not a nice solution in the case + when the temporary table with this name is not used anywhere + else in the query. + */ + thd->mark_tmp_table_as_free_for_reuse(table); + table= 0; + } with= with_elem; if (!with_elem->is_referenced() || with_elem->is_recursive) derived= with_elem->spec;