Commit 13cd4cf4 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-17278 CURSOR FOR LOOP - ERROR: unexpected end of stream, read 0 bytes (SERVER CRASH)

sp_instr_cursor_copy_struct::exec_core() created TYPELIBs on a wrong mem_root,
the one which is initialized in sp_head::execute(), this code:

  /* init per-instruction memroot */
  init_sql_alloc(&execute_mem_root, "per_instruction_memroot",
                 MEM_ROOT_BLOCK_SIZE, 0, MYF(0));

This memory root cleans up after every sp_instr_xxx executed, so later
sp_instr_cfetch::execute() tried to use already freed and trashed memory.

Changing sp_instr_cursor_copy_struct::exec_core() to call tmp.export_structure()
inside this block (not outside of it):
  thd->set_n_backup_active_arena(thd->spcont->callers_arena, &current_arena);
  ...
  thd->restore_active_arena(thd->spcont->callers_arena, &current_arena);

So now TYPELIBs created by sp_instr_cursor_copy_struct::exec_core() are
still available and valid when sp_instr_cfetch::execute() is called.
They are freed at the end of dispatch_command() corresponding to
the "CALL p1" statement.
parent 45769429
...@@ -713,3 +713,27 @@ END; ...@@ -713,3 +713,27 @@ END;
$$ $$
CALL p1; CALL p1;
DROP PROCEDURE p1; DROP PROCEDURE p1;
#
# MDEV-17278 CURSOR FOR LOOP - ERROR: unexpected end of stream, read 0 bytes (SERVER CRASH)
#
CREATE TABLE t1 (id2 int, id int, en1 enum('aaa','a','b','c'));
INSERT INTO t1 VALUES(1,1,'aaa'),(2,2,'a'),(3,3,'b'),(4,4,'c');
CREATE PROCEDURE p1()
BEGIN
FOR rec IN (SELECT en1 FROM t1)
DO
SELECT rec.en1;
END FOR;
END;
$$
CALL p1();
rec.en1
aaa
rec.en1
a
rec.en1
b
rec.en1
c
DROP PROCEDURE p1;
DROP TABLE t1;
...@@ -723,3 +723,24 @@ $$ ...@@ -723,3 +723,24 @@ $$
DELIMITER ;$$ DELIMITER ;$$
CALL p1; CALL p1;
DROP PROCEDURE p1; DROP PROCEDURE p1;
--echo #
--echo # MDEV-17278 CURSOR FOR LOOP - ERROR: unexpected end of stream, read 0 bytes (SERVER CRASH)
--echo #
CREATE TABLE t1 (id2 int, id int, en1 enum('aaa','a','b','c'));
INSERT INTO t1 VALUES(1,1,'aaa'),(2,2,'a'),(3,3,'b'),(4,4,'c');
DELIMITER $$;
CREATE PROCEDURE p1()
BEGIN
FOR rec IN (SELECT en1 FROM t1)
DO
SELECT rec.en1;
END FOR;
END;
$$
DELIMITER ;$$
CALL p1();
DROP PROCEDURE p1;
DROP TABLE t1;
...@@ -1479,3 +1479,28 @@ f1() ...@@ -1479,3 +1479,28 @@ f1()
1 1
DROP FUNCTION f1; DROP FUNCTION f1;
DROP TABLE t1; DROP TABLE t1;
#
# MDEV-17278 CURSOR FOR LOOP - ERROR: unexpected end of stream, read 0 bytes (SERVER CRASH)
#
CREATE TABLE t1 (id2 int, id int, en1 enum('aaa','a','b','c'));
INSERT INTO t1 VALUES(1,1,'aaa'),(2,2,'a'),(3,3,'b'),(4,4,'c');
CREATE PROCEDURE p1()
AS
BEGIN
FOR rec IN (SELECT en1 FROM t1)
LOOP
SELECT rec.en1;
END LOOP;
END;
$$
CALL p1();
rec.en1
aaa
rec.en1
a
rec.en1
b
rec.en1
c
DROP PROCEDURE p1;
DROP TABLE t1;
...@@ -1572,3 +1572,26 @@ DELIMITER ;$$ ...@@ -1572,3 +1572,26 @@ DELIMITER ;$$
SELECT f1(); SELECT f1();
DROP FUNCTION f1; DROP FUNCTION f1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-17278 CURSOR FOR LOOP - ERROR: unexpected end of stream, read 0 bytes (SERVER CRASH)
--echo #
CREATE TABLE t1 (id2 int, id int, en1 enum('aaa','a','b','c'));
INSERT INTO t1 VALUES(1,1,'aaa'),(2,2,'a'),(3,3,'b'),(4,4,'c');
DELIMITER $$;
CREATE PROCEDURE p1()
AS
BEGIN
FOR rec IN (SELECT en1 FROM t1)
LOOP
SELECT rec.en1;
END LOOP;
END;
$$
DELIMITER ;$$
CALL p1();
DROP PROCEDURE p1;
DROP TABLE t1;
...@@ -4475,19 +4475,21 @@ sp_instr_cursor_copy_struct::exec_core(THD *thd, uint *nextp) ...@@ -4475,19 +4475,21 @@ sp_instr_cursor_copy_struct::exec_core(THD *thd, uint *nextp)
if (!(ret= tmp.open(thd))) if (!(ret= tmp.open(thd)))
{ {
Row_definition_list defs; Row_definition_list defs;
/*
Create row elements on the caller arena.
It's the same arena that was used during sp_rcontext::create().
This puts cursor%ROWTYPE elements on the same mem_root
where explicit ROW elements and table%ROWTYPE reside:
- tmp.export_structure() allocates new Spvar_definition instances
and their components (such as TYPELIBs).
- row->row_create_items() creates new Item_field instances.
They all are created on the same mem_root.
*/
Query_arena current_arena;
thd->set_n_backup_active_arena(thd->spcont->callers_arena, &current_arena);
if (!(ret= tmp.export_structure(thd, &defs))) if (!(ret= tmp.export_structure(thd, &defs)))
{
/*
Create row elements on the caller arena.
It's the same arena that was used during sp_rcontext::create().
This puts cursor%ROWTYPE elements on the same mem_root
where explicit ROW elements and table%ROWTYPE reside.
*/
Query_arena current_arena;
thd->set_n_backup_active_arena(thd->spcont->callers_arena, &current_arena);
row->row_create_items(thd, &defs); row->row_create_items(thd, &defs);
thd->restore_active_arena(thd->spcont->callers_arena, &current_arena); thd->restore_active_arena(thd->spcont->callers_arena, &current_arena);
}
tmp.close(thd); tmp.close(thd);
} }
} }
......
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