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))
This commit is contained in:
Oleksandr Byelkin 2017-01-17 13:09:04 +01:00
parent be45f083e6
commit 17589989ee
5 changed files with 82 additions and 1 deletions

View file

@ -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

View file

@ -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

View file

@ -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();

View file

@ -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<Item> *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)

View file

@ -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