Bug#50755: Crash if stored routine def contains version comments
The problem was that a syntactically invalid trigger could cause the server to crash when trying to list triggers. The crash would happen due to a mishap in the backup/restore procedure that should protect parser items which are not associated with the trigger. The backup/restore is used to isolate the parse tree (and context) of a statement from the load (and parsing) of a trigger. In this case, a error during the parsing of a trigger could cause the improper backup/restore sequence. The solution is to properly restore the original statement context before the parser is exited due to syntax errors in the trigger body. mysql-test/r/trigger.result: Add test case result for Bug#50755 mysql-test/t/trigger.test: Add test case for Bug#50755 sql/sp_head.cc: Merge sp_head::destroy() and sp_head destructor. Retrieve THD from the LEX so that m_thd is not necessary. sql/sql_lex.cc: Explicitly restore the original environment.
This commit is contained in:
parent
2303a8c6e4
commit
7ecad98c45
@ -2128,4 +2128,27 @@ Warning 1048 Column 'id' cannot be null
|
|||||||
Warning 1048 Column 'id' cannot be null
|
Warning 1048 Column 'id' cannot be null
|
||||||
DROP TRIGGER t1_bu;
|
DROP TRIGGER t1_bu;
|
||||||
DROP TABLE t1,t2;
|
DROP TABLE t1,t2;
|
||||||
|
#
|
||||||
|
# Bug#50755: Crash if stored routine def contains version comments
|
||||||
|
#
|
||||||
|
DROP DATABASE IF EXISTS db1;
|
||||||
|
DROP TRIGGER IF EXISTS trg1;
|
||||||
|
DROP TABLE IF EXISTS t1, t2;
|
||||||
|
CREATE DATABASE db1;
|
||||||
|
USE db1;
|
||||||
|
CREATE TABLE t1 (b INT);
|
||||||
|
CREATE TABLE t2 (a INT);
|
||||||
|
CREATE TRIGGER trg1 BEFORE INSERT ON t2 FOR EACH ROW INSERT/*!INTO*/t1 VALUES (1);
|
||||||
|
# Used to crash
|
||||||
|
SHOW TRIGGERS IN db1;
|
||||||
|
Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation
|
||||||
|
Warnings:
|
||||||
|
Warning 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VALUES (1)' at line 1
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VALUES (1)' at line 1
|
||||||
|
SELECT * FROM t1;
|
||||||
|
b
|
||||||
|
# Work around Bug#45235
|
||||||
|
DROP DATABASE db1;
|
||||||
|
USE test;
|
||||||
End of 5.1 tests.
|
End of 5.1 tests.
|
||||||
|
@ -2439,4 +2439,35 @@ UPDATE t1 SET id=NULL;
|
|||||||
DROP TRIGGER t1_bu;
|
DROP TRIGGER t1_bu;
|
||||||
DROP TABLE t1,t2;
|
DROP TABLE t1,t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug#50755: Crash if stored routine def contains version comments
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
DROP DATABASE IF EXISTS db1;
|
||||||
|
DROP TRIGGER IF EXISTS trg1;
|
||||||
|
DROP TABLE IF EXISTS t1, t2;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
CREATE DATABASE db1;
|
||||||
|
USE db1;
|
||||||
|
|
||||||
|
CREATE TABLE t1 (b INT);
|
||||||
|
CREATE TABLE t2 (a INT);
|
||||||
|
|
||||||
|
CREATE TRIGGER trg1 BEFORE INSERT ON t2 FOR EACH ROW INSERT/*!INTO*/t1 VALUES (1);
|
||||||
|
--echo # Used to crash
|
||||||
|
SHOW TRIGGERS IN db1;
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
SELECT * FROM t1;
|
||||||
|
|
||||||
|
--echo # Work around Bug#45235
|
||||||
|
let $MYSQLD_DATADIR = `select @@datadir`;
|
||||||
|
--remove_file $MYSQLD_DATADIR/db1/t2.TRG
|
||||||
|
--remove_file $MYSQLD_DATADIR/db1/trg1.TRN
|
||||||
|
|
||||||
|
DROP DATABASE db1;
|
||||||
|
USE test;
|
||||||
|
|
||||||
--echo End of 5.1 tests.
|
--echo End of 5.1 tests.
|
||||||
|
@ -745,21 +745,12 @@ sp_head::create(THD *thd)
|
|||||||
|
|
||||||
sp_head::~sp_head()
|
sp_head::~sp_head()
|
||||||
{
|
{
|
||||||
DBUG_ENTER("sp_head::~sp_head");
|
|
||||||
destroy();
|
|
||||||
delete m_next_cached_sp;
|
|
||||||
if (m_thd)
|
|
||||||
restore_thd_mem_root(m_thd);
|
|
||||||
DBUG_VOID_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sp_head::destroy()
|
|
||||||
{
|
|
||||||
sp_instr *i;
|
|
||||||
LEX *lex;
|
LEX *lex;
|
||||||
DBUG_ENTER("sp_head::destroy");
|
sp_instr *i;
|
||||||
DBUG_PRINT("info", ("name: %s", m_name.str));
|
DBUG_ENTER("sp_head::~sp_head");
|
||||||
|
|
||||||
|
/* sp_head::restore_thd_mem_root() must already have been called. */
|
||||||
|
DBUG_ASSERT(m_thd == NULL);
|
||||||
|
|
||||||
for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
|
for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
|
||||||
delete i;
|
delete i;
|
||||||
@ -770,21 +761,22 @@ sp_head::destroy()
|
|||||||
/*
|
/*
|
||||||
If we have non-empty LEX stack then we just came out of parser with
|
If we have non-empty LEX stack then we just came out of parser with
|
||||||
error. Now we should delete all auxilary LEXes and restore original
|
error. Now we should delete all auxilary LEXes and restore original
|
||||||
THD::lex (In this case sp_head::restore_thd_mem_root() was not called
|
THD::lex. It is safe to not update LEX::ptr because further query
|
||||||
too, so m_thd points to the current thread context).
|
string parsing and execution will be stopped anyway.
|
||||||
It is safe to not update LEX::ptr because further query string parsing
|
|
||||||
and execution will be stopped anyway.
|
|
||||||
*/
|
*/
|
||||||
DBUG_ASSERT(m_lex.is_empty() || m_thd);
|
|
||||||
while ((lex= (LEX *)m_lex.pop()))
|
while ((lex= (LEX *)m_lex.pop()))
|
||||||
{
|
{
|
||||||
lex_end(m_thd->lex);
|
THD *thd= lex->thd;
|
||||||
delete m_thd->lex;
|
lex_end(thd->lex);
|
||||||
m_thd->lex= lex;
|
delete thd->lex;
|
||||||
|
thd->lex= lex;
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_free(&m_sptabs);
|
hash_free(&m_sptabs);
|
||||||
hash_free(&m_sroutines);
|
hash_free(&m_sroutines);
|
||||||
|
|
||||||
|
delete m_next_cached_sp;
|
||||||
|
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,10 +289,6 @@ public:
|
|||||||
|
|
||||||
virtual ~sp_head();
|
virtual ~sp_head();
|
||||||
|
|
||||||
/// Free memory
|
|
||||||
void
|
|
||||||
destroy();
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
execute_trigger(THD *thd,
|
execute_trigger(THD *thd,
|
||||||
const LEX_STRING *db_name,
|
const LEX_STRING *db_name,
|
||||||
|
@ -2106,6 +2106,7 @@ void st_lex::cleanup_lex_after_parse_error(THD *thd)
|
|||||||
*/
|
*/
|
||||||
if (thd->lex->sphead)
|
if (thd->lex->sphead)
|
||||||
{
|
{
|
||||||
|
thd->lex->sphead->restore_thd_mem_root(thd);
|
||||||
delete thd->lex->sphead;
|
delete thd->lex->sphead;
|
||||||
thd->lex->sphead= NULL;
|
thd->lex->sphead= NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user