From 17589989eec9cf4e9f7084505710a42929efe115 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Tue, 17 Jan 2017 13:09:04 +0100 Subject: [PATCH] MDEV-10972: Insert from select / view / union -- repeatable crash in 10.1, 10.2 Linux/Mac/Windows save thd->select_number between parsing and executions (in case it was not complete executed due to errors (for example epsent table)) --- mysql-test/r/sp.result | 28 ++++++++++++++++++++++++++++ mysql-test/t/sp.test | 31 +++++++++++++++++++++++++++++++ sql/sp.cc | 1 + sql/sp_head.cc | 20 +++++++++++++++++++- sql/sp_head.h | 3 +++ 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index d9b5dfd5a1f..c6867d46489 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -8079,4 +8079,32 @@ CALL sp1(); CALL sp1(); drop user 'foo'@'%'; drop procedure sp1; +# +# MDEV-10972: Insert from select / view / union -- +# repeatable crash in 10.1, 10.2 Linux/Mac/Windows +# +create table t (id int auto_increment primary key); +insert into t values (9494),(9495),(9496),(9497),(9498),(9499),(9500),(9501),(9502),(9503); +create VIEW v AS +select id from t +union +select id from t +; +drop procedure if exists p; +Warnings: +Note 1305 PROCEDURE test.p does not exist +create procedure p() +insert into tmp_t select t.id from ( +select id from v +union +select id from v +) sq +inner join t on (sq.id = t.id); +CALL p(); +ERROR 42S02: Table 'test.tmp_t' doesn't exist +create table tmp_t (id int null); +CALL p(); +drop procedure p; +drop view v; +drop table t, tmp_t; #End of 10.1 tests diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 6eba2522089..99020eb951f 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -9556,5 +9556,36 @@ CALL sp1(); drop user 'foo'@'%'; drop procedure sp1; +--echo # +--echo # MDEV-10972: Insert from select / view / union -- +--echo # repeatable crash in 10.1, 10.2 Linux/Mac/Windows +--echo # + +create table t (id int auto_increment primary key); +insert into t values (9494),(9495),(9496),(9497),(9498),(9499),(9500),(9501),(9502),(9503); + +create VIEW v AS +select id from t +union +select id from t +; + +drop procedure if exists p; +create procedure p() +insert into tmp_t select t.id from ( + select id from v + union + select id from v +) sq +inner join t on (sq.id = t.id); + +--error ER_NO_SUCH_TABLE +CALL p(); +create table tmp_t (id int null); +CALL p(); + +drop procedure p; +drop view v; +drop table t, tmp_t; --echo #End of 10.1 tests diff --git a/sql/sp.cc b/sql/sp.cc index 2e268e483e7..5a64c28865e 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -760,6 +760,7 @@ static sp_head *sp_compile(THD *thd, String *defstr, ulonglong sql_mode, else { sp= thd->lex->sphead; + sp->set_select_number(thd->select_number); } thd->pop_internal_handler(); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index bf25d45ffaf..ae274ee8714 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -598,7 +598,7 @@ sp_head::sp_head() m_flags(0), m_sp_cache_version(0), m_creation_ctx(0), - unsafe_flags(0), + unsafe_flags(0), m_select_number(1), m_recursion_level(0), m_next_cached_sp(0), m_cont_level(0) @@ -2100,8 +2100,26 @@ sp_head::execute_procedure(THD *thd, List *args) if (!err_status) { + /* + Normally the counter is not reset between parsing and first execution, + but it is possible in case of error to have parsing on one CALL and + first execution (where VIEW will be parsed and added). So we store the + counter after parsing and restore it before execution just to avoid + repeating SELECT numbers. + */ + thd->select_number= m_select_number; + err_status= execute(thd, TRUE); DBUG_PRINT("info", ("execute returned %d", (int) err_status)); + /* + This execution of the SP was aborted with an error (e.g. "Table not + found"). However it might still have consumed some numbers from the + thd->select_number counter. The next sp->exec() call must not use the + consumed numbers, so we remember the first free number (We know that + nobody will use it as this execution has stopped with an error). + */ + if (err_status) + set_select_number(thd->select_number); } if (save_log_general) diff --git a/sql/sp_head.h b/sql/sp_head.h index 604190079cb..5d3697daa16 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -232,6 +232,7 @@ private: */ uint32 unsafe_flags; + uint m_select_number; public: inline Stored_program_creation_ctx *get_creation_ctx() { @@ -521,6 +522,8 @@ public: sp_pcontext *get_parse_context() { return m_pcont; } + void set_select_number(uint num) { m_select_number= num; } + private: MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root