MDEV-7040: Crash in field_conv, memcpy_field_possible, part#2
The problem was with Materialized_cursor and temporary table it uses. Temorary table's fields had Field::orig_table pointing to the tables that were used in the query that produced data for the cursor. When "FETCH INTO sp_var" statement is executed, those original tables were already closed. However, copying from Materialized_cursor's table into SP variable may cause field_conv() to be invoked which calls field->type() which may access field->orig_table (for certain field types). Fixed by setting Materialized_cursor->table->field[i]->orig_table to point to Materialized_cursor->table. (this is how it is done for regular base tables)
This commit is contained in:
parent
cb925491d4
commit
b74795b00c
@ -7858,3 +7858,56 @@ v1
|
|||||||
DROP PROCEDURE p1;
|
DROP PROCEDURE p1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
# End of 5.5 test
|
# End of 5.5 test
|
||||||
|
#
|
||||||
|
# MDEV-7040: Crash in field_conv, memcpy_field_possible, part#2
|
||||||
|
#
|
||||||
|
create table t1 (
|
||||||
|
col1 bigint(20),
|
||||||
|
col2 char(1),
|
||||||
|
col3 char(2)
|
||||||
|
);
|
||||||
|
insert into t1 values (1,'a','a'), (2,'b','b');
|
||||||
|
create table t2 as select * from t1;
|
||||||
|
create table t3 as select * from t1;
|
||||||
|
create table t4 as select * from t1;
|
||||||
|
create table t5 as select * from t1;
|
||||||
|
create table t6 as select * from t1;
|
||||||
|
flush tables;
|
||||||
|
CREATE PROCEDURE p1()
|
||||||
|
begin
|
||||||
|
DECLARE _var1 bigint(20) UNSIGNED;
|
||||||
|
DECLARE _var2 CHAR(1) DEFAULT NULL;
|
||||||
|
DECLARE _var3 CHAR(1) DEFAULT NULL;
|
||||||
|
DECLARE _done BOOLEAN DEFAULT 0;
|
||||||
|
declare cur1 cursor for
|
||||||
|
select col1, col2, col3
|
||||||
|
from t1
|
||||||
|
where
|
||||||
|
col1 in (select t2.col1 from t2 where t2.col2=t1.col2) or
|
||||||
|
col2 in (select t3.col3 from t3 where t3.col3=t1.col2) ;
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET _done = 1;
|
||||||
|
OPEN cur1;
|
||||||
|
set _var1 = (select _var1 from t4 limit 1);
|
||||||
|
set _var1 = (select _var1 from t5 limit 1);
|
||||||
|
set _var1 = (select _var1 from t6 limit 1);
|
||||||
|
label1:
|
||||||
|
LOOP
|
||||||
|
SET _done = 0;
|
||||||
|
FETCH cur1 INTO _var1, _var2, _var3;
|
||||||
|
IF _done THEN
|
||||||
|
LEAVE label1;
|
||||||
|
END IF;
|
||||||
|
END LOOP label1;
|
||||||
|
CLOSE cur1;
|
||||||
|
end|
|
||||||
|
set @tmp_toc= @@table_open_cache;
|
||||||
|
set @tmp_tdc= @@table_definition_cache;
|
||||||
|
set global table_open_cache=1;
|
||||||
|
set global table_definition_cache=1;
|
||||||
|
Warnings:
|
||||||
|
Warning 1292 Truncated incorrect table_definition_cache value: '1'
|
||||||
|
call p1();
|
||||||
|
set global table_open_cache= @tmp_toc;
|
||||||
|
set global table_definition_cache= @tmp_tdc;
|
||||||
|
drop procedure p1;
|
||||||
|
drop table t1,t2,t3,t4,t5,t6;
|
||||||
|
@ -9303,3 +9303,71 @@ DROP PROCEDURE p1;
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
--echo # End of 5.5 test
|
--echo # End of 5.5 test
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-7040: Crash in field_conv, memcpy_field_possible, part#2
|
||||||
|
--echo #
|
||||||
|
create table t1 (
|
||||||
|
col1 bigint(20),
|
||||||
|
col2 char(1),
|
||||||
|
col3 char(2)
|
||||||
|
);
|
||||||
|
insert into t1 values (1,'a','a'), (2,'b','b');
|
||||||
|
|
||||||
|
create table t2 as select * from t1;
|
||||||
|
create table t3 as select * from t1;
|
||||||
|
create table t4 as select * from t1;
|
||||||
|
create table t5 as select * from t1;
|
||||||
|
create table t6 as select * from t1;
|
||||||
|
|
||||||
|
flush tables;
|
||||||
|
|
||||||
|
DELIMITER |;
|
||||||
|
|
||||||
|
CREATE PROCEDURE p1()
|
||||||
|
begin
|
||||||
|
DECLARE _var1 bigint(20) UNSIGNED;
|
||||||
|
DECLARE _var2 CHAR(1) DEFAULT NULL;
|
||||||
|
DECLARE _var3 CHAR(1) DEFAULT NULL;
|
||||||
|
|
||||||
|
DECLARE _done BOOLEAN DEFAULT 0;
|
||||||
|
|
||||||
|
declare cur1 cursor for
|
||||||
|
select col1, col2, col3
|
||||||
|
from t1
|
||||||
|
where
|
||||||
|
col1 in (select t2.col1 from t2 where t2.col2=t1.col2) or
|
||||||
|
col2 in (select t3.col3 from t3 where t3.col3=t1.col2) ;
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET _done = 1;
|
||||||
|
|
||||||
|
OPEN cur1;
|
||||||
|
|
||||||
|
set _var1 = (select _var1 from t4 limit 1);
|
||||||
|
set _var1 = (select _var1 from t5 limit 1);
|
||||||
|
set _var1 = (select _var1 from t6 limit 1);
|
||||||
|
label1:
|
||||||
|
LOOP
|
||||||
|
SET _done = 0;
|
||||||
|
FETCH cur1 INTO _var1, _var2, _var3;
|
||||||
|
IF _done THEN
|
||||||
|
LEAVE label1;
|
||||||
|
END IF;
|
||||||
|
END LOOP label1;
|
||||||
|
CLOSE cur1;
|
||||||
|
end|
|
||||||
|
DELIMITER ;|
|
||||||
|
|
||||||
|
set @tmp_toc= @@table_open_cache;
|
||||||
|
set @tmp_tdc= @@table_definition_cache;
|
||||||
|
|
||||||
|
set global table_open_cache=1;
|
||||||
|
set global table_definition_cache=1;
|
||||||
|
call p1();
|
||||||
|
|
||||||
|
set global table_open_cache= @tmp_toc;
|
||||||
|
set global table_definition_cache= @tmp_tdc;
|
||||||
|
drop procedure p1;
|
||||||
|
|
||||||
|
drop table t1,t2,t3,t4,t5,t6;
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ public:
|
|||||||
virtual void fetch(ulong num_rows);
|
virtual void fetch(ulong num_rows);
|
||||||
virtual void close();
|
virtual void close();
|
||||||
virtual ~Materialized_cursor();
|
virtual ~Materialized_cursor();
|
||||||
|
|
||||||
|
void on_table_fill_finished();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -74,6 +76,18 @@ public:
|
|||||||
Select_materialize(select_result *result_arg)
|
Select_materialize(select_result *result_arg)
|
||||||
:result(result_arg), materialized_cursor(0) {}
|
:result(result_arg), materialized_cursor(0) {}
|
||||||
virtual bool send_result_set_metadata(List<Item> &list, uint flags);
|
virtual bool send_result_set_metadata(List<Item> &list, uint flags);
|
||||||
|
bool send_eof()
|
||||||
|
{
|
||||||
|
if (materialized_cursor)
|
||||||
|
materialized_cursor->on_table_fill_finished();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void abort_result_set()
|
||||||
|
{
|
||||||
|
if (materialized_cursor)
|
||||||
|
materialized_cursor->on_table_fill_finished();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -388,6 +402,29 @@ Materialized_cursor::~Materialized_cursor()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
@brief
|
||||||
|
Perform actions that are to be done when cursor materialization has
|
||||||
|
finished.
|
||||||
|
|
||||||
|
@detail
|
||||||
|
This function is called when "OPEN $cursor" has finished filling the
|
||||||
|
temporary table with rows that the cursor will return.
|
||||||
|
|
||||||
|
Temporary table has table->field->orig_table pointing at the tables
|
||||||
|
that are used in the cursor definition query. Pointers to these tables
|
||||||
|
will not be valid after the query finishes. So, we do what is done for
|
||||||
|
regular tables: have orig_table point at the table that the fields belong
|
||||||
|
to.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Materialized_cursor::on_table_fill_finished()
|
||||||
|
{
|
||||||
|
uint fields= table->s->fields;
|
||||||
|
for (uint i= 0; i < fields; i++)
|
||||||
|
table->field[i]->orig_table= table->field[i]->table;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
Select_materialize
|
Select_materialize
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user