Commit b74795b0 authored by Sergei Petrunia's avatar Sergei Petrunia

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)
parent cb925491
......@@ -7858,3 +7858,56 @@ v1
DROP PROCEDURE p1;
DROP TABLE t1;
# 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;
--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 close();
virtual ~Materialized_cursor();
void on_table_fill_finished();
};
......@@ -74,6 +76,18 @@ public:
Select_materialize(select_result *result_arg)
:result(result_arg), materialized_cursor(0) {}
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
****************************************************************************/
......
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