Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions mysql-test/main/sp_validation.result
Original file line number Diff line number Diff line change
Expand Up @@ -2142,3 +2142,24 @@ ERROR HY000: The target table v1 of the DELETE is not updatable
# Clean up
DROP VIEW v1;
DROP TABLE t1;
#
# MDEV-37335: crash on re-parsing an sp_instr_set that does not own its LEX
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
CREATE PROCEDURE p()
BEGIN
DECLARE b,c INT DEFAULT (SELECT a FROM t1);
SELECT b, c;
END
$
CALL p();
b c
1 1
ALTER TABLE t1 MODIFY a BIGINT;
CALL p();
b c
1 1
# Clean up
DROP PROCEDURE p;
DROP TABLE t1;
28 changes: 28 additions & 0 deletions mysql-test/main/sp_validation.test
Original file line number Diff line number Diff line change
Expand Up @@ -2952,4 +2952,32 @@ UPDATE t1 SET a = 4;
DROP VIEW v1;
DROP TABLE t1;

--echo #
--echo # MDEV-37335: crash on re-parsing an sp_instr_set that does not own its LEX
--echo #
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);

--delimiter $
CREATE PROCEDURE p()
BEGIN
DECLARE b,c INT DEFAULT (SELECT a FROM t1);
SELECT b, c;
END
$
--delimiter ;

CALL p();

ALTER TABLE t1 MODIFY a BIGINT;

# The instruction assigning the variable b doesn't own the LEX shared with
# the instruction assigning the variable c, so re-parsing it after a metadata
# change used to run the code path intended for cursor instructions.
CALL p();

--echo # Clean up
DROP PROCEDURE p;
DROP TABLE t1;

--enable_ps2_protocol
9 changes: 6 additions & 3 deletions sql/sp_instr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -487,9 +487,10 @@ int sp_lex_keeper::validate_lex_and_exec_core(THD *thd, uint *nextp,
if (!lex) return true;

/*
m_lex != nullptr in case it points to sp_lex_cursor.
m_lex != nullptr in case it points to sp_lex_cursor, and also when
this instruction shares a LEX owned by a sibling instruction.
*/
if (m_lex == nullptr)
if (m_lex == nullptr || !m_lex->get_lex_for_cursor())
set_lex(lex);

m_first_execution= true;
Expand Down Expand Up @@ -896,8 +897,10 @@ LEX* sp_lex_instr::parse_expr(THD *thd, sp_head *sp, LEX *sp_instr_lex)
/*
sp_instr_lex != nullptr for cursor relating SP instructions (sp_instr_cpush,
sp_instr_cursor_copy_struct) and in some cases for sp_instr_set.
Only the cursor ones carry a sp_lex_cursor, which is what the else branch
below expects.
*/
if (sp_instr_lex == nullptr)
if (sp_instr_lex == nullptr || !sp_instr_lex->get_lex_for_cursor())
{
lex_local= new (thd->mem_root) st_lex_local;
thd->lex= lex_local;
Expand Down
Loading